17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 567dbe2beSCasper H.S. Dik * Common Development and Distribution License (the "License"). 667dbe2beSCasper H.S. Dik * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 2061961e0fSrobinson */ 2161961e0fSrobinson 2261961e0fSrobinson /* 2367dbe2beSCasper H.S. Dik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*4b3b7fc6SAlex Wilson * Copyright 2017 Joyent Inc 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 317c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 327c478bd9Sstevel@tonic-gate * California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * svcauth_des.c, server-side des authentication 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * We insure for the service the following: 397c478bd9Sstevel@tonic-gate * (1) The timestamp microseconds do not exceed 1 million. 407c478bd9Sstevel@tonic-gate * (2) The timestamp plus the window is less than the current time. 417c478bd9Sstevel@tonic-gate * (3) The timestamp is not less than the one previously 427c478bd9Sstevel@tonic-gate * seen in the current session. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * It is up to the server to determine if the window size is 457c478bd9Sstevel@tonic-gate * too small. 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #include "mt.h" 507c478bd9Sstevel@tonic-gate #include "rpc_mt.h" 517c478bd9Sstevel@tonic-gate #include <assert.h> 527c478bd9Sstevel@tonic-gate #include <rpc/des_crypt.h> 537c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 547c478bd9Sstevel@tonic-gate #include <sys/types.h> 5567dbe2beSCasper H.S. Dik #include <sys/param.h> 567c478bd9Sstevel@tonic-gate #include <stdlib.h> 577c478bd9Sstevel@tonic-gate #include <unistd.h> 587c478bd9Sstevel@tonic-gate #include <string.h> 5961961e0fSrobinson #include <strings.h> 60*4b3b7fc6SAlex Wilson #include <sys/debug.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <syslog.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate extern int key_decryptsession_pk(const char *, netobj *, des_block *); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define USEC_PER_SEC ((ulong_t)1000000L) 677c478bd9Sstevel@tonic-gate #define BEFORE(t1, t2) timercmp(t1, t2, < /* EMPTY */) 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * LRU cache of conversation keys and some other useful items. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate #define DEF_AUTHDES_CACHESZ 128 747c478bd9Sstevel@tonic-gate int authdes_cachesz = DEF_AUTHDES_CACHESZ; 757c478bd9Sstevel@tonic-gate struct cache_entry { 767c478bd9Sstevel@tonic-gate des_block key; /* conversation key */ 777c478bd9Sstevel@tonic-gate char *rname; /* client's name */ 787c478bd9Sstevel@tonic-gate uint_t window; /* credential lifetime window */ 797c478bd9Sstevel@tonic-gate struct timeval laststamp; /* detect replays of creds */ 807c478bd9Sstevel@tonic-gate char *localcred; /* generic local credential */ 817c478bd9Sstevel@tonic-gate int index; /* where are we in array? */ 827c478bd9Sstevel@tonic-gate struct cache_entry *prev; /* prev entry on LRU list */ 837c478bd9Sstevel@tonic-gate struct cache_entry *next; /* next entry on LRU list */ 847c478bd9Sstevel@tonic-gate }; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static const char __getucredstr[] = "authdes_getucred:"; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate static struct cache_entry *_rpc_authdes_cache; /* [authdes_cachesz] */ 897c478bd9Sstevel@tonic-gate static struct cache_entry *cache_head; /* cache (in LRU order) */ 907c478bd9Sstevel@tonic-gate static struct cache_entry *cache_tail; /* cache (in LRU order) */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * A rwlock_t would seem to make more sense, but it turns out we always 947c478bd9Sstevel@tonic-gate * muck with the cache entries, so would always need a write lock (in 957c478bd9Sstevel@tonic-gate * which case, we might as well use a mutex). 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate extern mutex_t authdes_lock; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static int cache_init(void); /* initialize the cache */ 1017c478bd9Sstevel@tonic-gate /* find an entry in the cache */ 1027c478bd9Sstevel@tonic-gate static int cache_spot(des_block *, char *, struct timeval *); 1037c478bd9Sstevel@tonic-gate static void cache_ref(uint32_t); /* note that sid was ref'd */ 1047c478bd9Sstevel@tonic-gate static void invalidate(char *); /* invalidate entry in cache */ 1057c478bd9Sstevel@tonic-gate static void __msgout(int, const char *, const char *); 1067c478bd9Sstevel@tonic-gate static void __msgout2(const char *, const char *); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * cache statistics 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate struct { 1127c478bd9Sstevel@tonic-gate ulong_t ncachehits; /* times cache hit, and is not replay */ 1137c478bd9Sstevel@tonic-gate ulong_t ncachereplays; /* times cache hit, and is replay */ 1147c478bd9Sstevel@tonic-gate ulong_t ncachemisses; /* times cache missed */ 1157c478bd9Sstevel@tonic-gate } svcauthdes_stats; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 118*4b3b7fc6SAlex Wilson * NOTE: this has to fit inside RQCRED_SIZE bytes. If you update this struct, 119*4b3b7fc6SAlex Wilson * double-check it still fits. 120*4b3b7fc6SAlex Wilson */ 121*4b3b7fc6SAlex Wilson struct authdes_area { 122*4b3b7fc6SAlex Wilson struct authdes_cred area_cred; 123*4b3b7fc6SAlex Wilson char area_netname[MAXNETNAMELEN+1]; 124*4b3b7fc6SAlex Wilson }; 125*4b3b7fc6SAlex Wilson CTASSERT(sizeof (struct authdes_area) <= RQCRED_SIZE); 126*4b3b7fc6SAlex Wilson 127*4b3b7fc6SAlex Wilson /* 1287c478bd9Sstevel@tonic-gate * Service side authenticator for AUTH_DES 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate enum auth_stat 1317c478bd9Sstevel@tonic-gate __svcauth_des(struct svc_req *rqst, struct rpc_msg *msg) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate int32_t *ixdr; 1347c478bd9Sstevel@tonic-gate des_block cryptbuf[2]; 1357c478bd9Sstevel@tonic-gate struct authdes_cred *cred; 1367c478bd9Sstevel@tonic-gate struct authdes_verf verf; 1377c478bd9Sstevel@tonic-gate int status; 1387c478bd9Sstevel@tonic-gate struct cache_entry *entry; 1397c478bd9Sstevel@tonic-gate uint32_t sid; 1407c478bd9Sstevel@tonic-gate int cache_spot_id; 1417c478bd9Sstevel@tonic-gate des_block *sessionkey, init_sessionkey; 1427c478bd9Sstevel@tonic-gate des_block ivec; 1437c478bd9Sstevel@tonic-gate uint_t window; 144*4b3b7fc6SAlex Wilson struct authdes_area *area; 1457c478bd9Sstevel@tonic-gate struct timeval timestamp; 1467c478bd9Sstevel@tonic-gate uint32_t namelen; 1477c478bd9Sstevel@tonic-gate int fullname_rcvd = 0; 1487c478bd9Sstevel@tonic-gate int from_cache = 0; 1497c478bd9Sstevel@tonic-gate 15061961e0fSrobinson (void) mutex_lock(&authdes_lock); 1517c478bd9Sstevel@tonic-gate if (_rpc_authdes_cache == NULL) { 1527c478bd9Sstevel@tonic-gate int ret = cache_init(); 1537c478bd9Sstevel@tonic-gate if (ret == -1) { 15461961e0fSrobinson (void) mutex_unlock(&authdes_lock); 1557c478bd9Sstevel@tonic-gate return (AUTH_FAILED); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate } 15861961e0fSrobinson (void) mutex_unlock(&authdes_lock); 1597c478bd9Sstevel@tonic-gate 16061961e0fSrobinson /* LINTED pointer cast */ 161*4b3b7fc6SAlex Wilson area = (struct authdes_area *)rqst->rq_clntcred; 1627c478bd9Sstevel@tonic-gate cred = (struct authdes_cred *)&area->area_cred; 1637c478bd9Sstevel@tonic-gate 16461961e0fSrobinson if ((uint_t)msg->rm_call.cb_cred.oa_length == 0) 1657c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * Get the credential 1687c478bd9Sstevel@tonic-gate */ 16961961e0fSrobinson /* LINTED pointer cast */ 1707c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_cred.oa_base; 1717c478bd9Sstevel@tonic-gate cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 1727c478bd9Sstevel@tonic-gate switch (cred->adc_namekind) { 1737c478bd9Sstevel@tonic-gate case ADN_FULLNAME: 1747c478bd9Sstevel@tonic-gate namelen = IXDR_GET_U_INT32(ixdr); 17561961e0fSrobinson if (namelen > MAXNETNAMELEN) 1767c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 1777c478bd9Sstevel@tonic-gate cred->adc_fullname.name = area->area_netname; 17861961e0fSrobinson (void) memcpy(cred->adc_fullname.name, ixdr, (uint_t)namelen); 1797c478bd9Sstevel@tonic-gate cred->adc_fullname.name[namelen] = 0; 1807c478bd9Sstevel@tonic-gate ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 1817c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.high = (uint32_t)*ixdr++; 1827c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.low = (uint32_t)*ixdr++; 1837c478bd9Sstevel@tonic-gate cred->adc_fullname.window = (uint32_t)*ixdr++; 1847c478bd9Sstevel@tonic-gate fullname_rcvd++; 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate case ADN_NICKNAME: 1877c478bd9Sstevel@tonic-gate cred->adc_nickname = (uint32_t)*ixdr++; 1887c478bd9Sstevel@tonic-gate break; 1897c478bd9Sstevel@tonic-gate default: 1907c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 19361961e0fSrobinson if ((uint_t)msg->rm_call.cb_verf.oa_length == 0) 1947c478bd9Sstevel@tonic-gate return (AUTH_BADVERF); 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * Get the verifier 1977c478bd9Sstevel@tonic-gate */ 19861961e0fSrobinson /* LINTED pointer cast */ 1997c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 2007c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.high = (uint32_t)*ixdr++; 2017c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.low = (uint32_t)*ixdr++; 2027c478bd9Sstevel@tonic-gate verf.adv_int_u = (uint32_t)*ixdr++; 2037c478bd9Sstevel@tonic-gate 20461961e0fSrobinson (void) mutex_lock(&authdes_lock); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * Get the conversation key 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate if (fullname_rcvd) { /* ADN_FULLNAME */ 2107c478bd9Sstevel@tonic-gate netobj pkey; 2117c478bd9Sstevel@tonic-gate char pkey_data[1024]; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate again: 2147c478bd9Sstevel@tonic-gate init_sessionkey = cred->adc_fullname.key; 2157c478bd9Sstevel@tonic-gate sessionkey = &init_sessionkey; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate if (!__getpublickey_cached(cred->adc_fullname.name, 2187c478bd9Sstevel@tonic-gate pkey_data, &from_cache)) { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * if the user has no public key, treat him as the 2217c478bd9Sstevel@tonic-gate * unauthenticated identity - nobody. If this 2227c478bd9Sstevel@tonic-gate * works, it means the client didn't find the 2237c478bd9Sstevel@tonic-gate * user's keys and used nobody's secret key 2247c478bd9Sstevel@tonic-gate * as a backup. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate if (!__getpublickey_cached("nobody", 2277c478bd9Sstevel@tonic-gate pkey_data, &from_cache)) { 2287c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 2297c478bd9Sstevel@tonic-gate "_svcauth_des: no public key for nobody or ", 2307c478bd9Sstevel@tonic-gate cred->adc_fullname.name); 23161961e0fSrobinson (void) mutex_unlock(&authdes_lock); 2327c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* no key */ 23361961e0fSrobinson } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * found a public key for nobody. change 2377c478bd9Sstevel@tonic-gate * the fullname id to nobody, so the caller 2387c478bd9Sstevel@tonic-gate * thinks the client specified nobody 2397c478bd9Sstevel@tonic-gate * as the user identity. 2407c478bd9Sstevel@tonic-gate */ 24161961e0fSrobinson (void) strcpy(cred->adc_fullname.name, "nobody"); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate pkey.n_bytes = pkey_data; 2447c478bd9Sstevel@tonic-gate pkey.n_len = strlen(pkey_data) + 1; 2457c478bd9Sstevel@tonic-gate if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, 2467c478bd9Sstevel@tonic-gate sessionkey) < 0) { 2477c478bd9Sstevel@tonic-gate if (from_cache) { 2487c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name); 2497c478bd9Sstevel@tonic-gate goto again; 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 2527c478bd9Sstevel@tonic-gate "_svcauth_des: key_decryptsessionkey failed for", 2537c478bd9Sstevel@tonic-gate cred->adc_fullname.name); 25461961e0fSrobinson (void) mutex_unlock(&authdes_lock); 2557c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* key not found */ 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 2587c478bd9Sstevel@tonic-gate sid = cred->adc_nickname; 2597c478bd9Sstevel@tonic-gate if (sid >= authdes_cachesz) { 2607c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, "_svcauth_des:", "bad nickname"); 26161961e0fSrobinson (void) mutex_unlock(&authdes_lock); 2627c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* garbled credential */ 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate /* actually check that the entry is not null */ 2657c478bd9Sstevel@tonic-gate entry = &_rpc_authdes_cache[sid]; 2667c478bd9Sstevel@tonic-gate if (entry->rname == NULL) { 26761961e0fSrobinson (void) mutex_unlock(&authdes_lock); 2687c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* cached out */ 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate sessionkey = &_rpc_authdes_cache[sid].key; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Decrypt the timestamp 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate cryptbuf[0] = verf.adv_xtimestamp; 2777c478bd9Sstevel@tonic-gate if (fullname_rcvd) { /* ADN_FULLNAME */ 2787c478bd9Sstevel@tonic-gate cryptbuf[1].key.high = cred->adc_fullname.window; 2797c478bd9Sstevel@tonic-gate cryptbuf[1].key.low = verf.adv_winverf; 2807c478bd9Sstevel@tonic-gate ivec.key.high = ivec.key.low = 0; 2817c478bd9Sstevel@tonic-gate status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 2827c478bd9Sstevel@tonic-gate 2 * (int)sizeof (des_block), DES_DECRYPT | DES_HW, 2837c478bd9Sstevel@tonic-gate (char *)&ivec); 2847c478bd9Sstevel@tonic-gate } else { 2857c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 2867c478bd9Sstevel@tonic-gate (int)sizeof (des_block), DES_DECRYPT | DES_HW); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) { 2897c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) { 2907c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name); 2917c478bd9Sstevel@tonic-gate goto again; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate __msgout(LOG_ERR, "_svcauth_des: DES decryption failure for", 2947c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 2957c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 29661961e0fSrobinson (void) mutex_unlock(&authdes_lock); 2977c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */ 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * XDR the decrypted timestamp 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf; 3047c478bd9Sstevel@tonic-gate timestamp.tv_sec = IXDR_GET_INT32(ixdr); 3057c478bd9Sstevel@tonic-gate timestamp.tv_usec = IXDR_GET_INT32(ixdr); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * Check for valid credentials and verifiers. 3097c478bd9Sstevel@tonic-gate * They could be invalid because the key was flushed 3107c478bd9Sstevel@tonic-gate * out of the cache, and so a new session should begin. 3117c478bd9Sstevel@tonic-gate * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate struct timeval current; 3157c478bd9Sstevel@tonic-gate int nick; 3167c478bd9Sstevel@tonic-gate int winverf; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (fullname_rcvd) { 3197c478bd9Sstevel@tonic-gate window = IXDR_GET_U_INT32(ixdr); 3207c478bd9Sstevel@tonic-gate winverf = IXDR_GET_U_INT32(ixdr); 3217c478bd9Sstevel@tonic-gate if (winverf != window - 1) { 3227c478bd9Sstevel@tonic-gate if (from_cache) { 3237c478bd9Sstevel@tonic-gate __getpublickey_flush( 3247c478bd9Sstevel@tonic-gate cred->adc_fullname.name); 3257c478bd9Sstevel@tonic-gate goto again; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 3287c478bd9Sstevel@tonic-gate "_svcauth_des: corrupted window from", 3297c478bd9Sstevel@tonic-gate cred->adc_fullname.name); 33061961e0fSrobinson (void) mutex_unlock(&authdes_lock); 3317c478bd9Sstevel@tonic-gate /* garbled credential or invalid secret key */ 3327c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate cache_spot_id = cache_spot(sessionkey, 3357c478bd9Sstevel@tonic-gate cred->adc_fullname.name, 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate ×tamp); 3387c478bd9Sstevel@tonic-gate if (cache_spot_id < 0) { 3397c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 3407c478bd9Sstevel@tonic-gate "_svcauth_des: replayed credential from", 3417c478bd9Sstevel@tonic-gate cred->adc_fullname.name); 34261961e0fSrobinson (void) mutex_unlock(&authdes_lock); 3437c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDCRED); /* replay */ 3447c478bd9Sstevel@tonic-gate } else sid = cache_spot_id; 3457c478bd9Sstevel@tonic-gate nick = 0; 3467c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 3477c478bd9Sstevel@tonic-gate window = _rpc_authdes_cache[sid].window; 3487c478bd9Sstevel@tonic-gate nick = 1; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if ((ulong_t)timestamp.tv_usec >= USEC_PER_SEC) { 3527c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) { 3537c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name); 3547c478bd9Sstevel@tonic-gate goto again; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 3577c478bd9Sstevel@tonic-gate "_svcauth_des: invalid timestamp received from", 3587c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 3597c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 3607c478bd9Sstevel@tonic-gate /* cached out (bad key), or garbled verifier */ 36161961e0fSrobinson (void) mutex_unlock(&authdes_lock); 3627c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate if (nick && BEFORE(×tamp, 3657c478bd9Sstevel@tonic-gate &_rpc_authdes_cache[sid].laststamp)) { 3667c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) { 3677c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name); 3687c478bd9Sstevel@tonic-gate goto again; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 3717c478bd9Sstevel@tonic-gate "_svcauth_des: timestamp is earlier than the one previously seen from", 3727c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 3737c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 37461961e0fSrobinson (void) mutex_unlock(&authdes_lock); 3757c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDVERF); /* replay */ 3767c478bd9Sstevel@tonic-gate } 37761961e0fSrobinson (void) gettimeofday(¤t, NULL); 3787c478bd9Sstevel@tonic-gate current.tv_sec -= window; /* allow for expiration */ 3797c478bd9Sstevel@tonic-gate if (!BEFORE(¤t, ×tamp)) { 3807c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) { 3817c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name); 3827c478bd9Sstevel@tonic-gate goto again; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, 3857c478bd9Sstevel@tonic-gate "_svcauth_des: timestamp expired for", 3867c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 3877c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 3887c478bd9Sstevel@tonic-gate /* replay, or garbled credential */ 38961961e0fSrobinson (void) mutex_unlock(&authdes_lock); 3907c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * Set up the reply verifier 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate verf.adv_nickname = sid; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * xdr the timestamp before encrypting 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf; 4037c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_sec - 1); 4047c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_usec); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * encrypt the timestamp 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 4107c478bd9Sstevel@tonic-gate (int)sizeof (des_block), DES_ENCRYPT | DES_HW); 4117c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) { 4127c478bd9Sstevel@tonic-gate __msgout(LOG_ERR, "_svcauth_des: DES encryption failure for", 4137c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 4147c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 41561961e0fSrobinson (void) mutex_unlock(&authdes_lock); 4167c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */ 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate verf.adv_xtimestamp = cryptbuf[0]; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * Serialize the reply verifier, and update rqst 4227c478bd9Sstevel@tonic-gate */ 42361961e0fSrobinson /* LINTED pointer cast */ 4247c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 4257c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.high; 4267c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.low; 4277c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_int_u; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 4307c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 4317c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length = 4327c478bd9Sstevel@tonic-gate (char *)ixdr - msg->rm_call.cb_verf.oa_base; 4337c478bd9Sstevel@tonic-gate if (rqst->rq_xprt->xp_verf.oa_length > MAX_AUTH_BYTES) { 4347c478bd9Sstevel@tonic-gate __msgout(LOG_ERR, 4357c478bd9Sstevel@tonic-gate "_svcauth_des: Authenticator length error", 4367c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name : 4377c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname); 43861961e0fSrobinson (void) mutex_unlock(&authdes_lock); 4397c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDVERF); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * We succeeded, commit the data to the cache now and 4447c478bd9Sstevel@tonic-gate * finish cooking the credential. 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate entry = &_rpc_authdes_cache[sid]; 4477c478bd9Sstevel@tonic-gate entry->laststamp = timestamp; 4487c478bd9Sstevel@tonic-gate cache_ref(sid); 4497c478bd9Sstevel@tonic-gate if (cred->adc_namekind == ADN_FULLNAME) { 4507c478bd9Sstevel@tonic-gate cred->adc_fullname.window = window; 4517c478bd9Sstevel@tonic-gate cred->adc_nickname = sid; /* save nickname */ 45261961e0fSrobinson if (entry->rname != NULL) 45361961e0fSrobinson free(entry->rname); 45461961e0fSrobinson entry->rname = malloc(strlen(cred->adc_fullname.name) + 1); 4557c478bd9Sstevel@tonic-gate if (entry->rname != NULL) { 4567c478bd9Sstevel@tonic-gate (void) strcpy(entry->rname, cred->adc_fullname.name); 4577c478bd9Sstevel@tonic-gate } else { 4587c478bd9Sstevel@tonic-gate __msgout(LOG_CRIT, "_svcauth_des:", "out of memory"); 45961961e0fSrobinson (void) mutex_unlock(&authdes_lock); 4607c478bd9Sstevel@tonic-gate return (AUTH_FAILED); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate entry->key = *sessionkey; 4637c478bd9Sstevel@tonic-gate entry->window = window; 4647c478bd9Sstevel@tonic-gate /* mark any cached cred invalid */ 4657c478bd9Sstevel@tonic-gate invalidate(entry->localcred); 4667c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * nicknames are cooked into fullnames 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate cred->adc_namekind = ADN_FULLNAME; 4717c478bd9Sstevel@tonic-gate cred->adc_fullname.name = entry->rname; 4727c478bd9Sstevel@tonic-gate cred->adc_fullname.key = entry->key; 4737c478bd9Sstevel@tonic-gate cred->adc_fullname.window = entry->window; 4747c478bd9Sstevel@tonic-gate } 47561961e0fSrobinson (void) mutex_unlock(&authdes_lock); 4767c478bd9Sstevel@tonic-gate return (AUTH_OK); /* we made it! */ 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * Initialize the cache 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate static int 48461961e0fSrobinson cache_init(void) 4857c478bd9Sstevel@tonic-gate { 4867c478bd9Sstevel@tonic-gate int i; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */ 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock)); 49161961e0fSrobinson _rpc_authdes_cache = 49261961e0fSrobinson malloc(sizeof (struct cache_entry) * authdes_cachesz); 4937c478bd9Sstevel@tonic-gate if (_rpc_authdes_cache == NULL) { 4947c478bd9Sstevel@tonic-gate __msgout(LOG_CRIT, "cache_init:", "out of memory"); 4957c478bd9Sstevel@tonic-gate return (-1); 4967c478bd9Sstevel@tonic-gate } 49761961e0fSrobinson (void) memset(_rpc_authdes_cache, 0, 4987c478bd9Sstevel@tonic-gate sizeof (struct cache_entry) * authdes_cachesz); 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Initialize the lru chain (linked-list) 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate for (i = 1; i < (authdes_cachesz - 1); i++) { 5047c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].index = i; 5057c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].next = &_rpc_authdes_cache[i + 1]; 5067c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].prev = &_rpc_authdes_cache[i - 1]; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate cache_head = &_rpc_authdes_cache[0]; 5097c478bd9Sstevel@tonic-gate cache_tail = &_rpc_authdes_cache[authdes_cachesz - 1]; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* 5127c478bd9Sstevel@tonic-gate * These elements of the chain need special attention... 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate cache_head->index = 0; 5157c478bd9Sstevel@tonic-gate cache_tail->index = authdes_cachesz - 1; 5167c478bd9Sstevel@tonic-gate cache_head->next = &_rpc_authdes_cache[1]; 5177c478bd9Sstevel@tonic-gate cache_head->prev = cache_tail; 5187c478bd9Sstevel@tonic-gate cache_tail->next = cache_head; 5197c478bd9Sstevel@tonic-gate cache_tail->prev = &_rpc_authdes_cache[authdes_cachesz - 2]; 5207c478bd9Sstevel@tonic-gate return (0); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Find the lru victim 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate static uint32_t 52861961e0fSrobinson cache_victim(void) 5297c478bd9Sstevel@tonic-gate { 5307c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */ 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock)); 5337c478bd9Sstevel@tonic-gate return (cache_head->index); /* list in lru order */ 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * Note that sid was referenced 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate static void 5407c478bd9Sstevel@tonic-gate cache_ref(uint32_t sid) 5417c478bd9Sstevel@tonic-gate { 5427c478bd9Sstevel@tonic-gate struct cache_entry *curr = &_rpc_authdes_cache[sid]; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */ 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock)); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * move referenced item from its place on the LRU chain 5517c478bd9Sstevel@tonic-gate * to the tail of the chain while checking for special 5527c478bd9Sstevel@tonic-gate * conditions (mainly for performance). 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate if (cache_tail == curr) { /* no work to do */ 5557c478bd9Sstevel@tonic-gate /*EMPTY*/; 5567c478bd9Sstevel@tonic-gate } else if (cache_head == curr) { 5577c478bd9Sstevel@tonic-gate cache_head = cache_head->next; 5587c478bd9Sstevel@tonic-gate cache_tail = curr; 5597c478bd9Sstevel@tonic-gate } else { 5607c478bd9Sstevel@tonic-gate (curr->next)->prev = curr->prev; /* fix thy neighbor */ 5617c478bd9Sstevel@tonic-gate (curr->prev)->next = curr->next; 5627c478bd9Sstevel@tonic-gate curr->next = cache_head; /* fix thy self... */ 5637c478bd9Sstevel@tonic-gate curr->prev = cache_tail; 5647c478bd9Sstevel@tonic-gate cache_head->prev = curr; /* fix the head */ 5657c478bd9Sstevel@tonic-gate cache_tail->next = curr; /* fix the tail */ 5667c478bd9Sstevel@tonic-gate cache_tail = curr; /* move the tail */ 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * Find a spot in the cache for a credential containing 5727c478bd9Sstevel@tonic-gate * the items given. Return -1 if a replay is detected, otherwise 5737c478bd9Sstevel@tonic-gate * return the spot in the cache. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate static int 5767c478bd9Sstevel@tonic-gate cache_spot(des_block *key, char *name, struct timeval *timestamp) 5777c478bd9Sstevel@tonic-gate { 5787c478bd9Sstevel@tonic-gate struct cache_entry *cp; 5797c478bd9Sstevel@tonic-gate int i; 5807c478bd9Sstevel@tonic-gate uint32_t hi; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */ 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock)); 5857c478bd9Sstevel@tonic-gate hi = key->key.high; 5867c478bd9Sstevel@tonic-gate for (cp = _rpc_authdes_cache, i = 0; i < authdes_cachesz; i++, cp++) { 5877c478bd9Sstevel@tonic-gate if (cp->key.key.high == hi && 5887c478bd9Sstevel@tonic-gate cp->key.key.low == key->key.low && 5897c478bd9Sstevel@tonic-gate cp->rname != NULL && 5907c478bd9Sstevel@tonic-gate memcmp(cp->rname, name, strlen(name) + 1) == 0) { 5917c478bd9Sstevel@tonic-gate if (BEFORE(timestamp, &cp->laststamp)) { 5927c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachereplays++; 5937c478bd9Sstevel@tonic-gate return (-1); /* replay */ 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachehits++; 5967c478bd9Sstevel@tonic-gate return (i); 5977c478bd9Sstevel@tonic-gate /* refresh */ 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachemisses++; 60161961e0fSrobinson return (cache_victim()); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * Local credential handling stuff. 6077c478bd9Sstevel@tonic-gate * NOTE: bsd unix dependent. 6087c478bd9Sstevel@tonic-gate * Other operating systems should put something else here. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate #define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ 6117c478bd9Sstevel@tonic-gate #define INVALID -1 /* grouplen, if cache entry is invalid */ 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate struct bsdcred { 6147c478bd9Sstevel@tonic-gate uid_t uid; /* cached uid */ 6157c478bd9Sstevel@tonic-gate gid_t gid; /* cached gid */ 6167c478bd9Sstevel@tonic-gate short grouplen; /* length of cached groups */ 61767dbe2beSCasper H.S. Dik gid_t groups[1]; /* cached groups allocate _SC_NGROUPS_MAX */ 6187c478bd9Sstevel@tonic-gate }; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate static void 6217c478bd9Sstevel@tonic-gate invalidate(char *cred) 6227c478bd9Sstevel@tonic-gate { 62361961e0fSrobinson if (cred == NULL) 6247c478bd9Sstevel@tonic-gate return; 62561961e0fSrobinson /* LINTED pointer cast */ 6267c478bd9Sstevel@tonic-gate ((struct bsdcred *)cred)->grouplen = INVALID; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * Map a des credential into a unix cred. 6317c478bd9Sstevel@tonic-gate * We cache the credential here so the application does 6327c478bd9Sstevel@tonic-gate * not have to make an rpc call every time to interpret 6337c478bd9Sstevel@tonic-gate * the credential. 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate int 6367c478bd9Sstevel@tonic-gate authdes_getucred(const struct authdes_cred *adc, uid_t *uid, gid_t *gid, 6377c478bd9Sstevel@tonic-gate short *grouplen, gid_t *groups) 6387c478bd9Sstevel@tonic-gate { 6397c478bd9Sstevel@tonic-gate uint32_t sid; 6407c478bd9Sstevel@tonic-gate int i; 6417c478bd9Sstevel@tonic-gate uid_t i_uid; 6427c478bd9Sstevel@tonic-gate gid_t i_gid; 6437c478bd9Sstevel@tonic-gate int i_grouplen; 6447c478bd9Sstevel@tonic-gate struct bsdcred *cred; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate sid = adc->adc_nickname; 6477c478bd9Sstevel@tonic-gate if (sid >= authdes_cachesz) { 6487c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "invalid nickname"); 6497c478bd9Sstevel@tonic-gate return (0); 6507c478bd9Sstevel@tonic-gate } 65161961e0fSrobinson (void) mutex_lock(&authdes_lock); 65261961e0fSrobinson /* LINTED pointer cast */ 6537c478bd9Sstevel@tonic-gate cred = (struct bsdcred *)_rpc_authdes_cache[sid].localcred; 6547c478bd9Sstevel@tonic-gate if (cred == NULL) { 65567dbe2beSCasper H.S. Dik static size_t bsdcred_sz; 65667dbe2beSCasper H.S. Dik 65767dbe2beSCasper H.S. Dik if (bsdcred_sz == 0) { 65867dbe2beSCasper H.S. Dik bsdcred_sz = sizeof (struct bsdcred) + 65967dbe2beSCasper H.S. Dik (sysconf(_SC_NGROUPS_MAX) - 1) * sizeof (gid_t); 66067dbe2beSCasper H.S. Dik } 66167dbe2beSCasper H.S. Dik cred = malloc(bsdcred_sz); 6627c478bd9Sstevel@tonic-gate if (cred == NULL) { 6637c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "out of memory"); 66461961e0fSrobinson (void) mutex_unlock(&authdes_lock); 6657c478bd9Sstevel@tonic-gate return (0); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].localcred = (char *)cred; 6687c478bd9Sstevel@tonic-gate cred->grouplen = INVALID; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate if (cred->grouplen == INVALID) { 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * not in cache: lookup 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate if (!netname2user(adc->adc_fullname.name, (uid_t *)&i_uid, 6757c478bd9Sstevel@tonic-gate (gid_t *)&i_gid, &i_grouplen, (gid_t *)groups)) { 6767c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "unknown netname"); 6777c478bd9Sstevel@tonic-gate /* mark as lookup up, but not found */ 6787c478bd9Sstevel@tonic-gate cred->grouplen = UNKNOWN; 67961961e0fSrobinson (void) mutex_unlock(&authdes_lock); 6807c478bd9Sstevel@tonic-gate return (0); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "missed ucred cache"); 6837c478bd9Sstevel@tonic-gate *uid = cred->uid = i_uid; 6847c478bd9Sstevel@tonic-gate *gid = cred->gid = i_gid; 6857c478bd9Sstevel@tonic-gate *grouplen = cred->grouplen = i_grouplen; 6867c478bd9Sstevel@tonic-gate for (i = i_grouplen - 1; i >= 0; i--) { 68767dbe2beSCasper H.S. Dik cred->groups[i] = groups[i]; 6887c478bd9Sstevel@tonic-gate } 68961961e0fSrobinson (void) mutex_unlock(&authdes_lock); 6907c478bd9Sstevel@tonic-gate return (1); 69161961e0fSrobinson } 69261961e0fSrobinson if (cred->grouplen == UNKNOWN) { 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Already lookup up, but no match found 6957c478bd9Sstevel@tonic-gate */ 69661961e0fSrobinson (void) mutex_unlock(&authdes_lock); 6977c478bd9Sstevel@tonic-gate return (0); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * cached credentials 7027c478bd9Sstevel@tonic-gate */ 7037c478bd9Sstevel@tonic-gate *uid = cred->uid; 7047c478bd9Sstevel@tonic-gate *gid = cred->gid; 7057c478bd9Sstevel@tonic-gate *grouplen = cred->grouplen; 7067c478bd9Sstevel@tonic-gate for (i = cred->grouplen - 1; i >= 0; i--) { 70767dbe2beSCasper H.S. Dik groups[i] = cred->groups[i]; 7087c478bd9Sstevel@tonic-gate } 70961961e0fSrobinson (void) mutex_unlock(&authdes_lock); 7107c478bd9Sstevel@tonic-gate return (1); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate static void 7157c478bd9Sstevel@tonic-gate __msgout(int level, const char *str, const char *strarg) 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate (void) syslog(level, "%s %s", str, strarg); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate static void 7227c478bd9Sstevel@tonic-gate __msgout2(const char *str, const char *str2) 7237c478bd9Sstevel@tonic-gate { 7247c478bd9Sstevel@tonic-gate (void) syslog(LOG_DEBUG, "%s %s", str, str2); 7257c478bd9Sstevel@tonic-gate } 726