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