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
__svcauth_des(struct svc_req * rqst,struct rpc_msg * msg)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
cache_init(void)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
cache_victim(void)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
cache_ref(uint32_t sid)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
cache_spot(des_block * key,char * name,struct timeval * timestamp)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
invalidate(char * cred)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
authdes_getucred(const struct authdes_cred * adc,uid_t * uid,gid_t * gid,short * grouplen,gid_t * groups)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
__msgout(int level,const char * str,const char * strarg)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
__msgout2(const char * str,const char * str2)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