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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2017 Joyent Inc 26 */ 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 /* 30 * Portions of this source code were derived from Berkeley 31 * 4.3 BSD under license from the Regents of the University of 32 * California. 33 */ 34 35 /* 36 * svcauth_des.c, server-side des authentication 37 * 38 * We insure for the service the following: 39 * (1) The timestamp microseconds do not exceed 1 million. 40 * (2) The timestamp plus the window is less than the current time. 41 * (3) The timestamp is not less than the one previously 42 * seen in the current session. 43 * 44 * It is up to the server to determine if the window size is 45 * too small. 46 * 47 */ 48 49 #include "mt.h" 50 #include "rpc_mt.h" 51 #include <assert.h> 52 #include <rpc/des_crypt.h> 53 #include <rpc/rpc.h> 54 #include <sys/types.h> 55 #include <sys/param.h> 56 #include <stdlib.h> 57 #include <unistd.h> 58 #include <string.h> 59 #include <strings.h> 60 #include <sys/debug.h> 61 62 #include <syslog.h> 63 64 extern int key_decryptsession_pk(const char *, netobj *, des_block *); 65 66 #define USEC_PER_SEC ((ulong_t)1000000L) 67 #define BEFORE(t1, t2) timercmp(t1, t2, < /* EMPTY */) 68 69 70 /* 71 * LRU cache of conversation keys and some other useful items. 72 */ 73 #define DEF_AUTHDES_CACHESZ 128 74 int authdes_cachesz = DEF_AUTHDES_CACHESZ; 75 struct cache_entry { 76 des_block key; /* conversation key */ 77 char *rname; /* client's name */ 78 uint_t window; /* credential lifetime window */ 79 struct timeval laststamp; /* detect replays of creds */ 80 char *localcred; /* generic local credential */ 81 int index; /* where are we in array? */ 82 struct cache_entry *prev; /* prev entry on LRU list */ 83 struct cache_entry *next; /* next entry on LRU list */ 84 }; 85 86 static const char __getucredstr[] = "authdes_getucred:"; 87 88 static struct cache_entry *_rpc_authdes_cache; /* [authdes_cachesz] */ 89 static struct cache_entry *cache_head; /* cache (in LRU order) */ 90 static struct cache_entry *cache_tail; /* cache (in LRU order) */ 91 92 /* 93 * A rwlock_t would seem to make more sense, but it turns out we always 94 * muck with the cache entries, so would always need a write lock (in 95 * which case, we might as well use a mutex). 96 */ 97 extern mutex_t authdes_lock; 98 99 100 static int cache_init(void); /* initialize the cache */ 101 /* find an entry in the cache */ 102 static int cache_spot(des_block *, char *, struct timeval *); 103 static void cache_ref(uint32_t); /* note that sid was ref'd */ 104 static void invalidate(char *); /* invalidate entry in cache */ 105 static void __msgout(int, const char *, const char *); 106 static void __msgout2(const char *, const char *); 107 108 /* 109 * cache statistics 110 */ 111 struct { 112 ulong_t ncachehits; /* times cache hit, and is not replay */ 113 ulong_t ncachereplays; /* times cache hit, and is replay */ 114 ulong_t ncachemisses; /* times cache missed */ 115 } svcauthdes_stats; 116 117 /* 118 * NOTE: this has to fit inside RQCRED_SIZE bytes. If you update this struct, 119 * double-check it still fits. 120 */ 121 struct authdes_area { 122 struct authdes_cred area_cred; 123 char area_netname[MAXNETNAMELEN+1]; 124 }; 125 CTASSERT(sizeof (struct authdes_area) <= RQCRED_SIZE); 126 127 /* 128 * Service side authenticator for AUTH_DES 129 */ 130 enum auth_stat 131 __svcauth_des(struct svc_req *rqst, struct rpc_msg *msg) 132 { 133 int32_t *ixdr; 134 des_block cryptbuf[2]; 135 struct authdes_cred *cred; 136 struct authdes_verf verf; 137 int status; 138 struct cache_entry *entry; 139 uint32_t sid; 140 int cache_spot_id; 141 des_block *sessionkey, init_sessionkey; 142 des_block ivec; 143 uint_t window; 144 struct authdes_area *area; 145 struct timeval timestamp; 146 uint32_t namelen; 147 int fullname_rcvd = 0; 148 int from_cache = 0; 149 150 (void) mutex_lock(&authdes_lock); 151 if (_rpc_authdes_cache == NULL) { 152 int ret = cache_init(); 153 if (ret == -1) { 154 (void) mutex_unlock(&authdes_lock); 155 return (AUTH_FAILED); 156 } 157 } 158 (void) mutex_unlock(&authdes_lock); 159 160 /* LINTED pointer cast */ 161 area = (struct authdes_area *)rqst->rq_clntcred; 162 cred = (struct authdes_cred *)&area->area_cred; 163 164 if ((uint_t)msg->rm_call.cb_cred.oa_length == 0) 165 return (AUTH_BADCRED); 166 /* 167 * Get the credential 168 */ 169 /* LINTED pointer cast */ 170 ixdr = (int32_t *)msg->rm_call.cb_cred.oa_base; 171 cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 172 switch (cred->adc_namekind) { 173 case ADN_FULLNAME: 174 namelen = IXDR_GET_U_INT32(ixdr); 175 if (namelen > MAXNETNAMELEN) 176 return (AUTH_BADCRED); 177 cred->adc_fullname.name = area->area_netname; 178 (void) memcpy(cred->adc_fullname.name, ixdr, (uint_t)namelen); 179 cred->adc_fullname.name[namelen] = 0; 180 ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 181 cred->adc_fullname.key.key.high = (uint32_t)*ixdr++; 182 cred->adc_fullname.key.key.low = (uint32_t)*ixdr++; 183 cred->adc_fullname.window = (uint32_t)*ixdr++; 184 fullname_rcvd++; 185 break; 186 case ADN_NICKNAME: 187 cred->adc_nickname = (uint32_t)*ixdr++; 188 break; 189 default: 190 return (AUTH_BADCRED); 191 } 192 193 if ((uint_t)msg->rm_call.cb_verf.oa_length == 0) 194 return (AUTH_BADVERF); 195 /* 196 * Get the verifier 197 */ 198 /* LINTED pointer cast */ 199 ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 200 verf.adv_xtimestamp.key.high = (uint32_t)*ixdr++; 201 verf.adv_xtimestamp.key.low = (uint32_t)*ixdr++; 202 verf.adv_int_u = (uint32_t)*ixdr++; 203 204 (void) mutex_lock(&authdes_lock); 205 206 /* 207 * Get the conversation key 208 */ 209 if (fullname_rcvd) { /* ADN_FULLNAME */ 210 netobj pkey; 211 char pkey_data[1024]; 212 213 again: 214 init_sessionkey = cred->adc_fullname.key; 215 sessionkey = &init_sessionkey; 216 217 if (!__getpublickey_cached(cred->adc_fullname.name, 218 pkey_data, &from_cache)) { 219 /* 220 * if the user has no public key, treat him as the 221 * unauthenticated identity - nobody. If this 222 * works, it means the client didn't find the 223 * user's keys and used nobody's secret key 224 * as a backup. 225 */ 226 if (!__getpublickey_cached("nobody", 227 pkey_data, &from_cache)) { 228 __msgout(LOG_INFO, 229 "_svcauth_des: no public key for nobody or ", 230 cred->adc_fullname.name); 231 (void) mutex_unlock(&authdes_lock); 232 return (AUTH_BADCRED); /* no key */ 233 } 234 235 /* 236 * found a public key for nobody. change 237 * the fullname id to nobody, so the caller 238 * thinks the client specified nobody 239 * as the user identity. 240 */ 241 (void) strcpy(cred->adc_fullname.name, "nobody"); 242 } 243 pkey.n_bytes = pkey_data; 244 pkey.n_len = strlen(pkey_data) + 1; 245 if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, 246 sessionkey) < 0) { 247 if (from_cache) { 248 __getpublickey_flush(cred->adc_fullname.name); 249 goto again; 250 } 251 __msgout(LOG_INFO, 252 "_svcauth_des: key_decryptsessionkey failed for", 253 cred->adc_fullname.name); 254 (void) mutex_unlock(&authdes_lock); 255 return (AUTH_BADCRED); /* key not found */ 256 } 257 } else { /* ADN_NICKNAME */ 258 sid = cred->adc_nickname; 259 if (sid >= authdes_cachesz) { 260 __msgout(LOG_INFO, "_svcauth_des:", "bad nickname"); 261 (void) mutex_unlock(&authdes_lock); 262 return (AUTH_BADCRED); /* garbled credential */ 263 } 264 /* actually check that the entry is not null */ 265 entry = &_rpc_authdes_cache[sid]; 266 if (entry->rname == NULL) { 267 (void) mutex_unlock(&authdes_lock); 268 return (AUTH_BADCRED); /* cached out */ 269 } 270 sessionkey = &_rpc_authdes_cache[sid].key; 271 } 272 273 /* 274 * Decrypt the timestamp 275 */ 276 cryptbuf[0] = verf.adv_xtimestamp; 277 if (fullname_rcvd) { /* ADN_FULLNAME */ 278 cryptbuf[1].key.high = cred->adc_fullname.window; 279 cryptbuf[1].key.low = verf.adv_winverf; 280 ivec.key.high = ivec.key.low = 0; 281 status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 282 2 * (int)sizeof (des_block), DES_DECRYPT | DES_HW, 283 (char *)&ivec); 284 } else { 285 status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 286 (int)sizeof (des_block), DES_DECRYPT | DES_HW); 287 } 288 if (DES_FAILED(status)) { 289 if (fullname_rcvd && from_cache) { 290 __getpublickey_flush(cred->adc_fullname.name); 291 goto again; 292 } 293 __msgout(LOG_ERR, "_svcauth_des: DES decryption failure for", 294 fullname_rcvd ? cred->adc_fullname.name : 295 _rpc_authdes_cache[sid].rname); 296 (void) mutex_unlock(&authdes_lock); 297 return (AUTH_FAILED); /* system error */ 298 } 299 300 /* 301 * XDR the decrypted timestamp 302 */ 303 ixdr = (int32_t *)cryptbuf; 304 timestamp.tv_sec = IXDR_GET_INT32(ixdr); 305 timestamp.tv_usec = IXDR_GET_INT32(ixdr); 306 307 /* 308 * Check for valid credentials and verifiers. 309 * They could be invalid because the key was flushed 310 * out of the cache, and so a new session should begin. 311 * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 312 */ 313 { 314 struct timeval current; 315 int nick; 316 int winverf; 317 318 if (fullname_rcvd) { 319 window = IXDR_GET_U_INT32(ixdr); 320 winverf = IXDR_GET_U_INT32(ixdr); 321 if (winverf != window - 1) { 322 if (from_cache) { 323 __getpublickey_flush( 324 cred->adc_fullname.name); 325 goto again; 326 } 327 __msgout(LOG_INFO, 328 "_svcauth_des: corrupted window from", 329 cred->adc_fullname.name); 330 (void) mutex_unlock(&authdes_lock); 331 /* garbled credential or invalid secret key */ 332 return (AUTH_BADCRED); 333 } 334 cache_spot_id = cache_spot(sessionkey, 335 cred->adc_fullname.name, 336 337 ×tamp); 338 if (cache_spot_id < 0) { 339 __msgout(LOG_INFO, 340 "_svcauth_des: replayed credential from", 341 cred->adc_fullname.name); 342 (void) mutex_unlock(&authdes_lock); 343 return (AUTH_REJECTEDCRED); /* replay */ 344 } else sid = cache_spot_id; 345 nick = 0; 346 } else { /* ADN_NICKNAME */ 347 window = _rpc_authdes_cache[sid].window; 348 nick = 1; 349 } 350 351 if ((ulong_t)timestamp.tv_usec >= USEC_PER_SEC) { 352 if (fullname_rcvd && from_cache) { 353 __getpublickey_flush(cred->adc_fullname.name); 354 goto again; 355 } 356 __msgout(LOG_INFO, 357 "_svcauth_des: invalid timestamp received from", 358 fullname_rcvd ? cred->adc_fullname.name : 359 _rpc_authdes_cache[sid].rname); 360 /* cached out (bad key), or garbled verifier */ 361 (void) mutex_unlock(&authdes_lock); 362 return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 363 } 364 if (nick && BEFORE(×tamp, 365 &_rpc_authdes_cache[sid].laststamp)) { 366 if (fullname_rcvd && from_cache) { 367 __getpublickey_flush(cred->adc_fullname.name); 368 goto again; 369 } 370 __msgout(LOG_INFO, 371 "_svcauth_des: timestamp is earlier than the one previously seen from", 372 fullname_rcvd ? cred->adc_fullname.name : 373 _rpc_authdes_cache[sid].rname); 374 (void) mutex_unlock(&authdes_lock); 375 return (AUTH_REJECTEDVERF); /* replay */ 376 } 377 (void) gettimeofday(¤t, NULL); 378 current.tv_sec -= window; /* allow for expiration */ 379 if (!BEFORE(¤t, ×tamp)) { 380 if (fullname_rcvd && from_cache) { 381 __getpublickey_flush(cred->adc_fullname.name); 382 goto again; 383 } 384 __msgout(LOG_INFO, 385 "_svcauth_des: timestamp expired for", 386 fullname_rcvd ? cred->adc_fullname.name : 387 _rpc_authdes_cache[sid].rname); 388 /* replay, or garbled credential */ 389 (void) mutex_unlock(&authdes_lock); 390 return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 391 } 392 } 393 394 /* 395 * Set up the reply verifier 396 */ 397 verf.adv_nickname = sid; 398 399 /* 400 * xdr the timestamp before encrypting 401 */ 402 ixdr = (int32_t *)cryptbuf; 403 IXDR_PUT_INT32(ixdr, timestamp.tv_sec - 1); 404 IXDR_PUT_INT32(ixdr, timestamp.tv_usec); 405 406 /* 407 * encrypt the timestamp 408 */ 409 status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 410 (int)sizeof (des_block), DES_ENCRYPT | DES_HW); 411 if (DES_FAILED(status)) { 412 __msgout(LOG_ERR, "_svcauth_des: DES encryption failure for", 413 fullname_rcvd ? cred->adc_fullname.name : 414 _rpc_authdes_cache[sid].rname); 415 (void) mutex_unlock(&authdes_lock); 416 return (AUTH_FAILED); /* system error */ 417 } 418 verf.adv_xtimestamp = cryptbuf[0]; 419 420 /* 421 * Serialize the reply verifier, and update rqst 422 */ 423 /* LINTED pointer cast */ 424 ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 425 *ixdr++ = (int32_t)verf.adv_xtimestamp.key.high; 426 *ixdr++ = (int32_t)verf.adv_xtimestamp.key.low; 427 *ixdr++ = (int32_t)verf.adv_int_u; 428 429 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 430 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 431 rqst->rq_xprt->xp_verf.oa_length = 432 (char *)ixdr - msg->rm_call.cb_verf.oa_base; 433 if (rqst->rq_xprt->xp_verf.oa_length > MAX_AUTH_BYTES) { 434 __msgout(LOG_ERR, 435 "_svcauth_des: Authenticator length error", 436 fullname_rcvd ? cred->adc_fullname.name : 437 _rpc_authdes_cache[sid].rname); 438 (void) mutex_unlock(&authdes_lock); 439 return (AUTH_REJECTEDVERF); 440 } 441 442 /* 443 * We succeeded, commit the data to the cache now and 444 * finish cooking the credential. 445 */ 446 entry = &_rpc_authdes_cache[sid]; 447 entry->laststamp = timestamp; 448 cache_ref(sid); 449 if (cred->adc_namekind == ADN_FULLNAME) { 450 cred->adc_fullname.window = window; 451 cred->adc_nickname = sid; /* save nickname */ 452 if (entry->rname != NULL) 453 free(entry->rname); 454 entry->rname = malloc(strlen(cred->adc_fullname.name) + 1); 455 if (entry->rname != NULL) { 456 (void) strcpy(entry->rname, cred->adc_fullname.name); 457 } else { 458 __msgout(LOG_CRIT, "_svcauth_des:", "out of memory"); 459 (void) mutex_unlock(&authdes_lock); 460 return (AUTH_FAILED); 461 } 462 entry->key = *sessionkey; 463 entry->window = window; 464 /* mark any cached cred invalid */ 465 invalidate(entry->localcred); 466 } else { /* ADN_NICKNAME */ 467 /* 468 * nicknames are cooked into fullnames 469 */ 470 cred->adc_namekind = ADN_FULLNAME; 471 cred->adc_fullname.name = entry->rname; 472 cred->adc_fullname.key = entry->key; 473 cred->adc_fullname.window = entry->window; 474 } 475 (void) mutex_unlock(&authdes_lock); 476 return (AUTH_OK); /* we made it! */ 477 } 478 479 480 /* 481 * Initialize the cache 482 */ 483 static int 484 cache_init(void) 485 { 486 int i; 487 488 /* LOCK HELD ON ENTRY: authdes_lock */ 489 490 assert(MUTEX_HELD(&authdes_lock)); 491 _rpc_authdes_cache = 492 malloc(sizeof (struct cache_entry) * authdes_cachesz); 493 if (_rpc_authdes_cache == NULL) { 494 __msgout(LOG_CRIT, "cache_init:", "out of memory"); 495 return (-1); 496 } 497 (void) memset(_rpc_authdes_cache, 0, 498 sizeof (struct cache_entry) * authdes_cachesz); 499 500 /* 501 * Initialize the lru chain (linked-list) 502 */ 503 for (i = 1; i < (authdes_cachesz - 1); i++) { 504 _rpc_authdes_cache[i].index = i; 505 _rpc_authdes_cache[i].next = &_rpc_authdes_cache[i + 1]; 506 _rpc_authdes_cache[i].prev = &_rpc_authdes_cache[i - 1]; 507 } 508 cache_head = &_rpc_authdes_cache[0]; 509 cache_tail = &_rpc_authdes_cache[authdes_cachesz - 1]; 510 511 /* 512 * These elements of the chain need special attention... 513 */ 514 cache_head->index = 0; 515 cache_tail->index = authdes_cachesz - 1; 516 cache_head->next = &_rpc_authdes_cache[1]; 517 cache_head->prev = cache_tail; 518 cache_tail->next = cache_head; 519 cache_tail->prev = &_rpc_authdes_cache[authdes_cachesz - 2]; 520 return (0); 521 } 522 523 524 /* 525 * Find the lru victim 526 */ 527 static uint32_t 528 cache_victim(void) 529 { 530 /* LOCK HELD ON ENTRY: authdes_lock */ 531 532 assert(MUTEX_HELD(&authdes_lock)); 533 return (cache_head->index); /* list in lru order */ 534 } 535 536 /* 537 * Note that sid was referenced 538 */ 539 static void 540 cache_ref(uint32_t sid) 541 { 542 struct cache_entry *curr = &_rpc_authdes_cache[sid]; 543 544 545 /* LOCK HELD ON ENTRY: authdes_lock */ 546 547 assert(MUTEX_HELD(&authdes_lock)); 548 549 /* 550 * move referenced item from its place on the LRU chain 551 * to the tail of the chain while checking for special 552 * conditions (mainly for performance). 553 */ 554 if (cache_tail == curr) { /* no work to do */ 555 /*EMPTY*/; 556 } else if (cache_head == curr) { 557 cache_head = cache_head->next; 558 cache_tail = curr; 559 } else { 560 (curr->next)->prev = curr->prev; /* fix thy neighbor */ 561 (curr->prev)->next = curr->next; 562 curr->next = cache_head; /* fix thy self... */ 563 curr->prev = cache_tail; 564 cache_head->prev = curr; /* fix the head */ 565 cache_tail->next = curr; /* fix the tail */ 566 cache_tail = curr; /* move the tail */ 567 } 568 } 569 570 /* 571 * Find a spot in the cache for a credential containing 572 * the items given. Return -1 if a replay is detected, otherwise 573 * return the spot in the cache. 574 */ 575 static int 576 cache_spot(des_block *key, char *name, struct timeval *timestamp) 577 { 578 struct cache_entry *cp; 579 int i; 580 uint32_t hi; 581 582 /* LOCK HELD ON ENTRY: authdes_lock */ 583 584 assert(MUTEX_HELD(&authdes_lock)); 585 hi = key->key.high; 586 for (cp = _rpc_authdes_cache, i = 0; i < authdes_cachesz; i++, cp++) { 587 if (cp->key.key.high == hi && 588 cp->key.key.low == key->key.low && 589 cp->rname != NULL && 590 memcmp(cp->rname, name, strlen(name) + 1) == 0) { 591 if (BEFORE(timestamp, &cp->laststamp)) { 592 svcauthdes_stats.ncachereplays++; 593 return (-1); /* replay */ 594 } 595 svcauthdes_stats.ncachehits++; 596 return (i); 597 /* refresh */ 598 } 599 } 600 svcauthdes_stats.ncachemisses++; 601 return (cache_victim()); 602 } 603 604 605 /* 606 * Local credential handling stuff. 607 * NOTE: bsd unix dependent. 608 * Other operating systems should put something else here. 609 */ 610 #define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ 611 #define INVALID -1 /* grouplen, if cache entry is invalid */ 612 613 struct bsdcred { 614 uid_t uid; /* cached uid */ 615 gid_t gid; /* cached gid */ 616 short grouplen; /* length of cached groups */ 617 gid_t groups[1]; /* cached groups allocate _SC_NGROUPS_MAX */ 618 }; 619 620 static void 621 invalidate(char *cred) 622 { 623 if (cred == NULL) 624 return; 625 /* LINTED pointer cast */ 626 ((struct bsdcred *)cred)->grouplen = INVALID; 627 } 628 629 /* 630 * Map a des credential into a unix cred. 631 * We cache the credential here so the application does 632 * not have to make an rpc call every time to interpret 633 * the credential. 634 */ 635 int 636 authdes_getucred(const struct authdes_cred *adc, uid_t *uid, gid_t *gid, 637 short *grouplen, gid_t *groups) 638 { 639 uint32_t sid; 640 int i; 641 uid_t i_uid; 642 gid_t i_gid; 643 int i_grouplen; 644 struct bsdcred *cred; 645 646 sid = adc->adc_nickname; 647 if (sid >= authdes_cachesz) { 648 __msgout2(__getucredstr, "invalid nickname"); 649 return (0); 650 } 651 (void) mutex_lock(&authdes_lock); 652 /* LINTED pointer cast */ 653 cred = (struct bsdcred *)_rpc_authdes_cache[sid].localcred; 654 if (cred == NULL) { 655 static size_t bsdcred_sz; 656 657 if (bsdcred_sz == 0) { 658 bsdcred_sz = sizeof (struct bsdcred) + 659 (sysconf(_SC_NGROUPS_MAX) - 1) * sizeof (gid_t); 660 } 661 cred = malloc(bsdcred_sz); 662 if (cred == NULL) { 663 __msgout2(__getucredstr, "out of memory"); 664 (void) mutex_unlock(&authdes_lock); 665 return (0); 666 } 667 _rpc_authdes_cache[sid].localcred = (char *)cred; 668 cred->grouplen = INVALID; 669 } 670 if (cred->grouplen == INVALID) { 671 /* 672 * not in cache: lookup 673 */ 674 if (!netname2user(adc->adc_fullname.name, (uid_t *)&i_uid, 675 (gid_t *)&i_gid, &i_grouplen, (gid_t *)groups)) { 676 __msgout2(__getucredstr, "unknown netname"); 677 /* mark as lookup up, but not found */ 678 cred->grouplen = UNKNOWN; 679 (void) mutex_unlock(&authdes_lock); 680 return (0); 681 } 682 __msgout2(__getucredstr, "missed ucred cache"); 683 *uid = cred->uid = i_uid; 684 *gid = cred->gid = i_gid; 685 *grouplen = cred->grouplen = i_grouplen; 686 for (i = i_grouplen - 1; i >= 0; i--) { 687 cred->groups[i] = groups[i]; 688 } 689 (void) mutex_unlock(&authdes_lock); 690 return (1); 691 } 692 if (cred->grouplen == UNKNOWN) { 693 /* 694 * Already lookup up, but no match found 695 */ 696 (void) mutex_unlock(&authdes_lock); 697 return (0); 698 } 699 700 /* 701 * cached credentials 702 */ 703 *uid = cred->uid; 704 *gid = cred->gid; 705 *grouplen = cred->grouplen; 706 for (i = cred->grouplen - 1; i >= 0; i--) { 707 groups[i] = cred->groups[i]; 708 } 709 (void) mutex_unlock(&authdes_lock); 710 return (1); 711 } 712 713 714 static void 715 __msgout(int level, const char *str, const char *strarg) 716 { 717 (void) syslog(level, "%s %s", str, strarg); 718 } 719 720 721 static void 722 __msgout2(const char *str, const char *str2) 723 { 724 (void) syslog(LOG_DEBUG, "%s %s", str, str2); 725 } 726