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
59nss_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
76void
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
87void
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 */
133char **
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
184extern 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
192typedef 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
245static int getXbyYdbopHASH[DBOP_PRIME_HASH] = { 0 };
246static mutex_t getXbydbop_hash_lock = DEFAULTMUTEX;
247static 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 */
253static 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
297static int
298nss_dbop_search(const char *name, uint32_t dbop)
299{
300	getXbyY_to_dbop_t *hptr;
301	int count = (sizeof (getXbyY_to_dbop) / sizeof (getXbyY_to_dbop_t));
302	uint32_t hval, g;
303	const char *cp;
304	int i, idx;
305	static const uint32_t hbits_tst = 0xf0000000;
306
307	/* Uses a table size is known to have no collisions */
308	if (getXbyYdbop_hashed == 0) {
309		lmutex_lock(&getXbydbop_hash_lock);
310		if (getXbyYdbop_hashed == 0) {
311			for (i = 0; i < count; i++) {
312				cp = getXbyY_to_dbop[i].name;
313				hval = 0;
314				while (*cp) {
315					hval = (hval << 4) + *cp++;
316					if ((g = (hval & hbits_tst)) != 0)
317						hval ^= g >> 24;
318					hval &= ~g;
319				}
320				hval += getXbyY_to_dbop[i].dbop;
321				hval %= DBOP_PRIME_HASH;
322				if (getXbyYdbopHASH[hval] != 0) {
323					/* hash table collision-see above */
324					lmutex_unlock(&getXbydbop_hash_lock);
325					return (-1);
326				}
327				getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG;
328			}
329			membar_producer();
330			getXbyYdbop_hashed = 1;
331		}
332		lmutex_unlock(&getXbydbop_hash_lock);
333	}
334	membar_consumer();
335	cp = name;
336	hval = 0;
337	while (*cp) {
338		hval = (hval << 4) + *cp++;
339		if ((g = (hval & hbits_tst)) != 0)
340			hval ^= g >> 24;
341		hval &= ~g;
342	}
343	hval += dbop;
344	hval %= DBOP_PRIME_HASH;
345	idx = getXbyYdbopHASH[hval];
346	if ((idx & DBOP_HASH_TAG) != DBOP_HASH_TAG)
347		return (-1);
348	idx &= ~DBOP_HASH_TAG;
349	if (idx >= count)
350		return (-1);
351	hptr = &getXbyY_to_dbop[idx];
352	if (hptr->dbop != dbop || strcmp(name, hptr->name) != 0)
353		return (-1);
354	return (idx);
355}
356
357/*
358 * nss_pack_key2str
359 * Private key to string packing function for getXbyY routines
360 * This routine performs a printf like parse over the argument
361 * key, given a string of items to pack and assembles the key in
362 * the packed structure.  This routine is called (currently) by
363 * nss_default_key2str, but will be used by other external
364 * APIs in the future.
365 *
366 * buffer - Start of the key buffer location [in packed buffer]
367 * length - Length of key buffer component
368 * Key offsets are relative to start of key buffer location.
369 *
370 * Pack fields			Key
371 *   key.name			n
372 *   key.number			N
373 *   key.uid			u
374 *   key.gid			g
375 *   key.hostaddr		h
376 *   key.ipnode			i
377 *   key.projid			p
378 *   key.serv(name)		s
379 *   key.serv(port)		S
380 *   key.ether			e
381 *   key.pkey			k
382 *   key.netaddr		a
383 *   key.attrp			A
384 *   groupsbymember		I
385 *   innetgr_args		t
386 *   setnetgr_args		T
387 */
388
389/*ARGSUSED*/
390static nss_status_t
391nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
392	const char *dbname, int dbop, size_t *rlen, const char *typestr)
393{
394	int				i, j;
395	size_t				len, len2, len3, len4, len5, slop;
396	nssuint_t 			*uptr, offv, offc;
397	struct nss_setnetgrent_args	*sng;
398	struct nss_innetgr_args		*ing;
399	struct nss_groupsbymem		*gbm;
400	char				**cv, *dptr;
401	nss_pnetgr_t			*pptr;
402	_priv_execattr			*pe;
403
404	if (buffer == NULL || length == 0 || arg == NULL ||
405	    dbname == NULL || rlen == NULL || typestr == NULL)
406		return (NSS_ERROR);
407
408	while (typestr && *typestr) {
409		switch (*typestr++) {
410		case 'n':
411			if (arg->key.name == NULL)
412				return (NSS_NOTFOUND);
413			len = strlen(arg->key.name) + 1;
414			if (len >= length)
415				return (NSS_ERROR);
416			(void) strlcpy(buffer, arg->key.name, len);
417			*rlen = len;
418			break;
419		case 'N':
420			len = sizeof (nssuint_t);
421			if (len >= length)
422				return (NSS_ERROR);
423			*(nssuint_t *)buffer = (nssuint_t)arg->key.number;
424			*rlen = len;
425			break;
426		case 'u':
427			len = sizeof (nssuint_t);
428			if (len >= length)
429				return (NSS_ERROR);
430			*(nssuint_t *)buffer = (nssuint_t)arg->key.uid;
431			*rlen = len;
432			break;
433		case 'g':
434			len = sizeof (nssuint_t);
435			if (len >= length)
436				return (NSS_ERROR);
437			*(nssuint_t *)buffer = (nssuint_t)arg->key.gid;
438			*rlen = len;
439			break;
440		case 'h':
441			if (arg->key.hostaddr.addr == NULL)
442				return (-1);
443			len = arg->key.hostaddr.len;
444			len = ROUND_UP(len, sizeof (nssuint_t));
445			len2 = (sizeof (nssuint_t) * 2) + len;
446			if (len2 >= length)
447				return (NSS_ERROR);
448			*(nssuint_t *)buffer =
449			    (nssuint_t)arg->key.hostaddr.len;
450			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
451			*(nssuint_t *)buffer =
452			    (nssuint_t)arg->key.hostaddr.type;
453			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
454			(void) memcpy(buffer, arg->key.hostaddr.addr,
455			    arg->key.hostaddr.len);
456			*rlen = len2;
457			break;
458		case 'i':
459			if (arg->key.ipnode.name == NULL)
460				return (NSS_NOTFOUND);
461			len = strlen(arg->key.ipnode.name) + 1;
462			len = ROUND_UP(len, sizeof (nssuint_t));
463			len2 = (sizeof (nssuint_t) * 2) + len;
464			if (len2 >= length)
465				return (NSS_ERROR);
466			*(nssuint_t *)buffer =
467			    (nssuint_t)arg->key.ipnode.af_family;
468			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
469			*(nssuint_t *)buffer =
470			    (nssuint_t)arg->key.ipnode.flags;
471			buffer = (void *)((char *)buffer + sizeof (nssuint_t));
472			(void) strlcpy(buffer, arg->key.ipnode.name, len);
473			*rlen = len2;
474			break;
475		case 'p':
476			len = sizeof (nssuint_t);
477			if (len >= length)
478				return (NSS_ERROR);
479			*(nssuint_t *)buffer = (nssuint_t)arg->key.projid;
480			*rlen = len;
481			break;
482		case 's':
483			if (arg->key.serv.serv.name == NULL)
484				return (NSS_NOTFOUND);
485			len = strlen(arg->key.serv.serv.name) + 1;
486			len2 = 1;
487			if (arg->key.serv.proto != NULL)
488				len2 += strlen(arg->key.serv.proto);
489			len3 = len + len2;
490			len3 = ROUND_UP(len3, sizeof (nssuint_t));
491			if (len3 >= length)
492				return (NSS_ERROR);
493			(void) strlcpy(buffer, arg->key.serv.serv.name, len);
494			buffer = (void *)((char *)buffer + len);
495			if (len2 > 1)
496				(void) strlcpy(buffer, arg->key.serv.proto,
497				    len2);
498			else
499				*(char *)buffer = '\0';
500			*rlen = len3;
501			break;
502		case 'S':
503			len2 = 0;
504			if (arg->key.serv.proto != NULL)
505				len2 = strlen(arg->key.serv.proto) + 1;
506			len = sizeof (nssuint_t) + len2;
507			if (len >= length)
508				return (NSS_ERROR);
509			uptr = (nssuint_t *)buffer;
510			*uptr++ = (nssuint_t)arg->key.serv.serv.port;
511			if (len2) {
512				(void) strlcpy((char *)uptr,
513				    arg->key.serv.proto, len2);
514			}
515			*rlen = len;
516			break;
517		case 'e':
518			if (arg->key.ether == NULL)
519				return (NSS_NOTFOUND);
520			len = sizeof (struct ether_addr);
521			len = ROUND_UP(len, sizeof (nssuint_t));
522			if (len >= length)
523				return (NSS_ERROR);
524			*(struct ether_addr *)buffer =
525			    *(struct ether_addr *)arg->key.ether;
526			*rlen = len;
527			break;
528		case 'k':
529			if (arg->key.pkey.name == NULL ||
530			    arg->key.pkey.keytype == NULL)
531				return (NSS_NOTFOUND);
532			len = strlen(arg->key.pkey.name) + 1;
533			len2 = strlen(arg->key.pkey.keytype) + 1;
534			len3 = len + len2;
535			len3 = ROUND_UP(len3, sizeof (nssuint_t));
536			if (len3 >= length)
537				return (NSS_ERROR);
538			(void) strlcpy(buffer, arg->key.pkey.name, len);
539			buffer = (void *)((char *)buffer + len);
540			(void) strlcpy(buffer, arg->key.pkey.keytype, len2);
541			*rlen = len3;
542			break;
543		case 'a':
544			uptr = (nssuint_t *)buffer;
545			len = sizeof (nssuint_t) * 2;
546			if (len >= length)
547				return (NSS_ERROR);
548			*uptr++ = (nssuint_t)arg->key.netaddr.net;
549			*uptr++ = (nssuint_t)arg->key.netaddr.type;
550			*rlen = len;
551			break;
552		case 'A':
553			pe = (_priv_execattr *)(arg->key.attrp);
554			if (pe == NULL)
555				return (NSS_NOTFOUND);
556			/* for search flag */
557			len = sizeof (nssuint_t);
558			/* for sizeof (_priv_execattr) static buffer */
559			/* Plus lots of slop just in case... */
560			slop = sizeof (nssuint_t) * 16;
561			len += slop;
562
563			len2 = len3 = len4 = len5 = 1;
564			if (pe->name != NULL)
565				len2 = strlen(pe->name) + 1;
566			if (pe->type != NULL)
567				len3 = strlen(pe->type) + 1;
568			if (pe->id != NULL)
569				len4 = strlen(pe->id) + 1;
570			if (pe->policy != NULL)
571				len5 = strlen(pe->policy) + 1;
572			/* head_exec, prev_exec - are client side only... */
573			len += len2 + len3 + len4 + len5;
574			len = ROUND_UP(len, sizeof (nssuint_t));
575			if (len >= length)
576				return (NSS_ERROR);
577			(void) memset((void *)buffer, 0, slop);
578			uptr = (nssuint_t *)((void *)((char *)buffer + slop));
579			*uptr++ = (nssuint_t)pe->search_flag;
580			dptr = (char *)uptr;
581			if (len2 == 1)
582				*dptr++ = '\0';
583			else {
584				(void) strlcpy(dptr, pe->name, len2);
585				dptr += len2;
586			}
587			if (len3 == 1)
588				*dptr++ = '\0';
589			else {
590				(void) strlcpy(dptr, pe->type, len3);
591				dptr += len3;
592			}
593			if (len4 == 1)
594				*dptr++ = '\0';
595			else {
596				(void) strlcpy(dptr, pe->id, len4);
597				dptr += len4;
598			}
599			if (len5 == 1)
600				*dptr++ = '\0';
601			else
602				(void) strlcpy(dptr, pe->policy, len5);
603			*rlen = len;
604			break;
605		case 'I':
606			gbm = (struct nss_groupsbymem *)arg;
607			if (gbm->username == NULL)
608				return (NSS_NOTFOUND);
609			len = strlen(gbm->username) + 1;
610			len2 = sizeof (nssuint_t) * 4;
611			len2 += ROUND_UP(len, sizeof (nssuint_t));
612			if (len2 >= length)
613				return (NSS_ERROR);
614			uptr = (nssuint_t *)buffer;
615			*uptr++ = (nssuint_t)gbm->force_slow_way;
616			*uptr++ = (nssuint_t)gbm->maxgids;
617			*uptr++ = (nssuint_t)gbm->numgids;
618			if (gbm->numgids == 1) {
619				*uptr++ = (nssuint_t)gbm->gid_array[0];
620			} else {
621				*uptr++ = (nssuint_t)0;
622			}
623			(void) strlcpy((void *)uptr, gbm->username, len);
624			*rlen = len2;
625			break;
626		case 't':
627			pptr = (nss_pnetgr_t *)buffer;
628			ing = (struct nss_innetgr_args *)arg;
629			len = sizeof (nss_pnetgr_t);
630			len2 = ing->arg[NSS_NETGR_MACHINE].argc +
631			    ing->arg[NSS_NETGR_USER].argc +
632			    ing->arg[NSS_NETGR_DOMAIN].argc +
633			    ing->groups.argc;
634			len2 *= sizeof (nssuint_t);
635			len3 = 0;
636			for (j = 0; j < NSS_NETGR_N; j++) {
637				cv = ing->arg[j].argv;
638				for (i = ing->arg[j].argc; --i >= 0; ) {
639					if (*cv)
640						len3 += strlen(*cv++) + 1;
641				}
642			}
643			cv = ing->groups.argv;
644			for (i = ing->groups.argc; --i >= 0; ) {
645				if (*cv)
646					len3 += strlen(*cv++) + 1;
647			}
648			len3 = ROUND_UP(len3, sizeof (nssuint_t));
649			/*
650			 * Double argv space. Reason:
651			 *    First 1/2 offsets
652			 *    Second 1/2 for client side pointer arrays
653			 *    resolves malloc/free issues with unpacked argvs
654			 */
655			if ((len + (len2 << 1) + len3) >= length)
656				return (NSS_ERROR);
657			*rlen = len + (len2 << 1) + len3;
658
659			pptr->machine_argc = ing->arg[NSS_NETGR_MACHINE].argc;
660			pptr->user_argc = ing->arg[NSS_NETGR_USER].argc;
661			pptr->domain_argc = ing->arg[NSS_NETGR_DOMAIN].argc;
662			pptr->groups_argc = ing->groups.argc;
663			offv = len;
664			uptr = (nssuint_t *)((void *)((char *)buffer + offv));
665			offc = len + (len2 << 1);
666			dptr = (char *)buffer + offc;
667			if (pptr->machine_argc == 0) {
668				pptr->machine_offv = (nssuint_t)0;
669			} else {
670				pptr->machine_offv = offv;
671				cv = ing->arg[NSS_NETGR_MACHINE].argv;
672				i = pptr->machine_argc;
673				offv += sizeof (nssuint_t) * i;
674				for (; --i >= 0; ) {
675					*uptr++ = offc;
676					len3 = strlen(*cv) + 1;
677					(void) strlcpy(dptr, *cv++, len3);
678					offc += len3;
679					dptr += len3;
680				}
681			}
682			if (pptr->user_argc == 0) {
683				pptr->user_offv = (nssuint_t)0;
684			} else {
685				pptr->user_offv = offv;
686				cv = ing->arg[NSS_NETGR_USER].argv;
687				i = pptr->user_argc;
688				offv += sizeof (nssuint_t) * i;
689				for (; --i >= 0; ) {
690					*uptr++ = offc;
691					len3 = strlen(*cv) + 1;
692					(void) strlcpy(dptr, *cv++, len3);
693					offc += len3;
694					dptr += len3;
695				}
696			}
697			if (pptr->domain_argc == 0) {
698				pptr->domain_offv = (nssuint_t)0;
699			} else {
700				pptr->domain_offv = offv;
701				cv = ing->arg[NSS_NETGR_DOMAIN].argv;
702				i = pptr->domain_argc;
703				offv += sizeof (nssuint_t) * i;
704				for (; --i >= 0; ) {
705					*uptr++ = offc;
706					len3 = strlen(*cv) + 1;
707					(void) strlcpy(dptr, *cv++, len3);
708					offc += len3;
709					dptr += len3;
710				}
711			}
712			if (pptr->groups_argc == 0) {
713				pptr->groups_offv = (nssuint_t)0;
714			} else {
715				pptr->groups_offv = offv;
716				cv = ing->groups.argv;
717				i = pptr->groups_argc;
718				offv += sizeof (nssuint_t) * i;
719				for (; --i >= 0; ) {
720					*uptr++ = offc;
721					len3 = strlen(*cv) + 1;
722					(void) strlcpy(dptr, *cv++, len3);
723					offc += len3;
724					dptr += len3;
725				}
726			}
727			break;
728		case 'T':
729			sng = (struct nss_setnetgrent_args *)arg;
730			if (sng->netgroup == NULL)
731				return (NSS_NOTFOUND);
732			len = strlen(sng->netgroup) + 1;
733			if (len >= length)
734				return (NSS_ERROR);
735			(void) strlcpy(buffer, sng->netgroup, len);
736			*rlen = len;
737			break;
738		default:
739			return (NSS_ERROR);
740		}
741	}
742	return (NSS_SUCCESS);
743}
744
745nss_status_t
746nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
747	const char *dbname, int dbop, size_t *rlen)
748{
749	int		index;
750
751	if (buffer == NULL || length == 0 || arg == NULL ||
752	    dbname == NULL || rlen == NULL)
753		return (NSS_ERROR);
754
755	/*
756	 * If this is not one of the well known getXbyYs
757	 * (IE _printers special processing etc.) use a
758	 * local (non-nscd) getXbyY lookup.
759	 */
760	if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
761		return (NSS_TRYLOCAL);
762
763	return (nss_pack_key2str(buffer, length, arg, dbname,
764	    dbop, rlen, getXbyY_to_dbop[index].tostr));
765}
766
767/*ARGSUSED*/
768void
769nss_packed_set_status(void *buffer, size_t length, nss_status_t status,
770		nss_XbyY_args_t *arg)
771{
772	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
773	nss_dbd_t	*pdbd;
774	char		*dbn;
775
776	/* sidestep odd cases */
777	pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
778	dbn = (char *)pdbd + pdbd->o_name;
779	if (pbuf->nss_dbop == NSS_DBOP_GROUP_BYMEMBER) {
780		if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) {
781			struct nss_groupsbymem *in =
782			    (struct nss_groupsbymem *)arg;
783
784			if (in->numgids >= 0) {
785				pbuf->p_status = NSS_SUCCESS;
786				pbuf->data_len = in->numgids *
787				    sizeof (gid_t);
788				pbuf->p_herrno = 0;
789			} else {
790				pbuf->p_status = status;
791				pbuf->p_errno = errno;
792				pbuf->data_len = 0;
793				pbuf->p_herrno = (uint32_t)arg->h_errno;
794			}
795			return;
796		}
797	}
798	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN) {
799		if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
800			struct nss_innetgr_args *in =
801			    (struct nss_innetgr_args *)arg;
802
803			/* tell nss_unpack() operation is successful */
804			pbuf->data_len = 1;
805
806			if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
807				pbuf->p_status = status;
808				pbuf->p_errno = errno;
809				return;
810			}
811
812			if (in->status == NSS_NETGR_FOUND) {
813				pbuf->p_status = NSS_SUCCESS;
814			} else {
815				pbuf->p_status = NSS_NOTFOUND;
816				pbuf->p_errno = errno;
817			}
818			return;
819		}
820	}
821
822	/* process normal cases */
823	if ((pbuf->p_status = status) != NSS_SUCCESS) {
824		if (arg->erange == 1)
825			pbuf->p_errno = ERANGE;
826		else
827			pbuf->p_errno = errno;
828	} else
829		pbuf->p_errno = 0;
830	if (arg != NULL) {
831		pbuf->p_herrno = (uint32_t)arg->h_errno;
832		pbuf->data_len = (nssuint_t)arg->returnlen;
833	} else {
834		pbuf->p_herrno = 0;
835		pbuf->data_len = 0;
836	}
837}
838
839/*
840 * nss_upack_key2arg
841 * Private string to key unpacking function for getXbyY routines
842 * This routine performs a scanf/printf like parse over the packed
843 * string, to uppack and re-assemble the key in the args structure.
844 *
845 * buffer - Start of the key buffer location [in packed buffer]
846 * length - Length of key buffer component
847 * Key offsets are relative to start of key buffer location.
848 *
849 * Unpack fields		Key
850 *   key.name			n
851 *   key.number			N
852 *   key.uid			u
853 *   key.gid			g
854 *   key.hostaddr		h
855 *   key.ipnode			i
856 *   key.projid			p
857 *   key.serv(name)		s
858 *   key.serv(port)		S
859 *   key.ether			e
860 *   key.pkey			k
861 *   key.netaddr		a
862 *   key.attrp			A
863 *   groupsbymember		I
864 *   innetgr_args		t
865 *   setnetgr_args		T
866 * Assumes arguments are all valid
867 */
868
869/*ARGSUSED*/
870static nss_status_t
871nss_upack_key2arg(void *buffer, size_t length, char **dbname,
872		int *dbop, nss_XbyY_args_t *arg, int index)
873{
874	nss_pheader_t 			*pbuf = (nss_pheader_t *)buffer;
875	const char			*strtype = NULL;
876	nssuint_t 			off, *uptr, keysize;
877	size_t				len, slop;
878	int				i, j;
879	char				**cv, *bptr;
880	struct nss_setnetgrent_args	*sng;
881	struct nss_innetgr_args		*ing;
882	struct nss_groupsbymem		*gbm;
883	nss_pnetgr_t			*pptr;
884	_priv_execattr			*pe;
885
886	/* keysize is length of the key area */
887	keysize = pbuf->data_off - pbuf->key_off;
888
889	off = pbuf->key_off;
890	bptr = (char *)buffer + off;
891	uptr = (nssuint_t *)((void *)bptr);
892	strtype = getXbyY_to_dbop[index].tostr;
893	if (strtype == NULL)
894		return (NSS_ERROR);
895	while (*strtype) {
896		switch (*strtype++) {
897		case 'n':
898			arg->key.name = (const char *)bptr;
899			break;
900		case 'N':
901			arg->key.number = (int)(*uptr);
902			break;
903		case 'u':
904			arg->key.uid = (uid_t)(*uptr);
905			break;
906		case 'g':
907			arg->key.gid = (gid_t)(*uptr);
908			break;
909		case 'h':
910			arg->key.hostaddr.len = (int)(*uptr++);
911			arg->key.hostaddr.type = (int)(*uptr++);
912			arg->key.hostaddr.addr = (const char *)uptr;
913			break;
914		case 'i':
915			arg->key.ipnode.af_family = (int)(*uptr++);
916			arg->key.ipnode.flags = (int)(*uptr++);
917			arg->key.ipnode.name = (const char *)uptr;
918			break;
919		case 'p':
920			arg->key.projid = (projid_t)(*uptr);
921			break;
922		case 's':
923			arg->key.serv.serv.name = (const char *)bptr;
924			len = strlen(arg->key.serv.serv.name) + 1;
925			bptr += len;
926			if (*(const char *)bptr == '\0')
927				arg->key.serv.proto = NULL;
928			else
929				arg->key.serv.proto = (const char *)bptr;
930			break;
931		case 'S':
932			arg->key.serv.serv.port = (int)(*uptr++);
933			if (pbuf->key_len == sizeof (nssuint_t)) {
934				arg->key.serv.proto = NULL;
935			} else {
936				bptr += sizeof (nssuint_t);
937				arg->key.serv.proto = (const char *)bptr;
938			}
939			break;
940		case 'e':
941			arg->key.ether = bptr;
942			break;
943		case 'k':
944			arg->key.pkey.name = (const char *)bptr;
945			len = strlen(arg->key.pkey.name) + 1;
946			bptr += len;
947			arg->key.pkey.keytype = (const char *)bptr;
948			break;
949		case 'a':
950			arg->key.netaddr.net = (uint32_t)(*uptr++);
951			arg->key.netaddr.type = (int)(*uptr++);
952			break;
953		case 'A':
954			pe = (_priv_execattr *)((void *)bptr);
955			/* use slop space as priv_execattr structure */
956			arg->key.attrp = (void *)pe;
957			/* skip over slop ... */
958			slop = sizeof (nssuint_t) * 16;
959			uptr = (nssuint_t *)((void *)((char *)bptr + slop));
960			pe->search_flag = (int)*uptr++;
961			bptr = (char *)uptr;
962			if (*bptr == '\0') {
963				pe->name = NULL;
964				bptr++;
965			} else {
966				pe->name = (char *)bptr;
967				bptr += strlen(pe->name) + 1;
968			}
969			if (*bptr == '\0') {
970				pe->type = NULL;
971				bptr++;
972			} else {
973				pe->type = (char *)bptr;
974				bptr += strlen(pe->type) + 1;
975			}
976			if (*bptr == '\0') {
977				pe->id = NULL;
978				bptr++;
979			} else {
980				pe->id = (char *)bptr;
981				bptr += strlen(pe->id) + 1;
982			}
983			if (*bptr == '\0') {
984				pe->policy = NULL;
985			} else {
986				pe->policy = (char *)bptr;
987			}
988			pe->head_exec = NULL;
989			pe->prev_exec = NULL;
990			break;
991		case 'I':
992			gbm = (struct nss_groupsbymem *)arg;
993			gbm->gid_array = (gid_t *)
994			    ((void *)((char *)pbuf + pbuf->data_off));
995			gbm->force_slow_way = (int)(*uptr++);
996			gbm->maxgids = (int)(*uptr++);
997			gbm->numgids = (int)(*uptr++);
998			if (gbm->numgids == 1) {
999				/* insert initial group into data area */
1000				gbm->gid_array[0] = (gid_t)(*uptr++);
1001			} else
1002				uptr++;
1003			gbm->username = (const char *)uptr;
1004			break;
1005		case 't':
1006			pptr = (nss_pnetgr_t *)((void *)bptr);
1007			ing = (struct nss_innetgr_args *)arg;
1008			ing->arg[NSS_NETGR_MACHINE].argc = pptr->machine_argc;
1009			ing->arg[NSS_NETGR_USER].argc = pptr->user_argc;
1010			ing->arg[NSS_NETGR_DOMAIN].argc = pptr->domain_argc;
1011			ing->groups.argc = pptr->groups_argc;
1012
1013			/*
1014			 * Start of argv pointer storage
1015			 */
1016			off = ing->arg[NSS_NETGR_MACHINE].argc +
1017			    ing->arg[NSS_NETGR_USER].argc +
1018			    ing->arg[NSS_NETGR_DOMAIN].argc +
1019			    ing->groups.argc;
1020			off *= sizeof (nssuint_t);
1021			off += sizeof (nss_pnetgr_t);
1022
1023			cv = (char **)((void *)(bptr + off));
1024			uptr = (nssuint_t *)
1025			    ((void *)(bptr + sizeof (nss_pnetgr_t)));
1026			for (j = 0; j < NSS_NETGR_N; j++) {
1027				ing->arg[j].argv = cv;
1028				for (i = 0; i < ing->arg[j].argc; i++) {
1029					if (*uptr >= keysize)
1030						return (NSS_ERROR);
1031					*cv++ = (bptr + *uptr++);
1032				}
1033			}
1034			ing->groups.argv = cv;
1035			for (i = 0; i < ing->groups.argc; i++) {
1036				if (*uptr >= keysize)
1037					return (NSS_ERROR);
1038				*cv++ = (bptr + *uptr++);
1039			}
1040			break;
1041		case 'T':
1042			sng = (struct nss_setnetgrent_args *)arg;
1043			sng->netgroup = (const char *)bptr;
1044			sng->iterator = 0;
1045			break;
1046
1047		default:
1048			return (NSS_ERROR);
1049		}
1050	}
1051	return (NSS_SUCCESS);
1052}
1053
1054static nss_status_t
1055nss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e)
1056{
1057	const char	*name;
1058	void		*htmp = NULL;
1059	void		*sym;
1060	static void	*handle = NULL;
1061	static mutex_t	handle_lock = DEFAULTMUTEX;
1062	static mutex_t	initf_lock = DEFAULTMUTEX;
1063	static mutex_t	s2e_lock = DEFAULTMUTEX;
1064
1065	if (handle == NULL) {
1066		htmp = dlopen((const char *)0, RTLD_LAZY);
1067
1068		lmutex_lock(&handle_lock);
1069		if (handle == NULL) {
1070			if (htmp == NULL) {
1071				lmutex_unlock(&handle_lock);
1072				return (NSS_ERROR);
1073			} else {
1074				membar_producer();
1075				handle = htmp;
1076				htmp = NULL;
1077			}
1078		}
1079		lmutex_unlock(&handle_lock);
1080		if (htmp)
1081			(void) dlclose(htmp);
1082	}
1083	membar_consumer();
1084
1085	if (initf) {
1086		if (getXbyY_to_dbop[index].initfnp == NULL) {
1087			name = getXbyY_to_dbop[index].initfn;
1088			if ((sym = dlsym(handle, name)) == NULL)
1089				return (NSS_ERROR);
1090			lmutex_lock(&initf_lock);
1091			if (getXbyY_to_dbop[index].initfnp == NULL)
1092				getXbyY_to_dbop[index].initfnp = sym;
1093			membar_producer();
1094			lmutex_unlock(&initf_lock);
1095		}
1096		membar_consumer();
1097		*initf = (nss_db_initf_t)getXbyY_to_dbop[index].initfnp;
1098	}
1099	if (s2e) {
1100		if (getXbyY_to_dbop[index].strfnp == NULL) {
1101			name = getXbyY_to_dbop[index].strfn;
1102			if ((sym = dlsym(handle, name)) == NULL)
1103				return (NSS_ERROR);
1104			lmutex_lock(&s2e_lock);
1105			if (getXbyY_to_dbop[index].strfnp == NULL)
1106				getXbyY_to_dbop[index].strfnp = sym;
1107			membar_producer();
1108			lmutex_unlock(&s2e_lock);
1109		}
1110		membar_consumer();
1111		*s2e = (nss_str2ent_t)getXbyY_to_dbop[index].strfnp;
1112	}
1113
1114	return (NSS_SUCCESS);
1115}
1116
1117nss_status_t
1118nss_packed_getkey(void *buffer, size_t length, char **dbname,
1119		int *dbop, nss_XbyY_args_t *arg)
1120{
1121	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
1122	nss_dbd_t	*pdbd;
1123	nssuint_t 	off, dbdsize;
1124	int		index;
1125
1126	if (buffer == NULL || length == 0 || dbop == NULL ||
1127	    arg == NULL || dbname == NULL)
1128		return (NSS_ERROR);
1129
1130	*dbop = pbuf->nss_dbop;
1131	off = pbuf->dbd_off;
1132	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
1133	dbdsize = pbuf->key_off - pbuf->dbd_off;
1134	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
1135	    pdbd->o_default_config >= dbdsize)
1136		return (NSS_ERROR);
1137	*dbname = (char *)buffer + off + pdbd->o_name;
1138	if ((index = nss_dbop_search(*dbname, (uint32_t)*dbop)) < 0)
1139		return (NSS_ERROR);
1140	return (nss_upack_key2arg(buffer, length, dbname, dbop, arg, index));
1141}
1142
1143
1144/*
1145 * str2packent: Standard format interposed str2X function for normal APIs
1146 *
1147 * Return values: 0 = success, 1 = parse error, 2 = erange ...
1148 *
1149 * The structure pointer is ignored since this is a nscd side packed request.
1150 * The client side routine does all the real parsing; we just check limits and
1151 * store the entry in the buffer we were passed by the caller.
1152 */
1153
1154/*ARGSUSED*/
1155static int
1156str2packent(
1157    const char *instr,
1158    int lenstr,
1159    void *ent,		/* really (char *) */
1160    char *buffer,
1161    int buflen
1162)
1163{
1164	if (buflen <= lenstr) {		/* not enough buffer */
1165		return (NSS_STR_PARSE_ERANGE);
1166	}
1167	(void) memmove(buffer, instr, lenstr);
1168	buffer[lenstr] = '\0';
1169
1170	return (NSS_STR_PARSE_SUCCESS);
1171}
1172
1173/*
1174 * Initialize db_root, initf, dbop and arg from a packed buffer
1175 */
1176
1177/*ARGSUSED*/
1178nss_status_t
1179nss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
1180		nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg)
1181{
1182	nss_pheader_t 		*pbuf = (nss_pheader_t *)buffer;
1183	nss_str2ent_t		s2e = str2packent;
1184	nss_str2ent_t		real_s2e = NULL;
1185	nss_dbd_t		*pdbd;
1186	nssuint_t		off, dbdsize;
1187	char			*dbname, *bptr;
1188	size_t			len;
1189	int			index;
1190
1191	if (buffer == NULL || length == 0 ||
1192	    dbop == NULL || arg == NULL)
1193		return (NSS_ERROR);
1194
1195	/* init dbop */
1196	*dbop = pbuf->nss_dbop;
1197	off = pbuf->dbd_off;
1198	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
1199	dbdsize = pbuf->key_off - pbuf->dbd_off;
1200	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
1201	    pdbd->o_default_config >= dbdsize)
1202		return (NSS_ERROR);
1203	dbname = (char *)buffer + off + pdbd->o_name;
1204	if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0)
1205		return (NSS_ERROR);
1206
1207	/* db_root is initialized by nscd's based on door info */
1208	/* do nothing here */
1209
1210	/* init key information - (and get dbname dbop etc...) */
1211	if (nss_upack_key2arg(buffer, length, &dbname,
1212	    dbop, arg, index) != NSS_SUCCESS)
1213		return (NSS_ERROR);
1214
1215	/* possible audituser init */
1216	if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
1217		arg->h_errno = (int)pbuf->p_herrno;
1218
1219	bptr = (char *)buffer + pbuf->data_off;
1220	len = (size_t)pbuf->data_len;
1221
1222	/* sidestep odd arg cases */
1223	if (*dbop == NSS_DBOP_GROUP_BYMEMBER &&
1224	    strcmp(dbname, NSS_DBNAM_GROUP) == 0) {
1225		/* get initf  and str2ent functions */
1226		if (nss_pinit_funcs(index, initf, &real_s2e) != NSS_SUCCESS)
1227			return (NSS_ERROR);
1228		((struct nss_groupsbymem *)arg)->str2ent = real_s2e;
1229		((struct nss_groupsbymem *)arg)->process_cstr = process_cstr;
1230		return (NSS_SUCCESS);
1231	}
1232	if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
1233	    strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
1234		return (NSS_SUCCESS);
1235	}
1236
1237	/* get initf  and str2ent functions */
1238	if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
1239		return (NSS_ERROR);
1240
1241	/* init normal arg cases */
1242	NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1243	arg->h_errno = 0;
1244
1245	return (NSS_SUCCESS);
1246}
1247
1248/*
1249 * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
1250 */
1251
1252/*ARGSUSED*/
1253nss_status_t
1254nss_packed_context_init(void *buffer, size_t length, nss_db_root_t *db_root,
1255		nss_db_initf_t *initf, nss_getent_t **contextp,
1256		nss_XbyY_args_t *arg)
1257{
1258	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
1259	nss_str2ent_t	s2e = str2packent;
1260	char		*bptr;
1261	size_t		len;
1262
1263	/* init arg */
1264	if (arg != NULL) {
1265		bptr = (char *)buffer + pbuf->data_off;
1266		len = (size_t)pbuf->data_len;
1267		NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1268	}
1269
1270	return (NSS_SUCCESS);
1271}
1272