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