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