xref: /illumos-gate/usr/src/lib/libc/port/gen/nss_dbdefs.c (revision dd72704bd9e794056c558153663c739e2012d721)
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  * "instr" is the beginning of the aliases string
134  * "buffer" has the return val for success
135  * "buflen" is the length of the buffer available for aliases
136  */
137 char **
138 _nss_netdb_aliases(const char *instr, int lenstr, char *buffer, int buflen)
139 {
140 	/*
141 	 * Build the alias-list in the start of the buffer, and copy
142 	 * the strings to the end of the buffer.
143 	 */
144 	const char *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 static nss_status_t
390 nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
391     const char *dbname, int dbop __unused, size_t *rlen, const char *typestr)
392 {
393 	int				i, j;
394 	size_t				len, len2, len3, len4, len5, slop;
395 	nssuint_t			*uptr, offv, offc;
396 	struct nss_setnetgrent_args	*sng;
397 	struct nss_innetgr_args		*ing;
398 	struct nss_groupsbymem		*gbm;
399 	char				**cv, *dptr;
400 	nss_pnetgr_t			*pptr;
401 	_priv_execattr			*pe;
402 
403 	if (buffer == NULL || length == 0 || arg == NULL ||
404 	    dbname == NULL || rlen == NULL || typestr == NULL)
405 		return (NSS_ERROR);
406 
407 	while (typestr && *typestr) {
408 		switch (*typestr++) {
409 		case 'n':
410 			if (arg->key.name == NULL)
411 				return (NSS_NOTFOUND);
412 			len = strlen(arg->key.name) + 1;
413 			if (len >= length)
414 				return (NSS_ERROR);
415 			(void) strlcpy(buffer, arg->key.name, len);
416 			*rlen = len;
417 			break;
418 		case 'N':
419 			len = sizeof (nssuint_t);
420 			if (len >= length)
421 				return (NSS_ERROR);
422 			*(nssuint_t *)buffer = (nssuint_t)arg->key.number;
423 			*rlen = len;
424 			break;
425 		case 'u':
426 			len = sizeof (nssuint_t);
427 			if (len >= length)
428 				return (NSS_ERROR);
429 			*(nssuint_t *)buffer = (nssuint_t)arg->key.uid;
430 			*rlen = len;
431 			break;
432 		case 'g':
433 			len = sizeof (nssuint_t);
434 			if (len >= length)
435 				return (NSS_ERROR);
436 			*(nssuint_t *)buffer = (nssuint_t)arg->key.gid;
437 			*rlen = len;
438 			break;
439 		case 'h':
440 			if (arg->key.hostaddr.addr == NULL)
441 				return (-1);
442 			len = arg->key.hostaddr.len;
443 			len = ROUND_UP(len, sizeof (nssuint_t));
444 			len2 = (sizeof (nssuint_t) * 2) + len;
445 			if (len2 >= length)
446 				return (NSS_ERROR);
447 			*(nssuint_t *)buffer =
448 			    (nssuint_t)arg->key.hostaddr.len;
449 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
450 			*(nssuint_t *)buffer =
451 			    (nssuint_t)arg->key.hostaddr.type;
452 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
453 			(void) memcpy(buffer, arg->key.hostaddr.addr,
454 			    arg->key.hostaddr.len);
455 			*rlen = len2;
456 			break;
457 		case 'i':
458 			if (arg->key.ipnode.name == NULL)
459 				return (NSS_NOTFOUND);
460 			len = strlen(arg->key.ipnode.name) + 1;
461 			len = ROUND_UP(len, sizeof (nssuint_t));
462 			len2 = (sizeof (nssuint_t) * 2) + len;
463 			if (len2 >= length)
464 				return (NSS_ERROR);
465 			*(nssuint_t *)buffer =
466 			    (nssuint_t)arg->key.ipnode.af_family;
467 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
468 			*(nssuint_t *)buffer =
469 			    (nssuint_t)arg->key.ipnode.flags;
470 			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
471 			(void) strlcpy(buffer, arg->key.ipnode.name, len);
472 			*rlen = len2;
473 			break;
474 		case 'p':
475 			len = sizeof (nssuint_t);
476 			if (len >= length)
477 				return (NSS_ERROR);
478 			*(nssuint_t *)buffer = (nssuint_t)arg->key.projid;
479 			*rlen = len;
480 			break;
481 		case 's':
482 			if (arg->key.serv.serv.name == NULL)
483 				return (NSS_NOTFOUND);
484 			len = strlen(arg->key.serv.serv.name) + 1;
485 			len2 = 1;
486 			if (arg->key.serv.proto != NULL)
487 				len2 += strlen(arg->key.serv.proto);
488 			len3 = len + len2;
489 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
490 			if (len3 >= length)
491 				return (NSS_ERROR);
492 			(void) strlcpy(buffer, arg->key.serv.serv.name, len);
493 			buffer = (void *)((char *)buffer + len);
494 			if (len2 > 1)
495 				(void) strlcpy(buffer, arg->key.serv.proto,
496 				    len2);
497 			else
498 				*(char *)buffer = '\0';
499 			*rlen = len3;
500 			break;
501 		case 'S':
502 			len2 = 0;
503 			if (arg->key.serv.proto != NULL)
504 				len2 = strlen(arg->key.serv.proto) + 1;
505 			len = sizeof (nssuint_t) + len2;
506 			if (len >= length)
507 				return (NSS_ERROR);
508 			uptr = (nssuint_t *)buffer;
509 			*uptr++ = (nssuint_t)arg->key.serv.serv.port;
510 			if (len2) {
511 				(void) strlcpy((char *)uptr,
512 				    arg->key.serv.proto, len2);
513 			}
514 			*rlen = len;
515 			break;
516 		case 'e':
517 			if (arg->key.ether == NULL)
518 				return (NSS_NOTFOUND);
519 			len = sizeof (struct ether_addr);
520 			len = ROUND_UP(len, sizeof (nssuint_t));
521 			if (len >= length)
522 				return (NSS_ERROR);
523 			*(struct ether_addr *)buffer =
524 			    *(struct ether_addr *)arg->key.ether;
525 			*rlen = len;
526 			break;
527 		case 'k':
528 			if (arg->key.pkey.name == NULL ||
529 			    arg->key.pkey.keytype == NULL)
530 				return (NSS_NOTFOUND);
531 			len = strlen(arg->key.pkey.name) + 1;
532 			len2 = strlen(arg->key.pkey.keytype) + 1;
533 			len3 = len + len2;
534 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
535 			if (len3 >= length)
536 				return (NSS_ERROR);
537 			(void) strlcpy(buffer, arg->key.pkey.name, len);
538 			buffer = (void *)((char *)buffer + len);
539 			(void) strlcpy(buffer, arg->key.pkey.keytype, len2);
540 			*rlen = len3;
541 			break;
542 		case 'a':
543 			uptr = (nssuint_t *)buffer;
544 			len = sizeof (nssuint_t) * 2;
545 			if (len >= length)
546 				return (NSS_ERROR);
547 			*uptr++ = (nssuint_t)arg->key.netaddr.net;
548 			*uptr++ = (nssuint_t)arg->key.netaddr.type;
549 			*rlen = len;
550 			break;
551 		case 'A':
552 			pe = (_priv_execattr *)(arg->key.attrp);
553 			if (pe == NULL)
554 				return (NSS_NOTFOUND);
555 			/* for search flag */
556 			len = sizeof (nssuint_t);
557 			/* for sizeof (_priv_execattr) static buffer */
558 			/* Plus lots of slop just in case... */
559 			slop = sizeof (nssuint_t) * 16;
560 			len += slop;
561 
562 			len2 = len3 = len4 = len5 = 1;
563 			if (pe->name != NULL)
564 				len2 = strlen(pe->name) + 1;
565 			if (pe->type != NULL)
566 				len3 = strlen(pe->type) + 1;
567 			if (pe->id != NULL)
568 				len4 = strlen(pe->id) + 1;
569 			if (pe->policy != NULL)
570 				len5 = strlen(pe->policy) + 1;
571 			/* head_exec, prev_exec - are client side only... */
572 			len += len2 + len3 + len4 + len5;
573 			len = ROUND_UP(len, sizeof (nssuint_t));
574 			if (len >= length)
575 				return (NSS_ERROR);
576 			(void) memset((void *)buffer, 0, slop);
577 			uptr = (nssuint_t *)((void *)((char *)buffer + slop));
578 			*uptr++ = (nssuint_t)pe->search_flag;
579 			dptr = (char *)uptr;
580 			if (len2 == 1)
581 				*dptr++ = '\0';
582 			else {
583 				(void) strlcpy(dptr, pe->name, len2);
584 				dptr += len2;
585 			}
586 			if (len3 == 1)
587 				*dptr++ = '\0';
588 			else {
589 				(void) strlcpy(dptr, pe->type, len3);
590 				dptr += len3;
591 			}
592 			if (len4 == 1)
593 				*dptr++ = '\0';
594 			else {
595 				(void) strlcpy(dptr, pe->id, len4);
596 				dptr += len4;
597 			}
598 			if (len5 == 1)
599 				*dptr++ = '\0';
600 			else
601 				(void) strlcpy(dptr, pe->policy, len5);
602 			*rlen = len;
603 			break;
604 		case 'I':
605 			gbm = (struct nss_groupsbymem *)arg;
606 			if (gbm->username == NULL)
607 				return (NSS_NOTFOUND);
608 			len = strlen(gbm->username) + 1;
609 			len2 = sizeof (nssuint_t) * 4;
610 			len2 += ROUND_UP(len, sizeof (nssuint_t));
611 			if (len2 >= length)
612 				return (NSS_ERROR);
613 			uptr = (nssuint_t *)buffer;
614 			*uptr++ = (nssuint_t)gbm->force_slow_way;
615 			*uptr++ = (nssuint_t)gbm->maxgids;
616 			*uptr++ = (nssuint_t)gbm->numgids;
617 			if (gbm->numgids == 1) {
618 				*uptr++ = (nssuint_t)gbm->gid_array[0];
619 			} else {
620 				*uptr++ = (nssuint_t)0;
621 			}
622 			(void) strlcpy((void *)uptr, gbm->username, len);
623 			*rlen = len2;
624 			break;
625 		case 't':
626 			pptr = (nss_pnetgr_t *)buffer;
627 			ing = (struct nss_innetgr_args *)arg;
628 			len = sizeof (nss_pnetgr_t);
629 			len2 = ing->arg[NSS_NETGR_MACHINE].argc +
630 			    ing->arg[NSS_NETGR_USER].argc +
631 			    ing->arg[NSS_NETGR_DOMAIN].argc +
632 			    ing->groups.argc;
633 			len2 *= sizeof (nssuint_t);
634 			len3 = 0;
635 			for (j = 0; j < NSS_NETGR_N; j++) {
636 				cv = ing->arg[j].argv;
637 				for (i = ing->arg[j].argc; --i >= 0; ) {
638 					if (*cv)
639 						len3 += strlen(*cv++) + 1;
640 				}
641 			}
642 			cv = ing->groups.argv;
643 			for (i = ing->groups.argc; --i >= 0; ) {
644 				if (*cv)
645 					len3 += strlen(*cv++) + 1;
646 			}
647 			len3 = ROUND_UP(len3, sizeof (nssuint_t));
648 			/*
649 			 * Double argv space. Reason:
650 			 *    First 1/2 offsets
651 			 *    Second 1/2 for client side pointer arrays
652 			 *    resolves malloc/free issues with unpacked argvs
653 			 */
654 			if ((len + (len2 << 1) + len3) >= length)
655 				return (NSS_ERROR);
656 			*rlen = len + (len2 << 1) + len3;
657 
658 			pptr->machine_argc = ing->arg[NSS_NETGR_MACHINE].argc;
659 			pptr->user_argc = ing->arg[NSS_NETGR_USER].argc;
660 			pptr->domain_argc = ing->arg[NSS_NETGR_DOMAIN].argc;
661 			pptr->groups_argc = ing->groups.argc;
662 			offv = len;
663 			uptr = (nssuint_t *)((void *)((char *)buffer + offv));
664 			offc = len + (len2 << 1);
665 			dptr = (char *)buffer + offc;
666 			if (pptr->machine_argc == 0) {
667 				pptr->machine_offv = (nssuint_t)0;
668 			} else {
669 				pptr->machine_offv = offv;
670 				cv = ing->arg[NSS_NETGR_MACHINE].argv;
671 				i = pptr->machine_argc;
672 				offv += sizeof (nssuint_t) * i;
673 				for (; --i >= 0; ) {
674 					*uptr++ = offc;
675 					len3 = strlen(*cv) + 1;
676 					(void) strlcpy(dptr, *cv++, len3);
677 					offc += len3;
678 					dptr += len3;
679 				}
680 			}
681 			if (pptr->user_argc == 0) {
682 				pptr->user_offv = (nssuint_t)0;
683 			} else {
684 				pptr->user_offv = offv;
685 				cv = ing->arg[NSS_NETGR_USER].argv;
686 				i = pptr->user_argc;
687 				offv += sizeof (nssuint_t) * i;
688 				for (; --i >= 0; ) {
689 					*uptr++ = offc;
690 					len3 = strlen(*cv) + 1;
691 					(void) strlcpy(dptr, *cv++, len3);
692 					offc += len3;
693 					dptr += len3;
694 				}
695 			}
696 			if (pptr->domain_argc == 0) {
697 				pptr->domain_offv = (nssuint_t)0;
698 			} else {
699 				pptr->domain_offv = offv;
700 				cv = ing->arg[NSS_NETGR_DOMAIN].argv;
701 				i = pptr->domain_argc;
702 				offv += sizeof (nssuint_t) * i;
703 				for (; --i >= 0; ) {
704 					*uptr++ = offc;
705 					len3 = strlen(*cv) + 1;
706 					(void) strlcpy(dptr, *cv++, len3);
707 					offc += len3;
708 					dptr += len3;
709 				}
710 			}
711 			if (pptr->groups_argc == 0) {
712 				pptr->groups_offv = (nssuint_t)0;
713 			} else {
714 				pptr->groups_offv = offv;
715 				cv = ing->groups.argv;
716 				i = pptr->groups_argc;
717 				offv += sizeof (nssuint_t) * i;
718 				for (; --i >= 0; ) {
719 					*uptr++ = offc;
720 					len3 = strlen(*cv) + 1;
721 					(void) strlcpy(dptr, *cv++, len3);
722 					offc += len3;
723 					dptr += len3;
724 				}
725 			}
726 			break;
727 		case 'T':
728 			sng = (struct nss_setnetgrent_args *)arg;
729 			if (sng->netgroup == NULL)
730 				return (NSS_NOTFOUND);
731 			len = strlen(sng->netgroup) + 1;
732 			if (len >= length)
733 				return (NSS_ERROR);
734 			(void) strlcpy(buffer, sng->netgroup, len);
735 			*rlen = len;
736 			break;
737 		default:
738 			return (NSS_ERROR);
739 		}
740 	}
741 	return (NSS_SUCCESS);
742 }
743 
744 nss_status_t
745 nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
746     const char *dbname, int dbop, size_t *rlen)
747 {
748 	int		index;
749 
750 	if (buffer == NULL || length == 0 || arg == NULL ||
751 	    dbname == NULL || rlen == NULL)
752 		return (NSS_ERROR);
753 
754 	/*
755 	 * If this is not one of the well known getXbyYs
756 	 * (IE _printers special processing etc.) use a
757 	 * local (non-nscd) getXbyY lookup.
758 	 */
759 	if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
760 		return (NSS_TRYLOCAL);
761 
762 	return (nss_pack_key2str(buffer, length, arg, dbname,
763 	    dbop, rlen, getXbyY_to_dbop[index].tostr));
764 }
765 
766 void
767 nss_packed_set_status(void *buffer, size_t length __unused, nss_status_t status,
768     nss_XbyY_args_t *arg)
769 {
770 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
771 	nss_dbd_t	*pdbd;
772 	char		*dbn;
773 
774 	/* sidestep odd cases */
775 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
776 	dbn = (char *)pdbd + pdbd->o_name;
777 	if (pbuf->nss_dbop == NSS_DBOP_GROUP_BYMEMBER) {
778 		if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) {
779 			struct nss_groupsbymem *in =
780 			    (struct nss_groupsbymem *)arg;
781 
782 			if (in->numgids >= 0) {
783 				pbuf->p_status = NSS_SUCCESS;
784 				pbuf->data_len = in->numgids *
785 				    sizeof (gid_t);
786 				pbuf->p_herrno = 0;
787 			} else {
788 				pbuf->p_status = status;
789 				pbuf->p_errno = errno;
790 				pbuf->data_len = 0;
791 				pbuf->p_herrno = (uint32_t)arg->h_errno;
792 			}
793 			return;
794 		}
795 	}
796 	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN) {
797 		if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
798 			struct nss_innetgr_args *in =
799 			    (struct nss_innetgr_args *)arg;
800 
801 			/* tell nss_unpack() operation is successful */
802 			pbuf->data_len = 1;
803 
804 			if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
805 				pbuf->p_status = status;
806 				pbuf->p_errno = errno;
807 				return;
808 			}
809 
810 			if (in->status == NSS_NETGR_FOUND) {
811 				pbuf->p_status = NSS_SUCCESS;
812 			} else {
813 				pbuf->p_status = NSS_NOTFOUND;
814 				pbuf->p_errno = errno;
815 			}
816 			return;
817 		}
818 	}
819 
820 	/* process normal cases */
821 	if ((pbuf->p_status = status) != NSS_SUCCESS) {
822 		if (arg->erange == 1)
823 			pbuf->p_errno = ERANGE;
824 		else
825 			pbuf->p_errno = errno;
826 	} else
827 		pbuf->p_errno = 0;
828 	if (arg != NULL) {
829 		pbuf->p_herrno = (uint32_t)arg->h_errno;
830 		pbuf->data_len = (nssuint_t)arg->returnlen;
831 	} else {
832 		pbuf->p_herrno = 0;
833 		pbuf->data_len = 0;
834 	}
835 }
836 
837 /*
838  * nss_upack_key2arg
839  * Private string to key unpacking function for getXbyY routines
840  * This routine performs a scanf/printf like parse over the packed
841  * string, to uppack and re-assemble the key in the args structure.
842  *
843  * buffer - Start of the key buffer location [in packed buffer]
844  * length - Length of key buffer component
845  * Key offsets are relative to start of key buffer location.
846  *
847  * Unpack fields		Key
848  *   key.name			n
849  *   key.number			N
850  *   key.uid			u
851  *   key.gid			g
852  *   key.hostaddr		h
853  *   key.ipnode			i
854  *   key.projid			p
855  *   key.serv(name)		s
856  *   key.serv(port)		S
857  *   key.ether			e
858  *   key.pkey			k
859  *   key.netaddr		a
860  *   key.attrp			A
861  *   groupsbymember		I
862  *   innetgr_args		t
863  *   setnetgr_args		T
864  * Assumes arguments are all valid
865  */
866 
867 static nss_status_t
868 nss_upack_key2arg(void *buffer, size_t length __unused, char **dbname __unused,
869     int *dbop __unused, 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 			(void) 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 static int
1152 str2packent(
1153     const char *instr,
1154     int lenstr,
1155     void *ent __unused,		/* really (char *) */
1156     char *buffer,
1157     int buflen)
1158 {
1159 	if (buflen <= lenstr) {		/* not enough buffer */
1160 		return (NSS_STR_PARSE_ERANGE);
1161 	}
1162 	(void) memmove(buffer, instr, lenstr);
1163 	buffer[lenstr] = '\0';
1164 
1165 	return (NSS_STR_PARSE_SUCCESS);
1166 }
1167 
1168 /*
1169  * Initialize db_root, initf, dbop and arg from a packed buffer
1170  */
1171 
1172 nss_status_t
1173 nss_packed_arg_init(void *buffer, size_t length,
1174     nss_db_root_t *db_root __unused,
1175     nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg)
1176 {
1177 	nss_pheader_t		*pbuf = (nss_pheader_t *)buffer;
1178 	nss_str2ent_t		s2e = str2packent;
1179 	nss_str2ent_t		real_s2e = NULL;
1180 	nss_dbd_t		*pdbd;
1181 	nssuint_t		off, dbdsize;
1182 	char			*dbname, *bptr;
1183 	size_t			len;
1184 	int			index;
1185 
1186 	if (buffer == NULL || length == 0 ||
1187 	    dbop == NULL || arg == NULL)
1188 		return (NSS_ERROR);
1189 
1190 	/* init dbop */
1191 	*dbop = pbuf->nss_dbop;
1192 	off = pbuf->dbd_off;
1193 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
1194 	dbdsize = pbuf->key_off - pbuf->dbd_off;
1195 	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
1196 	    pdbd->o_default_config >= dbdsize)
1197 		return (NSS_ERROR);
1198 	dbname = (char *)buffer + off + pdbd->o_name;
1199 	if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0)
1200 		return (NSS_ERROR);
1201 
1202 	/* db_root is initialized by nscd's based on door info */
1203 	/* do nothing here */
1204 
1205 	/* init key information - (and get dbname dbop etc...) */
1206 	if (nss_upack_key2arg(buffer, length, &dbname,
1207 	    dbop, arg, index) != NSS_SUCCESS)
1208 		return (NSS_ERROR);
1209 
1210 	/* possible audituser init */
1211 	if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
1212 		arg->h_errno = (int)pbuf->p_herrno;
1213 
1214 	bptr = (char *)buffer + pbuf->data_off;
1215 	len = (size_t)pbuf->data_len;
1216 
1217 	/* sidestep odd arg cases */
1218 	if (*dbop == NSS_DBOP_GROUP_BYMEMBER &&
1219 	    strcmp(dbname, NSS_DBNAM_GROUP) == 0) {
1220 		/* get initf  and str2ent functions */
1221 		if (nss_pinit_funcs(index, initf, &real_s2e) != NSS_SUCCESS)
1222 			return (NSS_ERROR);
1223 		((struct nss_groupsbymem *)arg)->str2ent = real_s2e;
1224 		((struct nss_groupsbymem *)arg)->process_cstr = process_cstr;
1225 		return (NSS_SUCCESS);
1226 	}
1227 	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
1228 	    strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
1229 		return (NSS_SUCCESS);
1230 	}
1231 
1232 	/* get initf  and str2ent functions */
1233 	if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
1234 		return (NSS_ERROR);
1235 
1236 	/* init normal arg cases */
1237 	NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1238 	arg->h_errno = 0;
1239 
1240 	return (NSS_SUCCESS);
1241 }
1242 
1243 /*
1244  * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
1245  */
1246 
1247 nss_status_t
1248 nss_packed_context_init(void *buffer, size_t length __unused,
1249     nss_db_root_t *db_root __unused,
1250     nss_db_initf_t *initf __unused, nss_getent_t **contextp __unused,
1251     nss_XbyY_args_t *arg)
1252 {
1253 	nss_pheader_t	*pbuf = (nss_pheader_t *)buffer;
1254 	nss_str2ent_t	s2e = str2packent;
1255 	char		*bptr;
1256 	size_t		len;
1257 
1258 	/* init arg */
1259 	if (arg != NULL) {
1260 		bptr = (char *)buffer + pbuf->data_off;
1261 		len = (size_t)pbuf->data_len;
1262 		NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1263 	}
1264 
1265 	return (NSS_SUCCESS);
1266 }
1267