xref: /illumos-gate/usr/src/lib/libc/port/gen/nss_dbdefs.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "lint.h"
28 #include <mtlib.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <nss_dbdefs.h>
34 #include <limits.h>
35 #include <dlfcn.h>
36 #include <link.h>
37 #include <thread.h>
38 #include <atomic.h>
39 /* headers for key2str/str2key routines */
40 #include <sys/ethernet.h>
41 #include <exec_attr.h>
42 #include <grp.h>
43 
44 /*
45  * functions in nss_dbdefs.c deal more with the mechanics of
46  * the data structures like nss_XbyY_args_t and the interaction
47  * with the packed buffers etc.  versus the mechanics of the
48  * actual policy component operations such as nss_search sequencing.
49  */
50 
51 /*
52  * ALIGN? is there an official definition of this?
53  * We use sizeof(long) to cover what we want
54  * for both the 32-bit world and 64-bit world.
55  */
56 
57 #define	ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1))
58 
59 nss_XbyY_buf_t *
60 _nss_XbyY_buf_alloc(int struct_size, int buffer_size)
61 {
62 	nss_XbyY_buf_t	*b;
63 
64 	/* Use one malloc for dbargs, result struct and buffer */
65 	b = (nss_XbyY_buf_t *)
66 	    malloc(ALIGN(sizeof (*b)) + struct_size + buffer_size);
67 	if (b == 0) {
68 		return (0);
69 	}
70 	b->result = (void *)ALIGN(&b[1]);
71 	b->buffer = (char *)(b->result) + struct_size;
72 	b->buflen = buffer_size;
73 	return (b);
74 }
75 
76 void
77 _nss_XbyY_buf_free(nss_XbyY_buf_t *b)
78 {
79 	if (b != 0) {
80 		free(b);
81 	}
82 }
83 
84 /* === Comment:  used by fget{gr,pw,sp}ent */
85 /* ==== Should do ye olde syslog()ing of suspiciously long lines */
86 
87 void
88 _nss_XbyY_fgets(FILE *f, nss_XbyY_args_t *b)
89 {
90 	char		buf[LINE_MAX];
91 	int		len, parsestat;
92 
93 	if (fgets(buf, LINE_MAX, f) == 0) {
94 		/* End of file */
95 		b->returnval = 0;
96 		b->erange    = 0;
97 		return;
98 	}
99 	len = (int)strlen(buf);
100 	/* len >= 0 (otherwise we would have got EOF) */
101 	if (buf[len - 1] != '\n') {
102 		if ((len + 1) == LINE_MAX) {
103 			/* Line too long for buffer; too bad */
104 			while (fgets(buf, LINE_MAX, f) != 0 &&
105 			    buf[strlen(buf) - 1] != '\n') {
106 				;
107 			}
108 			b->returnval = 0;
109 			b->erange    = 1;
110 			return;
111 		}
112 		/* case where the file is not terminated with a Newline */
113 		len++;
114 	}
115 	parsestat = (*b->str2ent)(buf, (len - 1), b->buf.result, b->buf.buffer,
116 	    b->buf.buflen);
117 	if (parsestat == NSS_STR_PARSE_ERANGE) {
118 		b->returnval = 0;
119 		b->erange    = 1;
120 	} else if (parsestat == NSS_STR_PARSE_SUCCESS) {
121 		b->returnval = b->buf.result;
122 	}
123 }
124 
125 /*
126  * parse the aliases string into the buffer and if successful return
127  * a char ** pointer to the beginning of the aliases.
128  *
129  * CAUTION: (instr, instr+lenstr) and (buffer, buffer+buflen) are
130  * non-intersecting memory areas. Since this is an internal interface,
131  * we should be able to live with that.
132  */
133 char **
134 _nss_netdb_aliases(const char *instr, int lenstr, char *buffer, int buflen)
135 	/* "instr" is the beginning of the aliases string */
136 	/* "buffer" has the return val for success */
137 	/* "buflen" is the length of the buffer available for aliases */
138 {
139 	/*
140 	 * Build the alias-list in the start of the buffer, and copy
141 	 * the strings to the end of the buffer.
142 	 */
143 	const char
144 		*instr_limit	= instr + lenstr;
145 	char	*copyptr	= buffer + buflen;
146 	char	**aliasp	= (char **)ROUND_UP(buffer, sizeof (*aliasp));
147 	char	**alias_start	= aliasp;
148 	int	nstrings	= 0;
149 
150 	for (;;) {
151 		const char	*str_start;
152 		size_t		str_len;
153 
154 		while (instr < instr_limit && isspace(*instr)) {
155 			instr++;
156 		}
157 		if (instr >= instr_limit || *instr == '#') {
158 			break;
159 		}
160 		str_start = instr;
161 		while (instr < instr_limit && !isspace(*instr)) {
162 			instr++;
163 		}
164 
165 		++nstrings;
166 
167 		str_len = instr - str_start;
168 		copyptr -= str_len + 1;
169 		if (copyptr <= (char *)(&aliasp[nstrings + 1])) {
170 			/* Has to be room for the pointer to */
171 			/* the alias we're about to add,   */
172 			/* as well as the final NULL ptr.  */
173 			return (0);
174 		}
175 		*aliasp++ = copyptr;
176 		(void) memcpy(copyptr, str_start, str_len);
177 		copyptr[str_len] = '\0';
178 	}
179 	*aliasp++ = 0;
180 	return (alias_start);
181 }
182 
183 
184 extern nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
185 
186 /*
187  * pack well known getXbyY keys to packed buffer prior to the door_call
188  * to nscd.  Some consideration is given to ordering the tests based on
189  * usage.  Note: buf is nssuint_t aligned.
190  */
191 
192 typedef struct {
193 	const char	*name;		/* NSS_DBNAM_* */
194 	const char	*defconf;	/* NSS_DEFCONF_* */
195 	const char	*initfn;	/* init function name */
196 	const char	*strfn;		/* str2X function name */
197 	const char	*cstrfn;	/* cstr2X function name */
198 	void		*initfnp;	/* init function pointer */
199 	void		*strfnp;	/* str2X function pointer */
200 	uint32_t	dbop;		/* NSS_DBOP_* */
201 	const char	*tostr;		/* key2str cvt str */
202 } getXbyY_to_dbop_t;
203 
204 #define	NSS_MK_GETXYDBOP(x, y, f, e)	\
205 	{ NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \
206 		NULL, NULL, NULL, NSS_DBOP_##x##_##y, (e) }
207 
208 #define	NSS_MK_GETXYDBOPA(x, a, f, e)	\
209 	{ NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \
210 		NULL, NULL, NULL, NSS_DBOP_##a, (e) }
211 
212 #define	NSS_MK_GETXYDBOPB(x, b, a, f, s, e)	\
213 	{ NSS_DBNAM_##x, NSS_DEFCONF_##b, "_nss_initf_" f, s,  \
214 		NULL, NULL, NULL, NSS_DBOP_##a, (e) }
215 
216 #define	NSS_MK_GETXYDBOPC(x, a, f, s, e)	\
217 	{ NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \
218 		NULL, NULL, NULL, NSS_DBOP_##x##_##a, (e) }
219 
220 #define	NSS_MK_GETXYDBOPD(x, y, i, f, e)	\
221 	{ NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" i, "str2" f, \
222 		NULL, NULL, NULL, NSS_DBOP_##x##_##y, (e) }
223 
224 #define	NSS_MK_GETXYDBOPCSTR(x, a, f, s, e)	\
225 	{ NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \
226 		"process_cstr", NULL, NULL, NSS_DBOP_##x##_##a, (e) }
227 
228 /*
229  * The getXbyY_to_dbop structure is hashed on first call in order to
230  * reduce the search time for the well known getXbyY operations.
231  * A binary search was not fast enough.  There were on average
232  * 3-4 tests (strcmps) per getXbyY call.
233  *
234  * DBOP_PRIME_HASH must be a prime number (reasonably small) but that
235  * is sufficient to uniquely map the entries in the following table
236  * without collision.
237  *
238  * The DBOP_PRIME_HASH was selected as the smallest hash value
239  * for this table without collisions. Changing this table WILL
240  * necessitate re-testing for possible collisions.
241  */
242 
243 #define	DBOP_PRIME_HASH		227
244 #define	DBOP_HASH_TAG		0xf0000000
245 static int getXbyYdbopHASH[DBOP_PRIME_HASH] = { 0 };
246 static mutex_t getXbydbop_hash_lock = DEFAULTMUTEX;
247 static int getXbyYdbop_hashed = 0;
248 
249 /*
250  * If the size of getXbyY_to_dbop[] is changed then hash function must be
251  * corrected to be without collisions in nss_dbop_search().
252  */
253 static getXbyY_to_dbop_t getXbyY_to_dbop[] = {
254 	/* NSS_MK_GETXYDBOP(ALIASES, ?, ?), */
255 	NSS_MK_GETXYDBOPD(AUDITUSER, BYNAME, "auuser", "audituser", "n"),
256 	NSS_MK_GETXYDBOP(AUTHATTR, BYNAME, "authattr", "n"),
257 	/* NSS_MK_GETXYDBOP(AUTOMOUNT, ?, ?), */
258 	NSS_MK_GETXYDBOP(BOOTPARAMS, BYNAME, "bootparams", "n"),
259 	NSS_MK_GETXYDBOPC(ETHERS, HOSTTON, "ethers", "str2ether", "n"),
260 	NSS_MK_GETXYDBOPC(ETHERS, NTOHOST, "ethers", "str2ether", "e"),
261 	NSS_MK_GETXYDBOP(EXECATTR, BYNAME, "execattr", "A"),
262 	NSS_MK_GETXYDBOP(EXECATTR, BYID, "execattr", "A"),
263 	NSS_MK_GETXYDBOP(EXECATTR, BYNAMEID, "execattr", "A"),
264 	NSS_MK_GETXYDBOP(GROUP, BYNAME, "group", "n"),
265 	NSS_MK_GETXYDBOP(GROUP, BYGID, "group", "g"),
266 	NSS_MK_GETXYDBOPCSTR(GROUP, BYMEMBER, "group", "str2group", "I"),
267 	NSS_MK_GETXYDBOPC(HOSTS, BYNAME, "hosts", "str2hostent", "n"),
268 	NSS_MK_GETXYDBOPC(HOSTS, BYADDR, "hosts", "str2hostent", "h"),
269 	NSS_MK_GETXYDBOPC(IPNODES, BYNAME, "ipnodes", "str2hostent", "i"),
270 	NSS_MK_GETXYDBOPC(IPNODES, BYADDR, "ipnodes", "str2hostent", "h"),
271 	NSS_MK_GETXYDBOP(NETGROUP, IN, "netgroup", "t"),
272 	NSS_MK_GETXYDBOP(NETGROUP, SET, "netgroup", "T"),
273 	NSS_MK_GETXYDBOPC(NETMASKS, BYNET, "netmasks", "str2addr", "n"),
274 	NSS_MK_GETXYDBOPC(NETWORKS, BYNAME, "net", "str2netent", "n"),
275 	NSS_MK_GETXYDBOPC(NETWORKS, BYADDR, "net", "str2netent", "a"),
276 	NSS_MK_GETXYDBOP(PASSWD, BYNAME, "passwd", "n"),
277 	NSS_MK_GETXYDBOP(PASSWD, BYUID, "passwd", "u"),
278 	NSS_MK_GETXYDBOP(PRINTERS, BYNAME, "printers", "n"),
279 	NSS_MK_GETXYDBOP(PROFATTR, BYNAME, "profattr", "n"),
280 	NSS_MK_GETXYDBOP(PROJECT, BYNAME, "project", "n"),
281 	NSS_MK_GETXYDBOP(PROJECT, BYID, "project", "p"),
282 	NSS_MK_GETXYDBOPC(PROTOCOLS, BYNAME, "proto", "str2protoent", "n"),
283 	NSS_MK_GETXYDBOPC(PROTOCOLS, BYNUMBER, "proto", "str2protoent", "N"),
284 	NSS_MK_GETXYDBOPA(PUBLICKEY, KEYS_BYNAME, "publickey", "k"),
285 	NSS_MK_GETXYDBOPC(RPC, BYNAME, "rpc", "str2rpcent", "n"),
286 	NSS_MK_GETXYDBOPC(RPC, BYNUMBER, "rpc", "str2rpcent", "N"),
287 	NSS_MK_GETXYDBOPC(SERVICES, BYNAME, "services", "str2servent", "s"),
288 	NSS_MK_GETXYDBOPC(SERVICES, BYPORT, "services", "str2servent", "S"),
289 	NSS_MK_GETXYDBOPB(SHADOW, PASSWD, PASSWD_BYNAME, "shadow",
290 				"str2spwd", "n"),
291 	NSS_MK_GETXYDBOPC(TSOL_RH, BYADDR, "tsol_rh", "str_to_rhstr", "h"),
292 	NSS_MK_GETXYDBOPC(TSOL_TP, BYNAME, "tsol_tp", "str_to_tpstr", "n"),
293 	NSS_MK_GETXYDBOPC(TSOL_ZC, BYNAME, "tsol_zc", "str_to_zcstr", "n"),
294 	NSS_MK_GETXYDBOP(USERATTR, BYNAME, "userattr", "n"),
295 };
296 
297 static int
298 nss_dbop_search(const char *name, uint32_t dbop)
299 {
300 	getXbyY_to_dbop_t *hptr;
301 	int count = (sizeof (getXbyY_to_dbop) / sizeof (getXbyY_to_dbop_t));
302 	uint32_t hval, g;
303 	const char *cp;
304 	int i, idx;
305 	static const uint32_t hbits_tst = 0xf0000000;
306 
307 	/* Uses a table size is known to have no collisions */
308 	if (getXbyYdbop_hashed == 0) {
309 		lmutex_lock(&getXbydbop_hash_lock);
310 		if (getXbyYdbop_hashed == 0) {
311 			for (i = 0; i < count; i++) {
312 				cp = getXbyY_to_dbop[i].name;
313 				hval = 0;
314 				while (*cp) {
315 					hval = (hval << 4) + *cp++;
316 					if ((g = (hval & hbits_tst)) != 0)
317 						hval ^= g >> 24;
318 					hval &= ~g;
319 				}
320 				hval += getXbyY_to_dbop[i].dbop;
321 				hval %= DBOP_PRIME_HASH;
322 				if (getXbyYdbopHASH[hval] != 0) {
323 					/* hash table collision-see above */
324 					lmutex_unlock(&getXbydbop_hash_lock);
325 					return (-1);
326 				}
327 				getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG;
328 			}
329 			membar_producer();
330 			getXbyYdbop_hashed = 1;
331 		}
332 		lmutex_unlock(&getXbydbop_hash_lock);
333 	}
334 	membar_consumer();
335 	cp = name;
336 	hval = 0;
337 	while (*cp) {
338 		hval = (hval << 4) + *cp++;
339 		if ((g = (hval & hbits_tst)) != 0)
340 			hval ^= g >> 24;
341 		hval &= ~g;
342 	}
343 	hval += dbop;
344 	hval %= DBOP_PRIME_HASH;
345 	idx = getXbyYdbopHASH[hval];
346 	if ((idx & DBOP_HASH_TAG) != DBOP_HASH_TAG)
347 		return (-1);
348 	idx &= ~DBOP_HASH_TAG;
349 	if (idx >= count)
350 		return (-1);
351 	hptr = &getXbyY_to_dbop[idx];
352 	if (hptr->dbop != dbop || strcmp(name, hptr->name) != 0)
353 		return (-1);
354 	return (idx);
355 }
356 
357 /*
358  * nss_pack_key2str
359  * Private key to string packing function for getXbyY routines
360  * This routine performs a printf like parse over the argument
361  * key, given a string of items to pack and assembles the key in
362  * the packed structure.  This routine is called (currently) by
363  * nss_default_key2str, but will be used by other external
364  * APIs in the future.
365  *
366  * buffer - Start of the key buffer location [in packed buffer]
367  * length - Length of key buffer component
368  * Key offsets are relative to start of key buffer location.
369  *
370  * Pack fields			Key
371  *   key.name			n
372  *   key.number			N
373  *   key.uid			u
374  *   key.gid			g
375  *   key.hostaddr		h
376  *   key.ipnode			i
377  *   key.projid			p
378  *   key.serv(name)		s
379  *   key.serv(port)		S
380  *   key.ether			e
381  *   key.pkey			k
382  *   key.netaddr		a
383  *   key.attrp			A
384  *   groupsbymember		I
385  *   innetgr_args		t
386  *   setnetgr_args		T
387  */
388 
389 /*ARGSUSED*/
390 static nss_status_t
391 nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
392 	const char *dbname, int dbop, size_t *rlen, const char *typestr)
393 {
394 	int				i, j;
395 	size_t				len, len2, len3, len4, len5, slop;
396 	nssuint_t 			*uptr, offv, offc;
397 	struct nss_setnetgrent_args	*sng;
398 	struct nss_innetgr_args		*ing;
399 	struct nss_groupsbymem		*gbm;
400 	char				**cv, *dptr;
401 	nss_pnetgr_t			*pptr;
402 	_priv_execattr			*pe;
403 
404 	if (buffer == NULL || length == 0 || arg == NULL ||
405 	    dbname == NULL || rlen == NULL || typestr == NULL)
406 		return (NSS_ERROR);
407 
408 	while (typestr && *typestr) {
409 		switch (*typestr++) {
410 		case 'n':
411 			if (arg->key.name == NULL)
412 				return (NSS_NOTFOUND);
413 			len = strlen(arg->key.name) + 1;
414 			if (len >= length)
415 				return (NSS_ERROR);
416 			(void) strlcpy(buffer, arg->key.name, len);
417 			*rlen = len;
418 			break;
419 		case 'N':
420 			len = sizeof (nssuint_t);
421 			if (len >= length)
422 				return (NSS_ERROR);
423 			*(nssuint_t *)buffer = (nssuint_t)arg->key.number;
424 			*rlen = len;
425 			break;
426 		case 'u':
427 			len = sizeof (nssuint_t);
428 			if (len >= length)
429 				return (NSS_ERROR);
430 			*(nssuint_t *)buffer = (nssuint_t)arg->key.uid;
431 			*rlen = len;
432 			break;
433 		case 'g':
434 			len = sizeof (nssuint_t);
435 			if (len >= length)
436 				return (NSS_ERROR);
437 			*(nssuint_t *)buffer = (nssuint_t)arg->key.gid;
438 			*rlen = len;
439 			break;
440 		case 'h':
441 			if (arg->key.hostaddr.addr == NULL)
442 				return (-1);
443 			len = arg->key.hostaddr.len;
444 			len = ROUND_UP(len, sizeof (nssuint_t));
445 			len2 = (sizeof (nssuint_t) * 2) + len;
446 			if (len2 >= length)
447 				return (NSS_ERROR);
448 			*(nssuint_t *)buffer =
449 			    (nssuint_t)arg->key.hostaddr.len;
450 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
451 			*(nssuint_t *)buffer =
452 			    (nssuint_t)arg->key.hostaddr.type;
453 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
454 			(void) memcpy(buffer, arg->key.hostaddr.addr,
455 			    arg->key.hostaddr.len);
456 			*rlen = len2;
457 			break;
458 		case 'i':
459 			if (arg->key.ipnode.name == NULL)
460 				return (NSS_NOTFOUND);
461 			len = strlen(arg->key.ipnode.name) + 1;
462 			len = ROUND_UP(len, sizeof (nssuint_t));
463 			len2 = (sizeof (nssuint_t) * 2) + len;
464 			if (len2 >= length)
465 				return (NSS_ERROR);
466 			*(nssuint_t *)buffer =
467 			    (nssuint_t)arg->key.ipnode.af_family;
468 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
469 			*(nssuint_t *)buffer =
470 			    (nssuint_t)arg->key.ipnode.flags;
471 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
472 			(void) strlcpy(buffer, arg->key.ipnode.name, len);
473 			*rlen = len2;
474 			break;
475 		case 'p':
476 			len = sizeof (nssuint_t);
477 			if (len >= length)
478 				return (NSS_ERROR);
479 			*(nssuint_t *)buffer = (nssuint_t)arg->key.projid;
480 			*rlen = len;
481 			break;
482 		case 's':
483 			if (arg->key.serv.serv.name == NULL)
484 				return (NSS_NOTFOUND);
485 			len = strlen(arg->key.serv.serv.name) + 1;
486 			len2 = 1;
487 			if (arg->key.serv.proto != NULL)
488 				len2 += strlen(arg->key.serv.proto);
489 			len3 = len + len2;
490 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
491 			if (len3 >= length)
492 				return (NSS_ERROR);
493 			(void) strlcpy(buffer, arg->key.serv.serv.name, len);
494 			buffer = (void *)((char *)buffer + len);
495 			if (len2 > 1)
496 				(void) strlcpy(buffer, arg->key.serv.proto,
497 				    len2);
498 			else
499 				*(char *)buffer = '\0';
500 			*rlen = len3;
501 			break;
502 		case 'S':
503 			len2 = 0;
504 			if (arg->key.serv.proto != NULL)
505 				len2 = strlen(arg->key.serv.proto) + 1;
506 			len = sizeof (nssuint_t) + len2;
507 			if (len >= length)
508 				return (NSS_ERROR);
509 			uptr = (nssuint_t *)buffer;
510 			*uptr++ = (nssuint_t)arg->key.serv.serv.port;
511 			if (len2) {
512 				(void) strlcpy((char *)uptr,
513 				    arg->key.serv.proto, len2);
514 			}
515 			*rlen = len;
516 			break;
517 		case 'e':
518 			if (arg->key.ether == NULL)
519 				return (NSS_NOTFOUND);
520 			len = sizeof (struct ether_addr);
521 			len = ROUND_UP(len, sizeof (nssuint_t));
522 			if (len >= length)
523 				return (NSS_ERROR);
524 			*(struct ether_addr *)buffer =
525 			    *(struct ether_addr *)arg->key.ether;
526 			*rlen = len;
527 			break;
528 		case 'k':
529 			if (arg->key.pkey.name == NULL ||
530 			    arg->key.pkey.keytype == NULL)
531 				return (NSS_NOTFOUND);
532 			len = strlen(arg->key.pkey.name) + 1;
533 			len2 = strlen(arg->key.pkey.keytype) + 1;
534 			len3 = len + len2;
535 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
536 			if (len3 >= length)
537 				return (NSS_ERROR);
538 			(void) strlcpy(buffer, arg->key.pkey.name, len);
539 			buffer = (void *)((char *)buffer + len);
540 			(void) strlcpy(buffer, arg->key.pkey.keytype, len2);
541 			*rlen = len3;
542 			break;
543 		case 'a':
544 			uptr = (nssuint_t *)buffer;
545 			len = sizeof (nssuint_t) * 2;
546 			if (len >= length)
547 				return (NSS_ERROR);
548 			*uptr++ = (nssuint_t)arg->key.netaddr.net;
549 			*uptr++ = (nssuint_t)arg->key.netaddr.type;
550 			*rlen = len;
551 			break;
552 		case 'A':
553 			pe = (_priv_execattr *)(arg->key.attrp);
554 			if (pe == NULL)
555 				return (NSS_NOTFOUND);
556 			/* for search flag */
557 			len = sizeof (nssuint_t);
558 			/* for sizeof (_priv_execattr) static buffer */
559 			/* Plus lots of slop just in case... */
560 			slop = sizeof (nssuint_t) * 16;
561 			len += slop;
562 
563 			len2 = len3 = len4 = len5 = 1;
564 			if (pe->name != NULL)
565 				len2 = strlen(pe->name) + 1;
566 			if (pe->type != NULL)
567 				len3 = strlen(pe->type) + 1;
568 			if (pe->id != NULL)
569 				len4 = strlen(pe->id) + 1;
570 			if (pe->policy != NULL)
571 				len5 = strlen(pe->policy) + 1;
572 			/* head_exec, prev_exec - are client side only... */
573 			len += len2 + len3 + len4 + len5;
574 			len = ROUND_UP(len, sizeof (nssuint_t));
575 			if (len >= length)
576 				return (NSS_ERROR);
577 			(void) memset((void *)buffer, 0, slop);
578 			uptr = (nssuint_t *)((void *)((char *)buffer + slop));
579 			*uptr++ = (nssuint_t)pe->search_flag;
580 			dptr = (char *)uptr;
581 			if (len2 == 1)
582 				*dptr++ = '\0';
583 			else {
584 				(void) strlcpy(dptr, pe->name, len2);
585 				dptr += len2;
586 			}
587 			if (len3 == 1)
588 				*dptr++ = '\0';
589 			else {
590 				(void) strlcpy(dptr, pe->type, len3);
591 				dptr += len3;
592 			}
593 			if (len4 == 1)
594 				*dptr++ = '\0';
595 			else {
596 				(void) strlcpy(dptr, pe->id, len4);
597 				dptr += len4;
598 			}
599 			if (len5 == 1)
600 				*dptr++ = '\0';
601 			else
602 				(void) strlcpy(dptr, pe->policy, len5);
603 			*rlen = len;
604 			break;
605 		case 'I':
606 			gbm = (struct nss_groupsbymem *)arg;
607 			if (gbm->username == NULL)
608 				return (NSS_NOTFOUND);
609 			len = strlen(gbm->username) + 1;
610 			len2 = sizeof (nssuint_t) * 4;
611 			len2 += ROUND_UP(len, sizeof (nssuint_t));
612 			if (len2 >= length)
613 				return (NSS_ERROR);
614 			uptr = (nssuint_t *)buffer;
615 			*uptr++ = (nssuint_t)gbm->force_slow_way;
616 			*uptr++ = (nssuint_t)gbm->maxgids;
617 			*uptr++ = (nssuint_t)gbm->numgids;
618 			if (gbm->numgids == 1) {
619 				*uptr++ = (nssuint_t)gbm->gid_array[0];
620 			} else {
621 				*uptr++ = (nssuint_t)0;
622 			}
623 			(void) strlcpy((void *)uptr, gbm->username, len);
624 			*rlen = len2;
625 			break;
626 		case 't':
627 			pptr = (nss_pnetgr_t *)buffer;
628 			ing = (struct nss_innetgr_args *)arg;
629 			len = sizeof (nss_pnetgr_t);
630 			len2 = ing->arg[NSS_NETGR_MACHINE].argc +
631 			    ing->arg[NSS_NETGR_USER].argc +
632 			    ing->arg[NSS_NETGR_DOMAIN].argc +
633 			    ing->groups.argc;
634 			len2 *= sizeof (nssuint_t);
635 			len3 = 0;
636 			for (j = 0; j < NSS_NETGR_N; j++) {
637 				cv = ing->arg[j].argv;
638 				for (i = ing->arg[j].argc; --i >= 0; ) {
639 					if (*cv)
640 						len3 += strlen(*cv++) + 1;
641 				}
642 			}
643 			cv = ing->groups.argv;
644 			for (i = ing->groups.argc; --i >= 0; ) {
645 				if (*cv)
646 					len3 += strlen(*cv++) + 1;
647 			}
648 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
649 			/*
650 			 * Double argv space. Reason:
651 			 *    First 1/2 offsets
652 			 *    Second 1/2 for client side pointer arrays
653 			 *    resolves malloc/free issues with unpacked argvs
654 			 */
655 			if ((len + (len2 << 1) + len3) >= length)
656 				return (NSS_ERROR);
657 			*rlen = len + (len2 << 1) + len3;
658 
659 			pptr->machine_argc = ing->arg[NSS_NETGR_MACHINE].argc;
660 			pptr->user_argc = ing->arg[NSS_NETGR_USER].argc;
661 			pptr->domain_argc = ing->arg[NSS_NETGR_DOMAIN].argc;
662 			pptr->groups_argc = ing->groups.argc;
663 			offv = len;
664 			uptr = (nssuint_t *)((void *)((char *)buffer + offv));
665 			offc = len + (len2 << 1);
666 			dptr = (char *)buffer + offc;
667 			if (pptr->machine_argc == 0) {
668 				pptr->machine_offv = (nssuint_t)0;
669 			} else {
670 				pptr->machine_offv = offv;
671 				cv = ing->arg[NSS_NETGR_MACHINE].argv;
672 				i = pptr->machine_argc;
673 				offv += sizeof (nssuint_t) * i;
674 				for (; --i >= 0; ) {
675 					*uptr++ = offc;
676 					len3 = strlen(*cv) + 1;
677 					(void) strlcpy(dptr, *cv++, len3);
678 					offc += len3;
679 					dptr += len3;
680 				}
681 			}
682 			if (pptr->user_argc == 0) {
683 				pptr->user_offv = (nssuint_t)0;
684 			} else {
685 				pptr->user_offv = offv;
686 				cv = ing->arg[NSS_NETGR_USER].argv;
687 				i = pptr->user_argc;
688 				offv += sizeof (nssuint_t) * i;
689 				for (; --i >= 0; ) {
690 					*uptr++ = offc;
691 					len3 = strlen(*cv) + 1;
692 					(void) strlcpy(dptr, *cv++, len3);
693 					offc += len3;
694 					dptr += len3;
695 				}
696 			}
697 			if (pptr->domain_argc == 0) {
698 				pptr->domain_offv = (nssuint_t)0;
699 			} else {
700 				pptr->domain_offv = offv;
701 				cv = ing->arg[NSS_NETGR_DOMAIN].argv;
702 				i = pptr->domain_argc;
703 				offv += sizeof (nssuint_t) * i;
704 				for (; --i >= 0; ) {
705 					*uptr++ = offc;
706 					len3 = strlen(*cv) + 1;
707 					(void) strlcpy(dptr, *cv++, len3);
708 					offc += len3;
709 					dptr += len3;
710 				}
711 			}
712 			if (pptr->groups_argc == 0) {
713 				pptr->groups_offv = (nssuint_t)0;
714 			} else {
715 				pptr->groups_offv = offv;
716 				cv = ing->groups.argv;
717 				i = pptr->groups_argc;
718 				offv += sizeof (nssuint_t) * i;
719 				for (; --i >= 0; ) {
720 					*uptr++ = offc;
721 					len3 = strlen(*cv) + 1;
722 					(void) strlcpy(dptr, *cv++, len3);
723 					offc += len3;
724 					dptr += len3;
725 				}
726 			}
727 			break;
728 		case 'T':
729 			sng = (struct nss_setnetgrent_args *)arg;
730 			if (sng->netgroup == NULL)
731 				return (NSS_NOTFOUND);
732 			len = strlen(sng->netgroup) + 1;
733 			if (len >= length)
734 				return (NSS_ERROR);
735 			(void) strlcpy(buffer, sng->netgroup, len);
736 			*rlen = len;
737 			break;
738 		default:
739 			return (NSS_ERROR);
740 		}
741 	}
742 	return (NSS_SUCCESS);
743 }
744 
745 nss_status_t
746 nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
747 	const char *dbname, int dbop, size_t *rlen)
748 {
749 	int		index;
750 
751 	if (buffer == NULL || length == 0 || arg == NULL ||
752 	    dbname == NULL || rlen == NULL)
753 		return (NSS_ERROR);
754 
755 	/*
756 	 * If this is not one of the well known getXbyYs
757 	 * (IE _printers special processing etc.) use a
758 	 * local (non-nscd) getXbyY lookup.
759 	 */
760 	if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
761 		return (NSS_TRYLOCAL);
762 
763 	return (nss_pack_key2str(buffer, length, arg, dbname,
764 	    dbop, rlen, getXbyY_to_dbop[index].tostr));
765 }
766 
767 /*ARGSUSED*/
768 void
769 nss_packed_set_status(void *buffer, size_t length, nss_status_t status,
770 		nss_XbyY_args_t *arg)
771 {
772 	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
773 	nss_dbd_t	*pdbd;
774 	char		*dbn;
775 
776 	/* sidestep odd cases */
777 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
778 	dbn = (char *)pdbd + pdbd->o_name;
779 	if (pbuf->nss_dbop == NSS_DBOP_GROUP_BYMEMBER) {
780 		if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) {
781 			struct nss_groupsbymem *in =
782 			    (struct nss_groupsbymem *)arg;
783 
784 			if (in->numgids >= 0) {
785 				pbuf->p_status = NSS_SUCCESS;
786 				pbuf->data_len = in->numgids *
787 				    sizeof (gid_t);
788 				pbuf->p_herrno = 0;
789 			} else {
790 				pbuf->p_status = status;
791 				pbuf->p_errno = errno;
792 				pbuf->data_len = 0;
793 				pbuf->p_herrno = (uint32_t)arg->h_errno;
794 			}
795 			return;
796 		}
797 	}
798 	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN) {
799 		if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
800 			struct nss_innetgr_args *in =
801 			    (struct nss_innetgr_args *)arg;
802 
803 			/* tell nss_unpack() operation is successful */
804 			pbuf->data_len = 1;
805 
806 			if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
807 				pbuf->p_status = status;
808 				pbuf->p_errno = errno;
809 				return;
810 			}
811 
812 			if (in->status == NSS_NETGR_FOUND) {
813 				pbuf->p_status = NSS_SUCCESS;
814 			} else {
815 				pbuf->p_status = NSS_NOTFOUND;
816 				pbuf->p_errno = errno;
817 			}
818 			return;
819 		}
820 	}
821 
822 	/* process normal cases */
823 	if ((pbuf->p_status = status) != NSS_SUCCESS) {
824 		if (arg->erange == 1)
825 			pbuf->p_errno = ERANGE;
826 		else
827 			pbuf->p_errno = errno;
828 	} else
829 		pbuf->p_errno = 0;
830 	if (arg != NULL) {
831 		pbuf->p_herrno = (uint32_t)arg->h_errno;
832 		pbuf->data_len = (nssuint_t)arg->returnlen;
833 	} else {
834 		pbuf->p_herrno = 0;
835 		pbuf->data_len = 0;
836 	}
837 }
838 
839 /*
840  * nss_upack_key2arg
841  * Private string to key unpacking function for getXbyY routines
842  * This routine performs a scanf/printf like parse over the packed
843  * string, to uppack and re-assemble the key in the args structure.
844  *
845  * buffer - Start of the key buffer location [in packed buffer]
846  * length - Length of key buffer component
847  * Key offsets are relative to start of key buffer location.
848  *
849  * Unpack fields		Key
850  *   key.name			n
851  *   key.number			N
852  *   key.uid			u
853  *   key.gid			g
854  *   key.hostaddr		h
855  *   key.ipnode			i
856  *   key.projid			p
857  *   key.serv(name)		s
858  *   key.serv(port)		S
859  *   key.ether			e
860  *   key.pkey			k
861  *   key.netaddr		a
862  *   key.attrp			A
863  *   groupsbymember		I
864  *   innetgr_args		t
865  *   setnetgr_args		T
866  * Assumes arguments are all valid
867  */
868 
869 /*ARGSUSED*/
870 static nss_status_t
871 nss_upack_key2arg(void *buffer, size_t length, char **dbname,
872 		int *dbop, nss_XbyY_args_t *arg, int index)
873 {
874 	nss_pheader_t 			*pbuf = (nss_pheader_t *)buffer;
875 	const char			*strtype = NULL;
876 	nssuint_t 			off, *uptr, keysize;
877 	size_t				len, slop;
878 	int				i, j;
879 	char				**cv, *bptr;
880 	struct nss_setnetgrent_args	*sng;
881 	struct nss_innetgr_args		*ing;
882 	struct nss_groupsbymem		*gbm;
883 	nss_pnetgr_t			*pptr;
884 	_priv_execattr			*pe;
885 
886 	/* keysize is length of the key area */
887 	keysize = pbuf->data_off - pbuf->key_off;
888 
889 	off = pbuf->key_off;
890 	bptr = (char *)buffer + off;
891 	uptr = (nssuint_t *)((void *)bptr);
892 	strtype = getXbyY_to_dbop[index].tostr;
893 	if (strtype == NULL)
894 		return (NSS_ERROR);
895 	while (*strtype) {
896 		switch (*strtype++) {
897 		case 'n':
898 			arg->key.name = (const char *)bptr;
899 			break;
900 		case 'N':
901 			arg->key.number = (int)(*uptr);
902 			break;
903 		case 'u':
904 			arg->key.uid = (uid_t)(*uptr);
905 			break;
906 		case 'g':
907 			arg->key.gid = (gid_t)(*uptr);
908 			break;
909 		case 'h':
910 			arg->key.hostaddr.len = (int)(*uptr++);
911 			arg->key.hostaddr.type = (int)(*uptr++);
912 			arg->key.hostaddr.addr = (const char *)uptr;
913 			break;
914 		case 'i':
915 			arg->key.ipnode.af_family = (int)(*uptr++);
916 			arg->key.ipnode.flags = (int)(*uptr++);
917 			arg->key.ipnode.name = (const char *)uptr;
918 			break;
919 		case 'p':
920 			arg->key.projid = (projid_t)(*uptr);
921 			break;
922 		case 's':
923 			arg->key.serv.serv.name = (const char *)bptr;
924 			len = strlen(arg->key.serv.serv.name) + 1;
925 			bptr += len;
926 			if (*(const char *)bptr == '\0')
927 				arg->key.serv.proto = NULL;
928 			else
929 				arg->key.serv.proto = (const char *)bptr;
930 			break;
931 		case 'S':
932 			arg->key.serv.serv.port = (int)(*uptr++);
933 			if (pbuf->key_len == sizeof (nssuint_t)) {
934 				arg->key.serv.proto = NULL;
935 			} else {
936 				bptr += sizeof (nssuint_t);
937 				arg->key.serv.proto = (const char *)bptr;
938 			}
939 			break;
940 		case 'e':
941 			arg->key.ether = bptr;
942 			break;
943 		case 'k':
944 			arg->key.pkey.name = (const char *)bptr;
945 			len = strlen(arg->key.pkey.name) + 1;
946 			bptr += len;
947 			arg->key.pkey.keytype = (const char *)bptr;
948 			break;
949 		case 'a':
950 			arg->key.netaddr.net = (uint32_t)(*uptr++);
951 			arg->key.netaddr.type = (int)(*uptr++);
952 			break;
953 		case 'A':
954 			pe = (_priv_execattr *)((void *)bptr);
955 			/* use slop space as priv_execattr structure */
956 			arg->key.attrp = (void *)pe;
957 			/* skip over slop ... */
958 			slop = sizeof (nssuint_t) * 16;
959 			uptr = (nssuint_t *)((void *)((char *)bptr + slop));
960 			pe->search_flag = (int)*uptr++;
961 			bptr = (char *)uptr;
962 			if (*bptr == '\0') {
963 				pe->name = NULL;
964 				bptr++;
965 			} else {
966 				pe->name = (char *)bptr;
967 				bptr += strlen(pe->name) + 1;
968 			}
969 			if (*bptr == '\0') {
970 				pe->type = NULL;
971 				bptr++;
972 			} else {
973 				pe->type = (char *)bptr;
974 				bptr += strlen(pe->type) + 1;
975 			}
976 			if (*bptr == '\0') {
977 				pe->id = NULL;
978 				bptr++;
979 			} else {
980 				pe->id = (char *)bptr;
981 				bptr += strlen(pe->id) + 1;
982 			}
983 			if (*bptr == '\0') {
984 				pe->policy = NULL;
985 			} else {
986 				pe->policy = (char *)bptr;
987 			}
988 			pe->head_exec = NULL;
989 			pe->prev_exec = NULL;
990 			break;
991 		case 'I':
992 			gbm = (struct nss_groupsbymem *)arg;
993 			gbm->gid_array = (gid_t *)
994 			    ((void *)((char *)pbuf + pbuf->data_off));
995 			gbm->force_slow_way = (int)(*uptr++);
996 			gbm->maxgids = (int)(*uptr++);
997 			gbm->numgids = (int)(*uptr++);
998 			if (gbm->numgids == 1) {
999 				/* insert initial group into data area */
1000 				gbm->gid_array[0] = (gid_t)(*uptr++);
1001 			} else
1002 				uptr++;
1003 			gbm->username = (const char *)uptr;
1004 			break;
1005 		case 't':
1006 			pptr = (nss_pnetgr_t *)((void *)bptr);
1007 			ing = (struct nss_innetgr_args *)arg;
1008 			ing->arg[NSS_NETGR_MACHINE].argc = pptr->machine_argc;
1009 			ing->arg[NSS_NETGR_USER].argc = pptr->user_argc;
1010 			ing->arg[NSS_NETGR_DOMAIN].argc = pptr->domain_argc;
1011 			ing->groups.argc = pptr->groups_argc;
1012 
1013 			/*
1014 			 * Start of argv pointer storage
1015 			 */
1016 			off = ing->arg[NSS_NETGR_MACHINE].argc +
1017 			    ing->arg[NSS_NETGR_USER].argc +
1018 			    ing->arg[NSS_NETGR_DOMAIN].argc +
1019 			    ing->groups.argc;
1020 			off *= sizeof (nssuint_t);
1021 			off += sizeof (nss_pnetgr_t);
1022 
1023 			cv = (char **)((void *)(bptr + off));
1024 			uptr = (nssuint_t *)
1025 			    ((void *)(bptr + sizeof (nss_pnetgr_t)));
1026 			for (j = 0; j < NSS_NETGR_N; j++) {
1027 				ing->arg[j].argv = cv;
1028 				for (i = 0; i < ing->arg[j].argc; i++) {
1029 					if (*uptr >= keysize)
1030 						return (NSS_ERROR);
1031 					*cv++ = (bptr + *uptr++);
1032 				}
1033 			}
1034 			ing->groups.argv = cv;
1035 			for (i = 0; i < ing->groups.argc; i++) {
1036 				if (*uptr >= keysize)
1037 					return (NSS_ERROR);
1038 				*cv++ = (bptr + *uptr++);
1039 			}
1040 			break;
1041 		case 'T':
1042 			sng = (struct nss_setnetgrent_args *)arg;
1043 			sng->netgroup = (const char *)bptr;
1044 			sng->iterator = 0;
1045 			break;
1046 
1047 		default:
1048 			return (NSS_ERROR);
1049 		}
1050 	}
1051 	return (NSS_SUCCESS);
1052 }
1053 
1054 static nss_status_t
1055 nss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e)
1056 {
1057 	const char	*name;
1058 	void		*htmp = NULL;
1059 	void		*sym;
1060 	static void	*handle = NULL;
1061 	static mutex_t	handle_lock = DEFAULTMUTEX;
1062 	static mutex_t	initf_lock = DEFAULTMUTEX;
1063 	static mutex_t	s2e_lock = DEFAULTMUTEX;
1064 
1065 	if (handle == NULL) {
1066 		htmp = dlopen((const char *)0, RTLD_LAZY);
1067 
1068 		lmutex_lock(&handle_lock);
1069 		if (handle == NULL) {
1070 			if (htmp == NULL) {
1071 				lmutex_unlock(&handle_lock);
1072 				return (NSS_ERROR);
1073 			} else {
1074 				membar_producer();
1075 				handle = htmp;
1076 				htmp = NULL;
1077 			}
1078 		}
1079 		lmutex_unlock(&handle_lock);
1080 		if (htmp)
1081 			(void) dlclose(htmp);
1082 	}
1083 	membar_consumer();
1084 
1085 	if (initf) {
1086 		if (getXbyY_to_dbop[index].initfnp == NULL) {
1087 			name = getXbyY_to_dbop[index].initfn;
1088 			if ((sym = dlsym(handle, name)) == NULL)
1089 				return (NSS_ERROR);
1090 			lmutex_lock(&initf_lock);
1091 			if (getXbyY_to_dbop[index].initfnp == NULL)
1092 				getXbyY_to_dbop[index].initfnp = sym;
1093 			membar_producer();
1094 			lmutex_unlock(&initf_lock);
1095 		}
1096 		membar_consumer();
1097 		*initf = (nss_db_initf_t)getXbyY_to_dbop[index].initfnp;
1098 	}
1099 	if (s2e) {
1100 		if (getXbyY_to_dbop[index].strfnp == NULL) {
1101 			name = getXbyY_to_dbop[index].strfn;
1102 			if ((sym = dlsym(handle, name)) == NULL)
1103 				return (NSS_ERROR);
1104 			lmutex_lock(&s2e_lock);
1105 			if (getXbyY_to_dbop[index].strfnp == NULL)
1106 				getXbyY_to_dbop[index].strfnp = sym;
1107 			membar_producer();
1108 			lmutex_unlock(&s2e_lock);
1109 		}
1110 		membar_consumer();
1111 		*s2e = (nss_str2ent_t)getXbyY_to_dbop[index].strfnp;
1112 	}
1113 
1114 	return (NSS_SUCCESS);
1115 }
1116 
1117 nss_status_t
1118 nss_packed_getkey(void *buffer, size_t length, char **dbname,
1119 		int *dbop, nss_XbyY_args_t *arg)
1120 {
1121 	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
1122 	nss_dbd_t	*pdbd;
1123 	nssuint_t 	off, dbdsize;
1124 	int		index;
1125 
1126 	if (buffer == NULL || length == 0 || dbop == NULL ||
1127 	    arg == NULL || dbname == NULL)
1128 		return (NSS_ERROR);
1129 
1130 	*dbop = pbuf->nss_dbop;
1131 	off = pbuf->dbd_off;
1132 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
1133 	dbdsize = pbuf->key_off - pbuf->dbd_off;
1134 	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
1135 	    pdbd->o_default_config >= dbdsize)
1136 		return (NSS_ERROR);
1137 	*dbname = (char *)buffer + off + pdbd->o_name;
1138 	if ((index = nss_dbop_search(*dbname, (uint32_t)*dbop)) < 0)
1139 		return (NSS_ERROR);
1140 	return (nss_upack_key2arg(buffer, length, dbname, dbop, arg, index));
1141 }
1142 
1143 
1144 /*
1145  * str2packent: Standard format interposed str2X function for normal APIs
1146  *
1147  * Return values: 0 = success, 1 = parse error, 2 = erange ...
1148  *
1149  * The structure pointer is ignored since this is a nscd side packed request.
1150  * The client side routine does all the real parsing; we just check limits and
1151  * store the entry in the buffer we were passed by the caller.
1152  */
1153 
1154 /*ARGSUSED*/
1155 static int
1156 str2packent(
1157     const char *instr,
1158     int lenstr,
1159     void *ent,		/* really (char *) */
1160     char *buffer,
1161     int buflen
1162 )
1163 {
1164 	if (buflen <= lenstr) {		/* not enough buffer */
1165 		return (NSS_STR_PARSE_ERANGE);
1166 	}
1167 	(void) memmove(buffer, instr, lenstr);
1168 	buffer[lenstr] = '\0';
1169 
1170 	return (NSS_STR_PARSE_SUCCESS);
1171 }
1172 
1173 /*
1174  * Initialize db_root, initf, dbop and arg from a packed buffer
1175  */
1176 
1177 /*ARGSUSED*/
1178 nss_status_t
1179 nss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
1180 		nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg)
1181 {
1182 	nss_pheader_t 		*pbuf = (nss_pheader_t *)buffer;
1183 	nss_str2ent_t		s2e = str2packent;
1184 	nss_str2ent_t		real_s2e = NULL;
1185 	nss_dbd_t		*pdbd;
1186 	nssuint_t		off, dbdsize;
1187 	char			*dbname, *bptr;
1188 	size_t			len;
1189 	int			index;
1190 
1191 	if (buffer == NULL || length == 0 ||
1192 	    dbop == NULL || arg == NULL)
1193 		return (NSS_ERROR);
1194 
1195 	/* init dbop */
1196 	*dbop = pbuf->nss_dbop;
1197 	off = pbuf->dbd_off;
1198 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
1199 	dbdsize = pbuf->key_off - pbuf->dbd_off;
1200 	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
1201 	    pdbd->o_default_config >= dbdsize)
1202 		return (NSS_ERROR);
1203 	dbname = (char *)buffer + off + pdbd->o_name;
1204 	if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0)
1205 		return (NSS_ERROR);
1206 
1207 	/* db_root is initialized by nscd's based on door info */
1208 	/* do nothing here */
1209 
1210 	/* init key information - (and get dbname dbop etc...) */
1211 	if (nss_upack_key2arg(buffer, length, &dbname,
1212 	    dbop, arg, index) != NSS_SUCCESS)
1213 		return (NSS_ERROR);
1214 
1215 	/* possible audituser init */
1216 	if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
1217 		arg->h_errno = (int)pbuf->p_herrno;
1218 
1219 	bptr = (char *)buffer + pbuf->data_off;
1220 	len = (size_t)pbuf->data_len;
1221 
1222 	/* sidestep odd arg cases */
1223 	if (*dbop == NSS_DBOP_GROUP_BYMEMBER &&
1224 	    strcmp(dbname, NSS_DBNAM_GROUP) == 0) {
1225 		/* get initf  and str2ent functions */
1226 		if (nss_pinit_funcs(index, initf, &real_s2e) != NSS_SUCCESS)
1227 			return (NSS_ERROR);
1228 		((struct nss_groupsbymem *)arg)->str2ent = real_s2e;
1229 		((struct nss_groupsbymem *)arg)->process_cstr = process_cstr;
1230 		return (NSS_SUCCESS);
1231 	}
1232 	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
1233 	    strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
1234 		return (NSS_SUCCESS);
1235 	}
1236 
1237 	/* get initf  and str2ent functions */
1238 	if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
1239 		return (NSS_ERROR);
1240 
1241 	/* init normal arg cases */
1242 	NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1243 	arg->h_errno = 0;
1244 
1245 	return (NSS_SUCCESS);
1246 }
1247 
1248 /*
1249  * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
1250  */
1251 
1252 /*ARGSUSED*/
1253 nss_status_t
1254 nss_packed_context_init(void *buffer, size_t length, nss_db_root_t *db_root,
1255 		nss_db_initf_t *initf, nss_getent_t **contextp,
1256 		nss_XbyY_args_t *arg)
1257 {
1258 	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
1259 	nss_str2ent_t	s2e = str2packent;
1260 	char		*bptr;
1261 	size_t		len;
1262 
1263 	/* init arg */
1264 	if (arg != NULL) {
1265 		bptr = (char *)buffer + pbuf->data_off;
1266 		len = (size_t)pbuf->data_len;
1267 		NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1268 	}
1269 
1270 	return (NSS_SUCCESS);
1271 }
1272