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