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 5f48205beScasper * Common Development and Distribution License (the "License"). 6f48205beScasper * 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 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*4b3b7fc6SAlex Wilson * Copyright 2017 Joyent Inc 2367dbe2beSCasper H.S. Dik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 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 /* 317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of 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 #include <sys/types.h> 497c478bd9Sstevel@tonic-gate #include <sys/time.h> 507c478bd9Sstevel@tonic-gate #include <sys/systm.h> 517c478bd9Sstevel@tonic-gate #include <sys/param.h> 527c478bd9Sstevel@tonic-gate #include <sys/stream.h> 537c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 547c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 557c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 567c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 577c478bd9Sstevel@tonic-gate #include <sys/t_kuser.h> 587c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 597c478bd9Sstevel@tonic-gate #include <sys/debug.h> 607c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 617c478bd9Sstevel@tonic-gate #include <sys/time.h> 627c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 63*4b3b7fc6SAlex Wilson #include <sys/debug.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <rpc/types.h> 667c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 677c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 687c478bd9Sstevel@tonic-gate #include <rpc/auth_des.h> 697c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 707c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 717c478bd9Sstevel@tonic-gate #include <rpc/svc_auth.h> 727c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 737c478bd9Sstevel@tonic-gate #include <rpc/des_crypt.h> 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define USEC_PER_SEC 1000000 767c478bd9Sstevel@tonic-gate #define BEFORE(t1, t2) timercmp(t1, t2, < /* COMMENT HERE TO DEFEAT CSTYLE */) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Cache of conversation keys and some other useful items. 807c478bd9Sstevel@tonic-gate * The hash table size is controled via authdes_cachesz variable. 817c478bd9Sstevel@tonic-gate * The authdes_cachesz has to be the power of 2. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate #define AUTHDES_CACHE_TABLE_SZ 1024 847c478bd9Sstevel@tonic-gate static int authdes_cachesz = AUTHDES_CACHE_TABLE_SZ; 857c478bd9Sstevel@tonic-gate #define HASH(key) ((key) & (authdes_cachesz - 1)) 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* low water mark for the number of cache entries */ 887c478bd9Sstevel@tonic-gate static int low_cache_entries = 128; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate struct authdes_cache_entry { 917c478bd9Sstevel@tonic-gate uint32_t nickname; /* nick name id */ 927c478bd9Sstevel@tonic-gate uint32_t window; /* credential lifetime window */ 937c478bd9Sstevel@tonic-gate des_block key; /* conversation key */ 947c478bd9Sstevel@tonic-gate time_t ref_time; /* time referenced previously */ 957c478bd9Sstevel@tonic-gate char *rname; /* client's name */ 967c478bd9Sstevel@tonic-gate caddr_t localcred; /* generic local credential */ 977c478bd9Sstevel@tonic-gate struct authdes_cache_entry *prev, *next; /* hash table linked list */ 987c478bd9Sstevel@tonic-gate struct authdes_cache_entry *lru_prev, *lru_next; /* LRU linked list */ 997c478bd9Sstevel@tonic-gate kmutex_t lock; /* cache entry lock */ 1007c478bd9Sstevel@tonic-gate }; 1017c478bd9Sstevel@tonic-gate static struct authdes_cache_entry **authdes_cache; /* [authdes_cachesz] */ 1027c478bd9Sstevel@tonic-gate static struct authdes_cache_entry *lru_first = NULL; 1037c478bd9Sstevel@tonic-gate static struct authdes_cache_entry *lru_last = NULL; 1047c478bd9Sstevel@tonic-gate static kmutex_t authdes_lock; /* cache table lock */ 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate static struct kmem_cache *authdes_cache_handle; 1077c478bd9Sstevel@tonic-gate static uint32_t Nickname = 0; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate static struct authdes_cache_entry *authdes_cache_new(char *, 1107c478bd9Sstevel@tonic-gate des_block *, uint32_t); 1117c478bd9Sstevel@tonic-gate static struct authdes_cache_entry *authdes_cache_get(uint32_t); 1127c478bd9Sstevel@tonic-gate static void authdes_cache_reclaim(void *); 1137c478bd9Sstevel@tonic-gate static void sweep_cache(); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* 1167c478bd9Sstevel@tonic-gate * After 12 hours, check and delete cache entries that have been 1177c478bd9Sstevel@tonic-gate * idled for more than 10 hours. 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate static time_t authdes_sweep_interval = 12*60*60; 1207c478bd9Sstevel@tonic-gate static time_t authdes_cache_time = 10*60*60; 1217c478bd9Sstevel@tonic-gate static time_t authdes_last_swept = 0; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * cache statistics 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate static int authdes_ncache = 0; /* number of current cached entries */ 1277c478bd9Sstevel@tonic-gate static int authdes_ncachehits = 0; /* #times cache hit */ 1287c478bd9Sstevel@tonic-gate static int authdes_ncachemisses = 0; /* #times cache missed */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate #define NOT_DEAD(ptr) ASSERT((((intptr_t)(ptr)) != 0xdeadbeef)) 1317c478bd9Sstevel@tonic-gate #define IS_ALIGNED(ptr) ASSERT((((intptr_t)(ptr)) & 3) == 0) 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Service side authenticator for AUTH_DES 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate enum auth_stat 1377c478bd9Sstevel@tonic-gate _svcauth_des(struct svc_req *rqst, struct rpc_msg *msg) 1387c478bd9Sstevel@tonic-gate { 1397c478bd9Sstevel@tonic-gate int32_t *ixdr; 1407c478bd9Sstevel@tonic-gate des_block cryptbuf[2]; 1417c478bd9Sstevel@tonic-gate struct authdes_cred *cred; 1427c478bd9Sstevel@tonic-gate struct authdes_verf verf; 1437c478bd9Sstevel@tonic-gate int status; 1447c478bd9Sstevel@tonic-gate des_block *sessionkey; 1457c478bd9Sstevel@tonic-gate des_block ivec; 1467c478bd9Sstevel@tonic-gate uint32_t window, winverf, namelen; 1477c478bd9Sstevel@tonic-gate bool_t nick; 1487c478bd9Sstevel@tonic-gate struct timeval timestamp, current_time; 1497c478bd9Sstevel@tonic-gate struct authdes_cache_entry *nick_entry; 1507c478bd9Sstevel@tonic-gate struct area { 1517c478bd9Sstevel@tonic-gate struct authdes_cred area_cred; 1527c478bd9Sstevel@tonic-gate char area_netname[MAXNETNAMELEN+1]; 1537c478bd9Sstevel@tonic-gate } *area; 1547c478bd9Sstevel@tonic-gate timestruc_t now; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 1577c478bd9Sstevel@tonic-gate if (authdes_cache == NULL) { 1587c478bd9Sstevel@tonic-gate authdes_cache = kmem_zalloc( 1597c478bd9Sstevel@tonic-gate sizeof (struct authdes_cache_entry *) * authdes_cachesz, 1607c478bd9Sstevel@tonic-gate KM_SLEEP); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 1637c478bd9Sstevel@tonic-gate 164*4b3b7fc6SAlex Wilson CTASSERT(sizeof (struct area) <= RQCRED_SIZE); 1657c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1667c478bd9Sstevel@tonic-gate area = (struct area *)rqst->rq_clntcred; 1677c478bd9Sstevel@tonic-gate cred = (struct authdes_cred *)&area->area_cred; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Get the credential 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1737c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_cred.oa_base; 1747c478bd9Sstevel@tonic-gate cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 1757c478bd9Sstevel@tonic-gate switch (cred->adc_namekind) { 1767c478bd9Sstevel@tonic-gate case ADN_FULLNAME: 1777c478bd9Sstevel@tonic-gate namelen = IXDR_GET_U_INT32(ixdr); 1787c478bd9Sstevel@tonic-gate if (namelen > MAXNETNAMELEN) 1797c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 1807c478bd9Sstevel@tonic-gate cred->adc_fullname.name = area->area_netname; 1817c478bd9Sstevel@tonic-gate bcopy(ixdr, cred->adc_fullname.name, namelen); 1827c478bd9Sstevel@tonic-gate cred->adc_fullname.name[namelen] = 0; 1837c478bd9Sstevel@tonic-gate ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 1847c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.high = (uint32_t)*ixdr++; 1857c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.low = (uint32_t)*ixdr++; 1867c478bd9Sstevel@tonic-gate cred->adc_fullname.window = (uint32_t)*ixdr++; 1877c478bd9Sstevel@tonic-gate nick = FALSE; 1887c478bd9Sstevel@tonic-gate break; 1897c478bd9Sstevel@tonic-gate case ADN_NICKNAME: 1907c478bd9Sstevel@tonic-gate cred->adc_nickname = (uint32_t)*ixdr++; 1917c478bd9Sstevel@tonic-gate nick = TRUE; 1927c478bd9Sstevel@tonic-gate break; 1937c478bd9Sstevel@tonic-gate default: 1947c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Get the verifier 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 2017c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 2027c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.high = (uint32_t)*ixdr++; 2037c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.low = (uint32_t)*ixdr++; 2047c478bd9Sstevel@tonic-gate verf.adv_int_u = (uint32_t)*ixdr++; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Get the conversation key 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate if (!nick) { /* ADN_FULLNAME */ 2117c478bd9Sstevel@tonic-gate sessionkey = &cred->adc_fullname.key; 2127c478bd9Sstevel@tonic-gate if (key_decryptsession(cred->adc_fullname.name, sessionkey) != 2137c478bd9Sstevel@tonic-gate RPC_SUCCESS) { 2147c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* key not found */ 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 2177c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 2187c478bd9Sstevel@tonic-gate if (!(nick_entry = authdes_cache_get(cred->adc_nickname))) { 2197c478bd9Sstevel@tonic-gate RPCLOG(1, "_svcauth_des: nickname %d not in the cache\n", 2207c478bd9Sstevel@tonic-gate cred->adc_nickname); 2217c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 2227c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* need refresh */ 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate sessionkey = &nick_entry->key; 2257c478bd9Sstevel@tonic-gate mutex_enter(&nick_entry->lock); 2267c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Decrypt the timestamp 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate cryptbuf[0] = verf.adv_xtimestamp; 2337c478bd9Sstevel@tonic-gate if (!nick) { /* ADN_FULLNAME */ 2347c478bd9Sstevel@tonic-gate cryptbuf[1].key.high = cred->adc_fullname.window; 2357c478bd9Sstevel@tonic-gate cryptbuf[1].key.low = verf.adv_winverf; 2367c478bd9Sstevel@tonic-gate ivec.key.high = ivec.key.low = 0; 2377c478bd9Sstevel@tonic-gate status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 2387c478bd9Sstevel@tonic-gate 2 * sizeof (des_block), DES_DECRYPT, (char *)&ivec); 2397c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 2407c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 2417c478bd9Sstevel@tonic-gate sizeof (des_block), DES_DECRYPT); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) { 2447c478bd9Sstevel@tonic-gate RPCLOG0(1, "_svcauth_des: decryption failure\n"); 2457c478bd9Sstevel@tonic-gate if (nick) { 2467c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */ 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * XDR the decrypted timestamp 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf; 2557c478bd9Sstevel@tonic-gate timestamp.tv_sec = IXDR_GET_INT32(ixdr); 2567c478bd9Sstevel@tonic-gate timestamp.tv_usec = IXDR_GET_INT32(ixdr); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Check for valid credentials and verifiers. 2607c478bd9Sstevel@tonic-gate * They could be invalid because the key was flushed 2617c478bd9Sstevel@tonic-gate * out of the cache, and so a new session should begin. 2627c478bd9Sstevel@tonic-gate * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate if (!nick) { /* ADN_FULLNAME */ 2657c478bd9Sstevel@tonic-gate window = IXDR_GET_U_INT32(ixdr); 2667c478bd9Sstevel@tonic-gate winverf = IXDR_GET_U_INT32(ixdr); 2677c478bd9Sstevel@tonic-gate if (winverf != window - 1) { 2687c478bd9Sstevel@tonic-gate RPCLOG(1, "_svcauth_des: window verifier mismatch %d\n", 2697c478bd9Sstevel@tonic-gate winverf); 2707c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* garbled credential */ 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 2737c478bd9Sstevel@tonic-gate window = nick_entry->window; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if (timestamp.tv_usec >= USEC_PER_SEC) { 2777c478bd9Sstevel@tonic-gate RPCLOG(1, "_svcauth_des: invalid usecs %ld\n", 2787c478bd9Sstevel@tonic-gate timestamp.tv_usec); 2797c478bd9Sstevel@tonic-gate /* cached out (bad key), or garbled verifier */ 2807c478bd9Sstevel@tonic-gate if (nick) { 2817c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate gethrestime(&now); 2877c478bd9Sstevel@tonic-gate current_time.tv_sec = now.tv_sec; 2887c478bd9Sstevel@tonic-gate current_time.tv_usec = now.tv_nsec / 1000; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate current_time.tv_sec -= window; /* allow for expiration */ 2917c478bd9Sstevel@tonic-gate if (!BEFORE(¤t_time, ×tamp)) { 2927c478bd9Sstevel@tonic-gate RPCLOG0(1, "_svcauth_des: timestamp expired\n"); 2937c478bd9Sstevel@tonic-gate /* replay, or garbled credential */ 2947c478bd9Sstevel@tonic-gate if (nick) { 2957c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * xdr the timestamp before encrypting 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf; 3047c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_sec - 1); 3057c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_usec); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * encrypt the timestamp 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 3117c478bd9Sstevel@tonic-gate sizeof (des_block), DES_ENCRYPT); 3127c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) { 3137c478bd9Sstevel@tonic-gate RPCLOG0(1, "_svcauth_des: encryption failure\n"); 3147c478bd9Sstevel@tonic-gate if (nick) { 3157c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */ 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate verf.adv_xtimestamp = cryptbuf[0]; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * If a ADN_FULLNAME, create a new nickname cache entry. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate if (!nick) { 3257c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 3267c478bd9Sstevel@tonic-gate if (!(nick_entry = authdes_cache_new(cred->adc_fullname.name, 3277c478bd9Sstevel@tonic-gate sessionkey, window))) { 3287c478bd9Sstevel@tonic-gate RPCLOG0(1, "_svcauth_des: can not create new cache entry\n"); 3297c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 3307c478bd9Sstevel@tonic-gate return (AUTH_FAILED); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate mutex_enter(&nick_entry->lock); 3337c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate verf.adv_nickname = nick_entry->nickname; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * Serialize the reply verifier, and update rqst 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 3417c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base; 3427c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.high; 3437c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.low; 3447c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_int_u; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 3477c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 3487c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length = 3497c478bd9Sstevel@tonic-gate (uint_t)((char *)ixdr - msg->rm_call.cb_verf.oa_base); 3507c478bd9Sstevel@tonic-gate if (rqst->rq_xprt->xp_verf.oa_length > MAX_AUTH_BYTES) { 3517c478bd9Sstevel@tonic-gate RPCLOG0(1, "_svcauth_des: invalid oa length\n"); 3527c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 3537c478bd9Sstevel@tonic-gate return (AUTH_BADVERF); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * We succeeded and finish cooking the credential. 3587c478bd9Sstevel@tonic-gate * nicknames are cooked into fullnames 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate if (!nick) { 3617c478bd9Sstevel@tonic-gate cred->adc_nickname = nick_entry->nickname; 3627c478bd9Sstevel@tonic-gate cred->adc_fullname.window = window; 3637c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */ 3647c478bd9Sstevel@tonic-gate cred->adc_namekind = ADN_FULLNAME; 3657c478bd9Sstevel@tonic-gate cred->adc_fullname.name = nick_entry->rname; 3667c478bd9Sstevel@tonic-gate cred->adc_fullname.key = nick_entry->key; 3677c478bd9Sstevel@tonic-gate cred->adc_fullname.window = nick_entry->window; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate mutex_exit(&nick_entry->lock); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * For every authdes_sweep_interval, delete cache entries that have been 3737c478bd9Sstevel@tonic-gate * idled for authdes_cache_time. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 3767c478bd9Sstevel@tonic-gate if ((gethrestime_sec() - authdes_last_swept) > authdes_sweep_interval) 3777c478bd9Sstevel@tonic-gate sweep_cache(); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate return (AUTH_OK); /* we made it! */ 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * Initialization upon loading the rpcsec module. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate void 3887c478bd9Sstevel@tonic-gate svcauthdes_init(void) 3897c478bd9Sstevel@tonic-gate { 3907c478bd9Sstevel@tonic-gate mutex_init(&authdes_lock, NULL, MUTEX_DEFAULT, NULL); 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Allocate des cache handle 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate authdes_cache_handle = kmem_cache_create("authdes_cache_handle", 3957c478bd9Sstevel@tonic-gate sizeof (struct authdes_cache_entry), 0, NULL, NULL, 3967c478bd9Sstevel@tonic-gate authdes_cache_reclaim, NULL, NULL, 0); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * Final actions upon exiting the rpcsec module. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate void 4037c478bd9Sstevel@tonic-gate svcauthdes_fini(void) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate mutex_destroy(&authdes_lock); 4067c478bd9Sstevel@tonic-gate kmem_cache_destroy(authdes_cache_handle); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Local credential handling stuff. 4117c478bd9Sstevel@tonic-gate * NOTE: bsd unix dependent. 4127c478bd9Sstevel@tonic-gate * Other operating systems should put something else here. 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate struct bsdcred { 4167c478bd9Sstevel@tonic-gate uid_t uid; /* cached uid */ 4177c478bd9Sstevel@tonic-gate gid_t gid; /* cached gid */ 4187c478bd9Sstevel@tonic-gate short valid; /* valid creds */ 4197c478bd9Sstevel@tonic-gate short grouplen; /* length of cached groups */ 42067dbe2beSCasper H.S. Dik gid_t groups[1]; /* cached groups - allocate ngroups_max */ 4217c478bd9Sstevel@tonic-gate }; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * Map a des credential into a unix cred. 4257c478bd9Sstevel@tonic-gate * We cache the credential here so the application does 4267c478bd9Sstevel@tonic-gate * not have to make an rpc call every time to interpret 4277c478bd9Sstevel@tonic-gate * the credential. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate int 4307c478bd9Sstevel@tonic-gate kauthdes_getucred(const struct authdes_cred *adc, cred_t *cr) 4317c478bd9Sstevel@tonic-gate { 4327c478bd9Sstevel@tonic-gate uid_t i_uid; 4337c478bd9Sstevel@tonic-gate gid_t i_gid; 4347c478bd9Sstevel@tonic-gate int i_grouplen; 4357c478bd9Sstevel@tonic-gate struct bsdcred *cred; 4367c478bd9Sstevel@tonic-gate struct authdes_cache_entry *nickentry; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 4397c478bd9Sstevel@tonic-gate if (!(nickentry = authdes_cache_get(adc->adc_nickname))) { 4407c478bd9Sstevel@tonic-gate RPCLOG0(1, "authdes_getucred: invalid nickname\n"); 4417c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 4427c478bd9Sstevel@tonic-gate return (0); 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate mutex_enter(&nickentry->lock); 4467c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 4477c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 4487c478bd9Sstevel@tonic-gate cred = (struct bsdcred *)nickentry->localcred; 4497c478bd9Sstevel@tonic-gate if (!cred->valid) { 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * not in cache: lookup 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate if (netname2user(adc->adc_fullname.name, &i_uid, &i_gid, 4547c478bd9Sstevel@tonic-gate &i_grouplen, &cred->groups[0]) != RPC_SUCCESS) { 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Probably a host principal, since at this 4577c478bd9Sstevel@tonic-gate * point we have valid keys. Note that later 4587c478bd9Sstevel@tonic-gate * if the principal is not in the root list 4597c478bd9Sstevel@tonic-gate * for NFS, we will be mapped to that exported 4607c478bd9Sstevel@tonic-gate * file system's anonymous user, typically 4617c478bd9Sstevel@tonic-gate * NOBODY. keyserv KEY_GETCRED will fail for a 4627c478bd9Sstevel@tonic-gate * root-netnames so we assume root here. 4637c478bd9Sstevel@tonic-gate * Currently NFS is the only caller of this 4647c478bd9Sstevel@tonic-gate * routine. If other RPC services call this 4657c478bd9Sstevel@tonic-gate * routine, it is up to that service to 4667c478bd9Sstevel@tonic-gate * differentiate between local and remote 4677c478bd9Sstevel@tonic-gate * roots. 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate i_uid = 0; 4707c478bd9Sstevel@tonic-gate i_gid = 0; 4717c478bd9Sstevel@tonic-gate i_grouplen = 0; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate RPCLOG0(2, "authdes_getucred: missed ucred cache\n"); 4747c478bd9Sstevel@tonic-gate cred->uid = i_uid; 4757c478bd9Sstevel@tonic-gate cred->gid = i_gid; 4767c478bd9Sstevel@tonic-gate cred->grouplen = (short)i_grouplen; 4777c478bd9Sstevel@tonic-gate cred->valid = 1; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * cached credentials 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate if (crsetugid(cr, cred->uid, cred->gid) != 0 || 4847c478bd9Sstevel@tonic-gate crsetgroups(cr, cred->grouplen, &cred->groups[0]) != 0) { 4857c478bd9Sstevel@tonic-gate mutex_exit(&nickentry->lock); 4867c478bd9Sstevel@tonic-gate return (0); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate mutex_exit(&nickentry->lock); 4897c478bd9Sstevel@tonic-gate return (1); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* 4937c478bd9Sstevel@tonic-gate * Create a new cache_entry and put it in authdes_cache table. 4947c478bd9Sstevel@tonic-gate * Caller should have already locked the authdes_cache table. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate struct authdes_cache_entry * 4977c478bd9Sstevel@tonic-gate authdes_cache_new(char *fullname, des_block *sessionkey, uint32_t window) { 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate struct authdes_cache_entry *new, *head; 5007c478bd9Sstevel@tonic-gate struct bsdcred *ucred; 5017c478bd9Sstevel@tonic-gate int index; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate if (!(new = kmem_cache_alloc(authdes_cache_handle, KM_SLEEP))) { 5047c478bd9Sstevel@tonic-gate return (NULL); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (!(new->rname = kmem_alloc(strlen(fullname) + 1, KM_NOSLEEP))) { 5087c478bd9Sstevel@tonic-gate kmem_cache_free(authdes_cache_handle, new); 5097c478bd9Sstevel@tonic-gate return (NULL); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 51267dbe2beSCasper H.S. Dik if (!(ucred = kmem_alloc(sizeof (struct bsdcred) + 51367dbe2beSCasper H.S. Dik (ngroups_max - 1) * sizeof (gid_t), KM_NOSLEEP))) { 5147c478bd9Sstevel@tonic-gate kmem_free(new->rname, strlen(fullname) + 1); 5157c478bd9Sstevel@tonic-gate kmem_cache_free(authdes_cache_handle, new); 5167c478bd9Sstevel@tonic-gate return (NULL); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate (void) strcpy(new->rname, fullname); 5207c478bd9Sstevel@tonic-gate ucred->valid = 0; 5217c478bd9Sstevel@tonic-gate new->localcred = (caddr_t)ucred; 5227c478bd9Sstevel@tonic-gate new->key = *sessionkey; 5237c478bd9Sstevel@tonic-gate new->window = window; 5247c478bd9Sstevel@tonic-gate new->ref_time = gethrestime_sec(); 5257c478bd9Sstevel@tonic-gate new->nickname = Nickname++; 5267c478bd9Sstevel@tonic-gate mutex_init(&new->lock, NULL, MUTEX_DEFAULT, NULL); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* put new into the hash table */ 5297c478bd9Sstevel@tonic-gate index = HASH(new->nickname); 5307c478bd9Sstevel@tonic-gate head = authdes_cache[index]; 5317c478bd9Sstevel@tonic-gate if ((new->next = head) != NULL) { 5327c478bd9Sstevel@tonic-gate head->prev = new; 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate authdes_cache[index] = new; 5357c478bd9Sstevel@tonic-gate new->prev = NULL; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* update the LRU list */ 5387c478bd9Sstevel@tonic-gate new->lru_prev = NULL; 5397c478bd9Sstevel@tonic-gate if ((new->lru_next = lru_first) != NULL) { 5407c478bd9Sstevel@tonic-gate lru_first->lru_prev = new; 5417c478bd9Sstevel@tonic-gate } else { 5427c478bd9Sstevel@tonic-gate lru_last = new; 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate lru_first = new; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate authdes_ncache++; 5477c478bd9Sstevel@tonic-gate return (new); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * Get an existing cache entry from authdes_cache table. 5527c478bd9Sstevel@tonic-gate * The caller should have locked the authdes_cache table. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate struct authdes_cache_entry * 5557c478bd9Sstevel@tonic-gate authdes_cache_get(uint32_t nickname) { 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate struct authdes_cache_entry *cur = NULL; 5587c478bd9Sstevel@tonic-gate int index = HASH(nickname); 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&authdes_lock)); 5617c478bd9Sstevel@tonic-gate for (cur = authdes_cache[index]; cur; cur = cur->next) { 5627c478bd9Sstevel@tonic-gate if ((cur->nickname == nickname)) { 5637c478bd9Sstevel@tonic-gate /* find it, update the LRU list */ 5647c478bd9Sstevel@tonic-gate if (cur != lru_first) { 5657c478bd9Sstevel@tonic-gate cur->lru_prev->lru_next = cur->lru_next; 5667c478bd9Sstevel@tonic-gate if (cur->lru_next != NULL) { 5677c478bd9Sstevel@tonic-gate cur->lru_next->lru_prev = cur->lru_prev; 5687c478bd9Sstevel@tonic-gate } else { 5697c478bd9Sstevel@tonic-gate lru_last = cur->lru_prev; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate cur->lru_prev = NULL; 5727c478bd9Sstevel@tonic-gate cur->lru_next = lru_first; 5737c478bd9Sstevel@tonic-gate lru_first->lru_prev = cur; 5747c478bd9Sstevel@tonic-gate lru_first = cur; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate cur->ref_time = gethrestime_sec(); 5787c478bd9Sstevel@tonic-gate authdes_ncachehits++; 5797c478bd9Sstevel@tonic-gate return (cur); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate authdes_ncachemisses++; 5847c478bd9Sstevel@tonic-gate return (NULL); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * authdes_cache_reclaim() is called by the kernel memory allocator 5897c478bd9Sstevel@tonic-gate * when memory is low. This routine will reclaim 25% of the least recent 5907c478bd9Sstevel@tonic-gate * used cache entries above the low water mark (low_cache_entries). 5917c478bd9Sstevel@tonic-gate * If the cache entries have already hit the low water mark, it will 5927c478bd9Sstevel@tonic-gate * return 1 cache entry. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5957c478bd9Sstevel@tonic-gate void 5967c478bd9Sstevel@tonic-gate authdes_cache_reclaim(void *pdata) { 5977c478bd9Sstevel@tonic-gate struct authdes_cache_entry *p; 5987c478bd9Sstevel@tonic-gate int n, i; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate mutex_enter(&authdes_lock); 6017c478bd9Sstevel@tonic-gate n = authdes_ncache - low_cache_entries; 6027c478bd9Sstevel@tonic-gate n = n > 0 ? n/4 : 1; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 6057c478bd9Sstevel@tonic-gate if ((p = lru_last) == lru_first) 6067c478bd9Sstevel@tonic-gate break; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* Update the hash linked list */ 6097c478bd9Sstevel@tonic-gate if (p->prev == NULL) { 6107c478bd9Sstevel@tonic-gate authdes_cache[HASH(p->nickname)] = p->next; 6117c478bd9Sstevel@tonic-gate } else { 6127c478bd9Sstevel@tonic-gate p->prev->next = p->next; 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate if (p->next != NULL) { 6157c478bd9Sstevel@tonic-gate p->next->prev = p->prev; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* update the LRU linked list */ 6197c478bd9Sstevel@tonic-gate p->lru_prev->lru_next = NULL; 6207c478bd9Sstevel@tonic-gate lru_last = p->lru_prev; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate kmem_free(p->rname, strlen(p->rname) + 1); 62367dbe2beSCasper H.S. Dik kmem_free(p->localcred, sizeof (struct bsdcred) + 62467dbe2beSCasper H.S. Dik (ngroups_max - 1) * sizeof (gid_t)); 6257c478bd9Sstevel@tonic-gate mutex_destroy(&p->lock); 6267c478bd9Sstevel@tonic-gate kmem_cache_free(authdes_cache_handle, p); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate authdes_ncache--; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate mutex_exit(&authdes_lock); 6317c478bd9Sstevel@tonic-gate RPCLOG(4, "_svcauth_des: %d cache entries reclaimed...\n", 6327c478bd9Sstevel@tonic-gate authdes_ncache); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * Walk through the LRU doubly-linked list and delete the cache 6377c478bd9Sstevel@tonic-gate * entries that have not been used for more than authdes_cache_time. 6387c478bd9Sstevel@tonic-gate * 6397c478bd9Sstevel@tonic-gate * Caller should have locked the cache table. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate void 6427c478bd9Sstevel@tonic-gate sweep_cache() { 6437c478bd9Sstevel@tonic-gate struct authdes_cache_entry *p; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&authdes_lock)); 6467c478bd9Sstevel@tonic-gate while ((p = lru_last) != lru_first) { 6477c478bd9Sstevel@tonic-gate IS_ALIGNED(p); 6487c478bd9Sstevel@tonic-gate NOT_DEAD(p); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 6517c478bd9Sstevel@tonic-gate * If the last LRU entry idled less than authdes_cache_time, 6527c478bd9Sstevel@tonic-gate * we are done with the sweeping. 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate if (p->ref_time + authdes_cache_time > gethrestime_sec()) 6557c478bd9Sstevel@tonic-gate break; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* update the hash linked list */ 6587c478bd9Sstevel@tonic-gate if (p->prev == NULL) { 6597c478bd9Sstevel@tonic-gate authdes_cache[HASH(p->nickname)] = p->next; 6607c478bd9Sstevel@tonic-gate } else { 6617c478bd9Sstevel@tonic-gate p->prev->next = p->next; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate if (p->next != NULL) { 6647c478bd9Sstevel@tonic-gate p->next->prev = p->prev; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* update the LRU linked list */ 6687c478bd9Sstevel@tonic-gate p->lru_prev->lru_next = NULL; 6697c478bd9Sstevel@tonic-gate lru_last = p->lru_prev; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate kmem_free(p->rname, strlen(p->rname) + 1); 67267dbe2beSCasper H.S. Dik kmem_free(p->localcred, sizeof (struct bsdcred) + 67367dbe2beSCasper H.S. Dik (ngroups_max - 1) * sizeof (gid_t)); 6747c478bd9Sstevel@tonic-gate mutex_destroy(&p->lock); 6757c478bd9Sstevel@tonic-gate kmem_cache_free(authdes_cache_handle, p); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate authdes_ncache--; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate authdes_last_swept = gethrestime_sec(); 6817c478bd9Sstevel@tonic-gate RPCLOG(4, "_svcauth_des: sweeping cache...#caches left = %d\n", 6827c478bd9Sstevel@tonic-gate authdes_ncache); 6837c478bd9Sstevel@tonic-gate } 684