6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / gen / nss_dbdefs.c
blobee526c5f3c2f319a76f28289c5cea7937af8de7e
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_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"),
297 static int
298 nss_dbop_search(const char *name, uint32_t dbop)
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;
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;
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);
327 getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG;
329 membar_producer();
330 getXbyYdbop_hashed = 1;
332 lmutex_unlock(&getXbydbop_hash_lock);
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;
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);
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.
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.
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
389 /*ARGSUSED*/
390 static nss_status_t
391 nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
392 const char *dbname, int dbop, size_t *rlen, const char *typestr)
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;
404 if (buffer == NULL || length == 0 || arg == NULL ||
405 dbname == NULL || rlen == NULL || typestr == NULL)
406 return (NSS_ERROR);
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);
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;
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;
587 if (len3 == 1)
588 *dptr++ = '\0';
589 else {
590 (void) strlcpy(dptr, pe->type, len3);
591 dptr += len3;
593 if (len4 == 1)
594 *dptr++ = '\0';
595 else {
596 (void) strlcpy(dptr, pe->id, len4);
597 dptr += len4;
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;
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;
643 cv = ing->groups.argv;
644 for (i = ing->groups.argc; --i >= 0; ) {
645 if (*cv)
646 len3 += strlen(*cv++) + 1;
648 len3 = ROUND_UP(len3, sizeof (nssuint_t));
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
655 if ((len + (len2 << 1) + len3) >= length)
656 return (NSS_ERROR);
657 *rlen = len + (len2 << 1) + len3;
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;
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;
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;
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;
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);
742 return (NSS_SUCCESS);
745 nss_status_t
746 nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
747 const char *dbname, int dbop, size_t *rlen)
749 int index;
751 if (buffer == NULL || length == 0 || arg == NULL ||
752 dbname == NULL || rlen == NULL)
753 return (NSS_ERROR);
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.
760 if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
761 return (NSS_TRYLOCAL);
763 return (nss_pack_key2str(buffer, length, arg, dbname,
764 dbop, rlen, getXbyY_to_dbop[index].tostr));
767 /*ARGSUSED*/
768 void
769 nss_packed_set_status(void *buffer, size_t length, nss_status_t status,
770 nss_XbyY_args_t *arg)
772 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
773 nss_dbd_t *pdbd;
774 char *dbn;
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;
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;
795 return;
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;
803 /* tell nss_unpack() operation is successful */
804 pbuf->data_len = 1;
806 if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
807 pbuf->p_status = status;
808 pbuf->p_errno = errno;
809 return;
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;
818 return;
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;
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.
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.
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
869 /*ARGSUSED*/
870 static nss_status_t
871 nss_upack_key2arg(void *buffer, size_t length, char **dbname,
872 int *dbop, nss_XbyY_args_t *arg, int index)
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;
886 /* keysize is length of the key area */
887 keysize = pbuf->data_off - pbuf->key_off;
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;
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;
969 if (*bptr == '\0') {
970 pe->type = NULL;
971 bptr++;
972 } else {
973 pe->type = (char *)bptr;
974 bptr += strlen(pe->type) + 1;
976 if (*bptr == '\0') {
977 pe->id = NULL;
978 bptr++;
979 } else {
980 pe->id = (char *)bptr;
981 bptr += strlen(pe->id) + 1;
983 if (*bptr == '\0') {
984 pe->policy = NULL;
985 } else {
986 pe->policy = (char *)bptr;
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;
1014 * Start of argv pointer storage
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);
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++);
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++);
1040 break;
1041 case 'T':
1042 sng = (struct nss_setnetgrent_args *)arg;
1043 sng->netgroup = (const char *)bptr;
1044 sng->iterator = 0;
1045 break;
1047 default:
1048 return (NSS_ERROR);
1051 return (NSS_SUCCESS);
1054 static nss_status_t
1055 nss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e)
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;
1065 if (handle == NULL) {
1066 htmp = dlopen((const char *)0, RTLD_LAZY);
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;
1079 lmutex_unlock(&handle_lock);
1080 if (htmp)
1081 dlclose(htmp);
1083 membar_consumer();
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);
1096 membar_consumer();
1097 *initf = (nss_db_initf_t)getXbyY_to_dbop[index].initfnp;
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);
1110 membar_consumer();
1111 *s2e = (nss_str2ent_t)getXbyY_to_dbop[index].strfnp;
1114 return (NSS_SUCCESS);
1117 nss_status_t
1118 nss_packed_getkey(void *buffer, size_t length, char **dbname,
1119 int *dbop, nss_XbyY_args_t *arg)
1121 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
1122 nss_dbd_t *pdbd;
1123 nssuint_t off, dbdsize;
1124 int index;
1126 if (buffer == NULL || length == 0 || dbop == NULL ||
1127 arg == NULL || dbname == NULL)
1128 return (NSS_ERROR);
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));
1145 * str2packent: Standard format interposed str2X function for normal APIs
1147 * Return values: 0 = success, 1 = parse error, 2 = erange ...
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.
1154 /*ARGSUSED*/
1155 static int
1156 str2packent(
1157 const char *instr,
1158 int lenstr,
1159 void *ent, /* really (char *) */
1160 char *buffer,
1161 int buflen
1164 if (buflen <= lenstr) { /* not enough buffer */
1165 return (NSS_STR_PARSE_ERANGE);
1167 (void) memmove(buffer, instr, lenstr);
1168 buffer[lenstr] = '\0';
1170 return (NSS_STR_PARSE_SUCCESS);
1174 * Initialize db_root, initf, dbop and arg from a packed buffer
1177 /*ARGSUSED*/
1178 nss_status_t
1179 nss_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)
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;
1191 if (buffer == NULL || length == 0 ||
1192 dbop == NULL || arg == NULL)
1193 return (NSS_ERROR);
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);
1207 /* db_root is initialized by nscd's based on door info */
1208 /* do nothing here */
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);
1215 /* possible audituser init */
1216 if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
1217 arg->h_errno = (int)pbuf->p_herrno;
1219 bptr = (char *)buffer + pbuf->data_off;
1220 len = (size_t)pbuf->data_len;
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);
1232 if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
1233 strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
1234 return (NSS_SUCCESS);
1237 /* get initf and str2ent functions */
1238 if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
1239 return (NSS_ERROR);
1241 /* init normal arg cases */
1242 NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
1243 arg->h_errno = 0;
1245 return (NSS_SUCCESS);
1249 * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
1252 /*ARGSUSED*/
1253 nss_status_t
1254 nss_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)
1258 nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
1259 nss_str2ent_t s2e = str2packent;
1260 char *bptr;
1261 size_t len;
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);
1270 return (NSS_SUCCESS);