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