1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 */
27
28 #include "lint.h"
29 #include <mtlib.h>
30 #include <sys/types.h>
31 #include <shadow.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <nss_dbdefs.h>
35 #include <stdio.h>
36 #include <synch.h>
37
38 int str2spwd(const char *, int, void *,
39 char *, int);
40
41 static DEFINE_NSS_DB_ROOT(db_root);
42 static DEFINE_NSS_GETENT(context);
43
44 void
_nss_initf_shadow(nss_db_params_t * p)45 _nss_initf_shadow(nss_db_params_t *p)
46 {
47 p->name = NSS_DBNAM_SHADOW;
48 p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */
49 p->default_config = NSS_DEFCONF_PASSWD;
50 }
51
52 struct spwd *
getspnam_r(const char * name,struct spwd * result,char * buffer,int buflen)53 getspnam_r(const char *name, struct spwd *result, char *buffer, int buflen)
54 {
55 nss_XbyY_args_t arg;
56
57 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
58 arg.key.name = name;
59 (void) nss_search(&db_root, _nss_initf_shadow,
60 NSS_DBOP_SHADOW_BYNAME, &arg);
61 return ((struct spwd *)NSS_XbyY_FINI(&arg));
62 }
63
64 void
setspent(void)65 setspent(void)
66 {
67 nss_setent(&db_root, _nss_initf_shadow, &context);
68 }
69
70 void
endspent(void)71 endspent(void)
72 {
73 nss_endent(&db_root, _nss_initf_shadow, &context);
74 nss_delete(&db_root);
75 }
76
77 struct spwd *
getspent_r(struct spwd * result,char * buffer,int buflen)78 getspent_r(struct spwd *result, char *buffer, int buflen)
79 {
80 nss_XbyY_args_t arg;
81 char *nam;
82
83 /* In getXXent_r(), protect the unsuspecting caller from +/- entries */
84
85 do {
86 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
87 /* No key to fill in */
88 (void) nss_getent(&db_root, _nss_initf_shadow, &context, &arg);
89 } while (arg.returnval != 0 &&
90 (nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
91 (*nam == '+' || *nam == '-'));
92
93 return (struct spwd *)NSS_XbyY_FINI(&arg);
94 }
95
96 struct spwd *
fgetspent_r(FILE * f,struct spwd * result,char * buffer,int buflen)97 fgetspent_r(FILE *f, struct spwd *result, char *buffer, int buflen)
98 {
99 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
100 nss_XbyY_args_t arg;
101
102 /* ... but in fgetXXent_r, the caller deserves any +/- entry it gets */
103
104 /* No key to fill in */
105 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
106 _nss_XbyY_fgets(f, &arg);
107 return (struct spwd *)NSS_XbyY_FINI(&arg);
108 }
109
110 typedef const char *constp;
111
112 static int /* 1 means success and more input, 0 means error or no more */
getfield(constp * nextp,constp limit,int uns,void * valp)113 getfield(constp *nextp, constp limit, int uns, void *valp)
114 {
115 constp p = *nextp;
116 char *endfield;
117 char numbuf[12]; /* Holds -2^31 and trailing ':' */
118 size_t len;
119
120 if (p == 0 || p >= limit) {
121 return (0);
122 }
123 if (*p == ':') {
124 p++;
125 *nextp = p;
126 return (p < limit);
127 }
128 if ((len = limit - p) > sizeof (numbuf) - 1) {
129 len = sizeof (numbuf) - 1;
130 }
131 /*
132 * We want to use strtol() and we have a readonly non-zero-terminated
133 * string, so first we copy and terminate the interesting bit.
134 * Ugh. (It's convenient to terminate with a colon rather than \0).
135 */
136 if ((endfield = memccpy(numbuf, p, ':', len)) == 0) {
137 if (len != limit - p) {
138 /* Error -- field is too big to be a legit number */
139 return (0);
140 }
141 numbuf[len] = ':';
142 p = limit;
143 } else {
144 p += (endfield - numbuf);
145 }
146 if (uns) {
147 unsigned long ux = strtoul(numbuf, &endfield, 10);
148 if (*endfield != ':') {
149 /* Error -- expected <integer><colon> */
150 return (0);
151 }
152 *((unsigned int *)valp) = (unsigned int)ux;
153 } else {
154 long x = strtol(numbuf, &endfield, 10);
155 if (*endfield != ':') {
156 /* Error -- expected <integer><colon> */
157 return (0);
158 }
159 *((int *)valp) = (int)x;
160 }
161 *nextp = p;
162 return (p < limit);
163 }
164
165 /*
166 * str2spwd() -- convert a string to a shadow passwd entry. The parser is
167 * more liberal than the passwd or group parsers; since it's legitimate
168 * for almost all the fields here to be blank, the parser lets one omit
169 * any number of blank fields at the end of the entry. The acceptable
170 * forms for '+' and '-' entries are the same as those for normal entries.
171 * === Is this likely to do more harm than good?
172 *
173 * Return values: 0 = success, 1 = parse error, 2 = erange ...
174 * The structure pointer passed in is a structure in the caller's space
175 * wherein the field pointers would be set to areas in the buffer if
176 * need be. instring and buffer should be separate areas.
177 */
178 int
str2spwd(const char * instr,int lenstr,void * ent,char * buffer,int buflen)179 str2spwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
180 {
181 struct spwd *shadow = (struct spwd *)ent;
182 const char *p = instr, *limit;
183 char *bufp;
184 int black_magic;
185 size_t lencopy;
186
187 limit = p + lenstr;
188 if ((p = memchr(instr, ':', lenstr)) == 0 ||
189 ++p >= limit ||
190 (p = memchr(p, ':', limit - p)) == 0) {
191 lencopy = (size_t)lenstr;
192 p = 0;
193 } else {
194 lencopy = p - instr;
195 p++;
196 }
197 if (lencopy + 1 > buflen) {
198 return (NSS_STR_PARSE_ERANGE);
199 }
200
201 if (instr != buffer) {
202 /* Overlapping buffer copies are OK */
203 (void) memmove(buffer, instr, lencopy);
204 buffer[lencopy] = 0;
205 }
206
207 /* quick exit do not entry fill if not needed */
208 if (ent == (void *)NULL)
209 return (NSS_STR_PARSE_SUCCESS);
210
211 black_magic = (*instr == '+' || *instr == '-');
212 shadow->sp_namp = bufp = buffer;
213 shadow->sp_pwdp = 0;
214 shadow->sp_lstchg = -1;
215 shadow->sp_min = -1;
216 shadow->sp_max = -1;
217 shadow->sp_warn = -1;
218 shadow->sp_inact = -1;
219 shadow->sp_expire = -1;
220 shadow->sp_flag = 0;
221
222 if ((bufp = strchr(bufp, ':')) == 0) {
223 if (black_magic)
224 return (NSS_STR_PARSE_SUCCESS);
225 else
226 return (NSS_STR_PARSE_PARSE);
227 }
228 *bufp++ = '\0';
229
230 shadow->sp_pwdp = bufp;
231 if (instr == 0) {
232 if ((bufp = strchr(bufp, ':')) == 0) {
233 if (black_magic)
234 return (NSS_STR_PARSE_SUCCESS);
235 else
236 return (NSS_STR_PARSE_PARSE);
237 }
238 *bufp++ = '\0';
239 p = bufp;
240 } /* else p was set when we copied name and passwd into the buffer */
241
242 if (!getfield(&p, limit, 0, &shadow->sp_lstchg))
243 return (NSS_STR_PARSE_SUCCESS);
244 if (!getfield(&p, limit, 0, &shadow->sp_min))
245 return (NSS_STR_PARSE_SUCCESS);
246 if (!getfield(&p, limit, 0, &shadow->sp_max))
247 return (NSS_STR_PARSE_SUCCESS);
248 if (!getfield(&p, limit, 0, &shadow->sp_warn))
249 return (NSS_STR_PARSE_SUCCESS);
250 if (!getfield(&p, limit, 0, &shadow->sp_inact))
251 return (NSS_STR_PARSE_SUCCESS);
252 if (!getfield(&p, limit, 0, &shadow->sp_expire))
253 return (NSS_STR_PARSE_SUCCESS);
254 if (!getfield(&p, limit, 1, &shadow->sp_flag))
255 return (NSS_STR_PARSE_SUCCESS);
256 if (p != limit) {
257 /* Syntax error -- garbage at end of line */
258 return (NSS_STR_PARSE_PARSE);
259 }
260 return (NSS_STR_PARSE_SUCCESS);
261 }
262