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