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