import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / nss_dbdefs.c
blobca5841487a1d3dfae85648c223690436bedb54ff
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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>
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.
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.
57 #define ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1))
59 nss_XbyY_buf_t *
60 _nss_XbyY_buf_alloc(int struct_size, int buffer_size)
62 nss_XbyY_buf_t *b;
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);
70 b->result = (void *)ALIGN(&b[1]);
71 b->buffer = (char *)(b->result) + struct_size;
72 b->buflen = buffer_size;
73 return (b);
76 void
77 _nss_XbyY_buf_free(nss_XbyY_buf_t *b)
79 if (b != 0) {
80 free(b);
84 /* === Comment: used by fget{gr,pw,sp}ent */
85 /* ==== Should do ye olde syslog()ing of suspiciously long lines */
87 void
88 _nss_XbyY_fgets(FILE *f, nss_XbyY_args_t *b)
90 char buf[LINE_MAX];
91 int len, parsestat;
93 if (fgets(buf, LINE_MAX, f) == 0) {
94 /* End of file */
95 b->returnval = 0;
96 b->erange = 0;
97 return;
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') {
108 b->returnval = 0;
109 b->erange = 1;
110 return;
112 /* case where the file is not terminated with a Newline */
113 len++;
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;
126 * parse the aliases string into the buffer and if successful return
127 * a char ** pointer to the beginning of the aliases.
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.
133 char **
134 _nss_netdb_aliases(const char *instr, int lenstr, char *buffer, int buflen)
135 /* "instr" is the beginning of the aliases string */
136 /* "buffer" has the return val for success */
137 /* "buflen" is the length of the buffer available for aliases */
140 * Build the alias-list in the start of the buffer, and copy
141 * the strings to the end of the buffer.
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;
150 for (;;) {
151 const char *str_start;
152 size_t str_len;
154 while (instr < instr_limit && isspace(*instr)) {
155 instr++;
157 if (instr >= instr_limit || *instr == '#') {
158 break;
160 str_start = instr;
161 while (instr < instr_limit && !isspace(*instr)) {
162 instr++;
165 ++nstrings;
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);
175 *aliasp++ = copyptr;
176 (void) memcpy(copyptr, str_start, str_len);
177 copyptr[str_len] = '\0';
179 *aliasp++ = 0;
180 return (alias_start);
184 extern nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
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.
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;
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) }
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) }
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) }
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) }
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) }
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) }
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.
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.
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.
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;
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().
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_GETXYDBOP(USERATTR, BYNAME, "userattr", "n"),
294 static int
295 nss_dbop_search(const char *name, uint32_t dbop)
297 getXbyY_to_dbop_t *hptr;
298 int count = (sizeof (getXbyY_to_dbop) / sizeof (getXbyY_to_dbop_t));
299 uint32_t hval, g;
300 const char *cp;
301 int i, idx;
302 static const uint32_t hbits_tst = 0xf0000000;
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 & hbits_tst)) != 0)
314 hval ^= g >> 24;
315 hval &= ~g;
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);
324 getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG;
326 membar_producer();
327 getXbyYdbop_hashed = 1;
329 lmutex_unlock(&getXbydbop_hash_lock);
331 membar_consumer();
332 cp = name;
333 hval = 0;
334 while (*cp) {
335 hval = (hval << 4) + *cp++;
336 if ((g = (hval & hbits_tst)) != 0)
337 hval ^= g >> 24;
338 hval &= ~g;
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);
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.
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.
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
386 /*ARGSUSED*/
387 static nss_status_t
388 nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
389 const char *dbname, int dbop, size_t *rlen, const char *typestr)
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;
401 if (buffer == NULL || length == 0 || arg == NULL ||
402 dbname == NULL || rlen == NULL || typestr == NULL)
403 return (NSS_ERROR);
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);
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;
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(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;
584 if (len3 == 1)
585 *dptr++ = '\0';
586 else {
587 (void) strlcpy(dptr, pe->type, len3);
588 dptr += len3;
590 if (len4 == 1)
591 *dptr++ = '\0';
592 else {
593 (void) strlcpy(dptr, pe->id, len4);
594 dptr += len4;
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;
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;
640 cv = ing->groups.argv;
641 for (i = ing->groups.argc; --i >= 0; ) {
642 if (*cv)
643 len3 += strlen(*cv++) + 1;
645 len3 = ROUND_UP(len3, sizeof (nssuint_t));
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
652 if ((len + (len2 << 1) + len3) >= length)
653 return (NSS_ERROR);
654 *rlen = len + (len2 << 1) + len3;
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;
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;
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;
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;
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);
739 return (NSS_SUCCESS);
742 nss_status_t
743 nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
744 const char *dbname, int dbop, size_t *rlen)
746 int index;
748 if (buffer == NULL || length == 0 || arg == NULL ||
749 dbname == NULL || rlen == NULL)
750 return (NSS_ERROR);
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.
757 if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
758 return (NSS_TRYLOCAL);
760 return (nss_pack_key2str(buffer, length, arg, dbname,
761 dbop, rlen, getXbyY_to_dbop[index].tostr));
764 /*ARGSUSED*/
765 void
766 nss_packed_set_status(void *buffer, size_t length, nss_status_t status,
767 nss_XbyY_args_t *arg)
769 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
770 nss_dbd_t *pdbd;
771 char *dbn;
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;
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;
792 return;
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;
800 /* tell nss_unpack() operation is successful */
801 pbuf->data_len = 1;
803 if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
804 pbuf->p_status = status;
805 pbuf->p_errno = errno;
806 return;
809 if (in->status == NSS_NETGR_FOUND) {
810 pbuf->p_status = NSS_SUCCESS;
811 } else {
812 pbuf->p_status = NSS_NOTFOUND;
813 pbuf->p_errno = errno;
815 return;
819 /* process normal cases */
820 if ((pbuf->p_status = status) != NSS_SUCCESS) {
821 if (arg->erange == 1)
822 pbuf->p_errno = ERANGE;
823 else
824 pbuf->p_errno = errno;
825 } else
826 pbuf->p_errno = 0;
827 if (arg != NULL) {
828 pbuf->p_herrno = (uint32_t)arg->h_errno;
829 pbuf->data_len = (nssuint_t)arg->returnlen;
830 } else {
831 pbuf->p_herrno = 0;
832 pbuf->data_len = 0;
837 * nss_upack_key2arg
838 * Private string to key unpacking function for getXbyY routines
839 * This routine performs a scanf/printf like parse over the packed
840 * string, to uppack and re-assemble the key in the args structure.
842 * buffer - Start of the key buffer location [in packed buffer]
843 * length - Length of key buffer component
844 * Key offsets are relative to start of key buffer location.
846 * Unpack fields Key
847 * key.name n
848 * key.number N
849 * key.uid u
850 * key.gid g
851 * key.hostaddr h
852 * key.ipnode i
853 * key.projid p
854 * key.serv(name) s
855 * key.serv(port) S
856 * key.ether e
857 * key.pkey k
858 * key.netaddr a
859 * key.attrp A
860 * groupsbymember I
861 * innetgr_args t
862 * setnetgr_args T
863 * Assumes arguments are all valid
866 /*ARGSUSED*/
867 static nss_status_t
868 nss_upack_key2arg(void *buffer, size_t length, char **dbname,
869 int *dbop, nss_XbyY_args_t *arg, int index)
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;
883 /* keysize is length of the key area */
884 keysize = pbuf->data_off - pbuf->key_off;
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;
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;
966 if (*bptr == '\0') {
967 pe->type = NULL;
968 bptr++;
969 } else {
970 pe->type = (char *)bptr;
971 bptr += strlen(pe->type) + 1;
973 if (*bptr == '\0') {
974 pe->id = NULL;
975 bptr++;
976 } else {
977 pe->id = (char *)bptr;
978 bptr += strlen(pe->id) + 1;
980 if (*bptr == '\0') {
981 pe->policy = NULL;
982 } else {
983 pe->policy = (char *)bptr;
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;
1011 * Start of argv pointer storage
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);
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++);
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++);
1037 break;
1038 case 'T':
1039 sng = (struct nss_setnetgrent_args *)arg;
1040 sng->netgroup = (const char *)bptr;
1041 sng->iterator = 0;
1042 break;
1044 default:
1045 return (NSS_ERROR);
1048 return (NSS_SUCCESS);
1051 static nss_status_t
1052 nss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e)
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;
1062 if (handle == NULL) {
1063 htmp = dlopen((const char *)0, RTLD_LAZY);
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;
1076 lmutex_unlock(&handle_lock);
1077 if (htmp)
1078 (void) dlclose(htmp);
1080 membar_consumer();
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);
1093 membar_consumer();
1094 *initf = (nss_db_initf_t)getXbyY_to_dbop[index].initfnp;
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);
1107 membar_consumer();
1108 *s2e = (nss_str2ent_t)getXbyY_to_dbop[index].strfnp;
1111 return (NSS_SUCCESS);
1114 nss_status_t
1115 nss_packed_getkey(void *buffer, size_t length, char **dbname,
1116 int *dbop, nss_XbyY_args_t *arg)
1118 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
1119 nss_dbd_t *pdbd;
1120 nssuint_t off, dbdsize;
1121 int index;
1123 if (buffer == NULL || length == 0 || dbop == NULL ||
1124 arg == NULL || dbname == NULL)
1125 return (NSS_ERROR);
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));
1142 * str2packent: Standard format interposed str2X function for normal APIs
1144 * Return values: 0 = success, 1 = parse error, 2 = erange ...
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.
1151 /*ARGSUSED*/
1152 static int
1153 str2packent(
1154 const char *instr,
1155 int lenstr,
1156 void *ent, /* really (char *) */
1157 char *buffer,
1158 int buflen
1161 if (buflen <= lenstr) { /* not enough buffer */
1162 return (NSS_STR_PARSE_ERANGE);
1164 (void) memmove(buffer, instr, lenstr);
1165 buffer[lenstr] = '\0';
1167 return (NSS_STR_PARSE_SUCCESS);
1171 * Initialize db_root, initf, dbop and arg from a packed buffer
1174 /*ARGSUSED*/
1175 nss_status_t
1176 nss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
1177 nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg)
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;
1188 if (buffer == NULL || length == 0 ||
1189 dbop == NULL || arg == NULL)
1190 return (NSS_ERROR);
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);
1204 /* db_root is initialized by nscd's based on door info */
1205 /* do nothing here */
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);
1212 /* possible audituser init */
1213 if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
1214 arg->h_errno = (int)pbuf->p_herrno;
1216 bptr = (char *)buffer + pbuf->data_off;
1217 len = (size_t)pbuf->data_len;
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);
1229 if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
1230 strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
1231 return (NSS_SUCCESS);
1234 /* get initf and str2ent functions */
1235 if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
1236 return (NSS_ERROR);
1238 /* init normal arg cases */
1239 NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1240 arg->h_errno = 0;
1242 return (NSS_SUCCESS);
1246 * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
1249 /*ARGSUSED*/
1250 nss_status_t
1251 nss_packed_context_init(void *buffer, size_t length, nss_db_root_t *db_root,
1252 nss_db_initf_t *initf, nss_getent_t **contextp,
1253 nss_XbyY_args_t *arg)
1255 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
1256 nss_str2ent_t s2e = str2packent;
1257 char *bptr;
1258 size_t len;
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);
1267 return (NSS_SUCCESS);