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