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