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