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