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.
2548bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
26*b1cdc720SAlex Wilson * Copyright 2017 Joyent Inc
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
297c478bd9Sstevel@tonic-gate /* All Rights Reserved */
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley
327c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of
337c478bd9Sstevel@tonic-gate * California.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * svcauth_des.c, server-side des authentication
387c478bd9Sstevel@tonic-gate *
397c478bd9Sstevel@tonic-gate * We insure for the service the following:
407c478bd9Sstevel@tonic-gate * (1) The timestamp microseconds do not exceed 1 million.
417c478bd9Sstevel@tonic-gate * (2) The timestamp plus the window is less than the current time.
427c478bd9Sstevel@tonic-gate * (3) The timestamp is not less than the one previously
437c478bd9Sstevel@tonic-gate * seen in the current session.
447c478bd9Sstevel@tonic-gate *
457c478bd9Sstevel@tonic-gate * It is up to the server to determine if the window size is
467c478bd9Sstevel@tonic-gate * too small.
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate */
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include "mt.h"
517c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
527c478bd9Sstevel@tonic-gate #include <assert.h>
537c478bd9Sstevel@tonic-gate #include <rpc/des_crypt.h>
547c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
557c478bd9Sstevel@tonic-gate #include <sys/types.h>
5667dbe2beSCasper H.S. Dik #include <sys/param.h>
577c478bd9Sstevel@tonic-gate #include <stdlib.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <string.h>
6061961e0fSrobinson #include <strings.h>
61*b1cdc720SAlex Wilson #include <sys/debug.h>
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate #include <syslog.h>
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate extern int key_decryptsession_pk(const char *, netobj *, des_block *);
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate #define USEC_PER_SEC ((ulong_t)1000000L)
687c478bd9Sstevel@tonic-gate #define BEFORE(t1, t2) timercmp(t1, t2, < /* EMPTY */)
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate * LRU cache of conversation keys and some other useful items.
737c478bd9Sstevel@tonic-gate */
747c478bd9Sstevel@tonic-gate #define DEF_AUTHDES_CACHESZ 128
757c478bd9Sstevel@tonic-gate int authdes_cachesz = DEF_AUTHDES_CACHESZ;
767c478bd9Sstevel@tonic-gate struct cache_entry {
777c478bd9Sstevel@tonic-gate des_block key; /* conversation key */
787c478bd9Sstevel@tonic-gate char *rname; /* client's name */
797c478bd9Sstevel@tonic-gate uint_t window; /* credential lifetime window */
807c478bd9Sstevel@tonic-gate struct timeval laststamp; /* detect replays of creds */
817c478bd9Sstevel@tonic-gate char *localcred; /* generic local credential */
827c478bd9Sstevel@tonic-gate int index; /* where are we in array? */
837c478bd9Sstevel@tonic-gate struct cache_entry *prev; /* prev entry on LRU list */
847c478bd9Sstevel@tonic-gate struct cache_entry *next; /* next entry on LRU list */
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate static const char __getucredstr[] = "authdes_getucred:";
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate static struct cache_entry *_rpc_authdes_cache; /* [authdes_cachesz] */
907c478bd9Sstevel@tonic-gate static struct cache_entry *cache_head; /* cache (in LRU order) */
917c478bd9Sstevel@tonic-gate static struct cache_entry *cache_tail; /* cache (in LRU order) */
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate * A rwlock_t would seem to make more sense, but it turns out we always
957c478bd9Sstevel@tonic-gate * muck with the cache entries, so would always need a write lock (in
967c478bd9Sstevel@tonic-gate * which case, we might as well use a mutex).
977c478bd9Sstevel@tonic-gate */
987c478bd9Sstevel@tonic-gate extern mutex_t authdes_lock;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate static int cache_init(void); /* initialize the cache */
1027c478bd9Sstevel@tonic-gate /* find an entry in the cache */
1037c478bd9Sstevel@tonic-gate static int cache_spot(des_block *, char *, struct timeval *);
1047c478bd9Sstevel@tonic-gate static void cache_ref(uint32_t); /* note that sid was ref'd */
1057c478bd9Sstevel@tonic-gate static void invalidate(char *); /* invalidate entry in cache */
1067c478bd9Sstevel@tonic-gate static void __msgout(int, const char *, const char *);
1077c478bd9Sstevel@tonic-gate static void __msgout2(const char *, const char *);
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate * cache statistics
1117c478bd9Sstevel@tonic-gate */
1127c478bd9Sstevel@tonic-gate struct {
1137c478bd9Sstevel@tonic-gate ulong_t ncachehits; /* times cache hit, and is not replay */
1147c478bd9Sstevel@tonic-gate ulong_t ncachereplays; /* times cache hit, and is replay */
1157c478bd9Sstevel@tonic-gate ulong_t ncachemisses; /* times cache missed */
1167c478bd9Sstevel@tonic-gate } svcauthdes_stats;
1177c478bd9Sstevel@tonic-gate
118*b1cdc720SAlex Wilson /*
119*b1cdc720SAlex Wilson * NOTE: this has to fit inside RQCRED_SIZE bytes. If you update this struct,
120*b1cdc720SAlex Wilson * double-check it still fits.
121*b1cdc720SAlex Wilson */
122*b1cdc720SAlex Wilson struct authdes_area {
123*b1cdc720SAlex Wilson struct authdes_cred area_cred;
124*b1cdc720SAlex Wilson char area_netname[MAXNETNAMELEN+1];
125*b1cdc720SAlex Wilson };
126*b1cdc720SAlex Wilson CTASSERT(sizeof (struct authdes_area) <= RQCRED_SIZE);
127*b1cdc720SAlex Wilson
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate * Service side authenticator for AUTH_DES
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate enum auth_stat
__svcauth_des(struct svc_req * rqst,struct rpc_msg * msg)1327c478bd9Sstevel@tonic-gate __svcauth_des(struct svc_req *rqst, struct rpc_msg *msg)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate int32_t *ixdr;
1357c478bd9Sstevel@tonic-gate des_block cryptbuf[2];
1367c478bd9Sstevel@tonic-gate struct authdes_cred *cred;
1377c478bd9Sstevel@tonic-gate struct authdes_verf verf;
1387c478bd9Sstevel@tonic-gate int status;
1397c478bd9Sstevel@tonic-gate struct cache_entry *entry;
1407c478bd9Sstevel@tonic-gate uint32_t sid;
1417c478bd9Sstevel@tonic-gate int cache_spot_id;
1427c478bd9Sstevel@tonic-gate des_block *sessionkey, init_sessionkey;
1437c478bd9Sstevel@tonic-gate des_block ivec;
1447c478bd9Sstevel@tonic-gate uint_t window;
145*b1cdc720SAlex Wilson struct authdes_area *area;
1467c478bd9Sstevel@tonic-gate struct timeval timestamp;
1477c478bd9Sstevel@tonic-gate uint32_t namelen;
1487c478bd9Sstevel@tonic-gate int fullname_rcvd = 0;
1497c478bd9Sstevel@tonic-gate int from_cache = 0;
1507c478bd9Sstevel@tonic-gate
15161961e0fSrobinson (void) mutex_lock(&authdes_lock);
1527c478bd9Sstevel@tonic-gate if (_rpc_authdes_cache == NULL) {
1537c478bd9Sstevel@tonic-gate int ret = cache_init();
1547c478bd9Sstevel@tonic-gate if (ret == -1) {
15561961e0fSrobinson (void) mutex_unlock(&authdes_lock);
1567c478bd9Sstevel@tonic-gate return (AUTH_FAILED);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate }
15961961e0fSrobinson (void) mutex_unlock(&authdes_lock);
1607c478bd9Sstevel@tonic-gate
16161961e0fSrobinson /* LINTED pointer cast */
162*b1cdc720SAlex Wilson area = (struct authdes_area *)rqst->rq_clntcred;
1637c478bd9Sstevel@tonic-gate cred = (struct authdes_cred *)&area->area_cred;
1647c478bd9Sstevel@tonic-gate
16561961e0fSrobinson if ((uint_t)msg->rm_call.cb_cred.oa_length == 0)
1667c478bd9Sstevel@tonic-gate return (AUTH_BADCRED);
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate * Get the credential
1697c478bd9Sstevel@tonic-gate */
17061961e0fSrobinson /* LINTED pointer cast */
1717c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_cred.oa_base;
1727c478bd9Sstevel@tonic-gate cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
1737c478bd9Sstevel@tonic-gate switch (cred->adc_namekind) {
1747c478bd9Sstevel@tonic-gate case ADN_FULLNAME:
1757c478bd9Sstevel@tonic-gate namelen = IXDR_GET_U_INT32(ixdr);
17661961e0fSrobinson if (namelen > MAXNETNAMELEN)
1777c478bd9Sstevel@tonic-gate return (AUTH_BADCRED);
1787c478bd9Sstevel@tonic-gate cred->adc_fullname.name = area->area_netname;
17961961e0fSrobinson (void) memcpy(cred->adc_fullname.name, ixdr, (uint_t)namelen);
1807c478bd9Sstevel@tonic-gate cred->adc_fullname.name[namelen] = 0;
1817c478bd9Sstevel@tonic-gate ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
1827c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.high = (uint32_t)*ixdr++;
1837c478bd9Sstevel@tonic-gate cred->adc_fullname.key.key.low = (uint32_t)*ixdr++;
1847c478bd9Sstevel@tonic-gate cred->adc_fullname.window = (uint32_t)*ixdr++;
1857c478bd9Sstevel@tonic-gate fullname_rcvd++;
1867c478bd9Sstevel@tonic-gate break;
1877c478bd9Sstevel@tonic-gate case ADN_NICKNAME:
1887c478bd9Sstevel@tonic-gate cred->adc_nickname = (uint32_t)*ixdr++;
1897c478bd9Sstevel@tonic-gate break;
1907c478bd9Sstevel@tonic-gate default:
1917c478bd9Sstevel@tonic-gate return (AUTH_BADCRED);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
19461961e0fSrobinson if ((uint_t)msg->rm_call.cb_verf.oa_length == 0)
1957c478bd9Sstevel@tonic-gate return (AUTH_BADVERF);
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate * Get the verifier
1987c478bd9Sstevel@tonic-gate */
19961961e0fSrobinson /* LINTED pointer cast */
2007c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base;
2017c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.high = (uint32_t)*ixdr++;
2027c478bd9Sstevel@tonic-gate verf.adv_xtimestamp.key.low = (uint32_t)*ixdr++;
2037c478bd9Sstevel@tonic-gate verf.adv_int_u = (uint32_t)*ixdr++;
2047c478bd9Sstevel@tonic-gate
20561961e0fSrobinson (void) mutex_lock(&authdes_lock);
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate * Get the conversation key
2097c478bd9Sstevel@tonic-gate */
2107c478bd9Sstevel@tonic-gate if (fullname_rcvd) { /* ADN_FULLNAME */
2117c478bd9Sstevel@tonic-gate netobj pkey;
2127c478bd9Sstevel@tonic-gate char pkey_data[1024];
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate again:
2157c478bd9Sstevel@tonic-gate init_sessionkey = cred->adc_fullname.key;
2167c478bd9Sstevel@tonic-gate sessionkey = &init_sessionkey;
2177c478bd9Sstevel@tonic-gate
21861961e0fSrobinson if (!__getpublickey_cached(cred->adc_fullname.name,
2197c478bd9Sstevel@tonic-gate pkey_data, &from_cache)) {
2207c478bd9Sstevel@tonic-gate /*
22148bbca81SDaniel Hoffman * if the user has no public key, treat them as the
2227c478bd9Sstevel@tonic-gate * unauthenticated identity - nobody. If this
2237c478bd9Sstevel@tonic-gate * works, it means the client didn't find the
2247c478bd9Sstevel@tonic-gate * user's keys and used nobody's secret key
2257c478bd9Sstevel@tonic-gate * as a backup.
2267c478bd9Sstevel@tonic-gate */
22761961e0fSrobinson if (!__getpublickey_cached("nobody",
2287c478bd9Sstevel@tonic-gate pkey_data, &from_cache)) {
2297c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
2307c478bd9Sstevel@tonic-gate "_svcauth_des: no public key for nobody or ",
2317c478bd9Sstevel@tonic-gate cred->adc_fullname.name);
23261961e0fSrobinson (void) mutex_unlock(&authdes_lock);
2337c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* no key */
2347c478bd9Sstevel@tonic-gate }
23561961e0fSrobinson
23661961e0fSrobinson /*
23761961e0fSrobinson * found a public key for nobody. change
23861961e0fSrobinson * the fullname id to nobody, so the caller
23961961e0fSrobinson * thinks the client specified nobody
24061961e0fSrobinson * as the user identity.
24161961e0fSrobinson */
24261961e0fSrobinson (void) strcpy(cred->adc_fullname.name, "nobody");
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate pkey.n_bytes = pkey_data;
2457c478bd9Sstevel@tonic-gate pkey.n_len = strlen(pkey_data) + 1;
2467c478bd9Sstevel@tonic-gate if (key_decryptsession_pk(cred->adc_fullname.name, &pkey,
2477c478bd9Sstevel@tonic-gate sessionkey) < 0) {
2487c478bd9Sstevel@tonic-gate if (from_cache) {
2497c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name);
2507c478bd9Sstevel@tonic-gate goto again;
2517c478bd9Sstevel@tonic-gate }
25261961e0fSrobinson __msgout(LOG_INFO,
25361961e0fSrobinson "_svcauth_des: key_decryptsessionkey failed for",
25461961e0fSrobinson cred->adc_fullname.name);
25561961e0fSrobinson (void) mutex_unlock(&authdes_lock);
2567c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* key not found */
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */
2597c478bd9Sstevel@tonic-gate sid = cred->adc_nickname;
2607c478bd9Sstevel@tonic-gate if (sid >= authdes_cachesz) {
2617c478bd9Sstevel@tonic-gate __msgout(LOG_INFO, "_svcauth_des:", "bad nickname");
26261961e0fSrobinson (void) mutex_unlock(&authdes_lock);
2637c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* garbled credential */
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate /* actually check that the entry is not null */
2667c478bd9Sstevel@tonic-gate entry = &_rpc_authdes_cache[sid];
2677c478bd9Sstevel@tonic-gate if (entry->rname == NULL) {
26861961e0fSrobinson (void) mutex_unlock(&authdes_lock);
2697c478bd9Sstevel@tonic-gate return (AUTH_BADCRED); /* cached out */
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate sessionkey = &_rpc_authdes_cache[sid].key;
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate * Decrypt the timestamp
2767c478bd9Sstevel@tonic-gate */
2777c478bd9Sstevel@tonic-gate cryptbuf[0] = verf.adv_xtimestamp;
2787c478bd9Sstevel@tonic-gate if (fullname_rcvd) { /* ADN_FULLNAME */
2797c478bd9Sstevel@tonic-gate cryptbuf[1].key.high = cred->adc_fullname.window;
2807c478bd9Sstevel@tonic-gate cryptbuf[1].key.low = verf.adv_winverf;
2817c478bd9Sstevel@tonic-gate ivec.key.high = ivec.key.low = 0;
2827c478bd9Sstevel@tonic-gate status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
2837c478bd9Sstevel@tonic-gate 2 * (int)sizeof (des_block), DES_DECRYPT | DES_HW,
2847c478bd9Sstevel@tonic-gate (char *)&ivec);
2857c478bd9Sstevel@tonic-gate } else {
2867c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
2877c478bd9Sstevel@tonic-gate (int)sizeof (des_block), DES_DECRYPT | DES_HW);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) {
2907c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) {
2917c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name);
2927c478bd9Sstevel@tonic-gate goto again;
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate __msgout(LOG_ERR, "_svcauth_des: DES decryption failure for",
2957c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
2967c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
29761961e0fSrobinson (void) mutex_unlock(&authdes_lock);
2987c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate * XDR the decrypted timestamp
3037c478bd9Sstevel@tonic-gate */
3047c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf;
3057c478bd9Sstevel@tonic-gate timestamp.tv_sec = IXDR_GET_INT32(ixdr);
3067c478bd9Sstevel@tonic-gate timestamp.tv_usec = IXDR_GET_INT32(ixdr);
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate * Check for valid credentials and verifiers.
3107c478bd9Sstevel@tonic-gate * They could be invalid because the key was flushed
3117c478bd9Sstevel@tonic-gate * out of the cache, and so a new session should begin.
3127c478bd9Sstevel@tonic-gate * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
3137c478bd9Sstevel@tonic-gate */
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate struct timeval current;
3167c478bd9Sstevel@tonic-gate int nick;
3177c478bd9Sstevel@tonic-gate int winverf;
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if (fullname_rcvd) {
3207c478bd9Sstevel@tonic-gate window = IXDR_GET_U_INT32(ixdr);
3217c478bd9Sstevel@tonic-gate winverf = IXDR_GET_U_INT32(ixdr);
3227c478bd9Sstevel@tonic-gate if (winverf != window - 1) {
3237c478bd9Sstevel@tonic-gate if (from_cache) {
3247c478bd9Sstevel@tonic-gate __getpublickey_flush(
3257c478bd9Sstevel@tonic-gate cred->adc_fullname.name);
3267c478bd9Sstevel@tonic-gate goto again;
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
3297c478bd9Sstevel@tonic-gate "_svcauth_des: corrupted window from",
3307c478bd9Sstevel@tonic-gate cred->adc_fullname.name);
33161961e0fSrobinson (void) mutex_unlock(&authdes_lock);
3327c478bd9Sstevel@tonic-gate /* garbled credential or invalid secret key */
3337c478bd9Sstevel@tonic-gate return (AUTH_BADCRED);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate cache_spot_id = cache_spot(sessionkey,
3367c478bd9Sstevel@tonic-gate cred->adc_fullname.name,
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate ×tamp);
3397c478bd9Sstevel@tonic-gate if (cache_spot_id < 0) {
3407c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
3417c478bd9Sstevel@tonic-gate "_svcauth_des: replayed credential from",
3427c478bd9Sstevel@tonic-gate cred->adc_fullname.name);
34361961e0fSrobinson (void) mutex_unlock(&authdes_lock);
3447c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDCRED); /* replay */
3457c478bd9Sstevel@tonic-gate } else sid = cache_spot_id;
3467c478bd9Sstevel@tonic-gate nick = 0;
3477c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */
3487c478bd9Sstevel@tonic-gate window = _rpc_authdes_cache[sid].window;
3497c478bd9Sstevel@tonic-gate nick = 1;
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate if ((ulong_t)timestamp.tv_usec >= USEC_PER_SEC) {
3537c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) {
3547c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name);
3557c478bd9Sstevel@tonic-gate goto again;
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
3587c478bd9Sstevel@tonic-gate "_svcauth_des: invalid timestamp received from",
3597c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
3607c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
3617c478bd9Sstevel@tonic-gate /* cached out (bad key), or garbled verifier */
36261961e0fSrobinson (void) mutex_unlock(&authdes_lock);
3637c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate if (nick && BEFORE(×tamp,
3667c478bd9Sstevel@tonic-gate &_rpc_authdes_cache[sid].laststamp)) {
3677c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) {
3687c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name);
3697c478bd9Sstevel@tonic-gate goto again;
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
3727c478bd9Sstevel@tonic-gate "_svcauth_des: timestamp is earlier than the one previously seen from",
3737c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
3747c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
37561961e0fSrobinson (void) mutex_unlock(&authdes_lock);
3767c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDVERF); /* replay */
3777c478bd9Sstevel@tonic-gate }
37861961e0fSrobinson (void) gettimeofday(¤t, NULL);
3797c478bd9Sstevel@tonic-gate current.tv_sec -= window; /* allow for expiration */
3807c478bd9Sstevel@tonic-gate if (!BEFORE(¤t, ×tamp)) {
3817c478bd9Sstevel@tonic-gate if (fullname_rcvd && from_cache) {
3827c478bd9Sstevel@tonic-gate __getpublickey_flush(cred->adc_fullname.name);
3837c478bd9Sstevel@tonic-gate goto again;
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate __msgout(LOG_INFO,
3867c478bd9Sstevel@tonic-gate "_svcauth_des: timestamp expired for",
3877c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
3887c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
3897c478bd9Sstevel@tonic-gate /* replay, or garbled credential */
39061961e0fSrobinson (void) mutex_unlock(&authdes_lock);
3917c478bd9Sstevel@tonic-gate return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * Set up the reply verifier
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate verf.adv_nickname = sid;
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate * xdr the timestamp before encrypting
4027c478bd9Sstevel@tonic-gate */
4037c478bd9Sstevel@tonic-gate ixdr = (int32_t *)cryptbuf;
4047c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_sec - 1);
4057c478bd9Sstevel@tonic-gate IXDR_PUT_INT32(ixdr, timestamp.tv_usec);
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * encrypt the timestamp
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
4117c478bd9Sstevel@tonic-gate (int)sizeof (des_block), DES_ENCRYPT | DES_HW);
4127c478bd9Sstevel@tonic-gate if (DES_FAILED(status)) {
4137c478bd9Sstevel@tonic-gate __msgout(LOG_ERR, "_svcauth_des: DES encryption failure for",
4147c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
4157c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
41661961e0fSrobinson (void) mutex_unlock(&authdes_lock);
4177c478bd9Sstevel@tonic-gate return (AUTH_FAILED); /* system error */
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate verf.adv_xtimestamp = cryptbuf[0];
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate * Serialize the reply verifier, and update rqst
4237c478bd9Sstevel@tonic-gate */
42461961e0fSrobinson /* LINTED pointer cast */
4257c478bd9Sstevel@tonic-gate ixdr = (int32_t *)msg->rm_call.cb_verf.oa_base;
4267c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.high;
4277c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_xtimestamp.key.low;
4287c478bd9Sstevel@tonic-gate *ixdr++ = (int32_t)verf.adv_int_u;
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
4317c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
4327c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length =
4337c478bd9Sstevel@tonic-gate (char *)ixdr - msg->rm_call.cb_verf.oa_base;
4347c478bd9Sstevel@tonic-gate if (rqst->rq_xprt->xp_verf.oa_length > MAX_AUTH_BYTES) {
4357c478bd9Sstevel@tonic-gate __msgout(LOG_ERR,
4367c478bd9Sstevel@tonic-gate "_svcauth_des: Authenticator length error",
4377c478bd9Sstevel@tonic-gate fullname_rcvd ? cred->adc_fullname.name :
4387c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].rname);
43961961e0fSrobinson (void) mutex_unlock(&authdes_lock);
4407c478bd9Sstevel@tonic-gate return (AUTH_REJECTEDVERF);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate * We succeeded, commit the data to the cache now and
4457c478bd9Sstevel@tonic-gate * finish cooking the credential.
4467c478bd9Sstevel@tonic-gate */
4477c478bd9Sstevel@tonic-gate entry = &_rpc_authdes_cache[sid];
4487c478bd9Sstevel@tonic-gate entry->laststamp = timestamp;
4497c478bd9Sstevel@tonic-gate cache_ref(sid);
4507c478bd9Sstevel@tonic-gate if (cred->adc_namekind == ADN_FULLNAME) {
4517c478bd9Sstevel@tonic-gate cred->adc_fullname.window = window;
4527c478bd9Sstevel@tonic-gate cred->adc_nickname = sid; /* save nickname */
45361961e0fSrobinson if (entry->rname != NULL)
45461961e0fSrobinson free(entry->rname);
45561961e0fSrobinson entry->rname = malloc(strlen(cred->adc_fullname.name) + 1);
4567c478bd9Sstevel@tonic-gate if (entry->rname != NULL) {
4577c478bd9Sstevel@tonic-gate (void) strcpy(entry->rname, cred->adc_fullname.name);
4587c478bd9Sstevel@tonic-gate } else {
4597c478bd9Sstevel@tonic-gate __msgout(LOG_CRIT, "_svcauth_des:", "out of memory");
46061961e0fSrobinson (void) mutex_unlock(&authdes_lock);
4617c478bd9Sstevel@tonic-gate return (AUTH_FAILED);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate entry->key = *sessionkey;
4647c478bd9Sstevel@tonic-gate entry->window = window;
4657c478bd9Sstevel@tonic-gate /* mark any cached cred invalid */
4667c478bd9Sstevel@tonic-gate invalidate(entry->localcred);
4677c478bd9Sstevel@tonic-gate } else { /* ADN_NICKNAME */
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate * nicknames are cooked into fullnames
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate cred->adc_namekind = ADN_FULLNAME;
4727c478bd9Sstevel@tonic-gate cred->adc_fullname.name = entry->rname;
4737c478bd9Sstevel@tonic-gate cred->adc_fullname.key = entry->key;
4747c478bd9Sstevel@tonic-gate cred->adc_fullname.window = entry->window;
4757c478bd9Sstevel@tonic-gate }
47661961e0fSrobinson (void) mutex_unlock(&authdes_lock);
4777c478bd9Sstevel@tonic-gate return (AUTH_OK); /* we made it! */
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate * Initialize the cache
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate static int
cache_init(void)48561961e0fSrobinson cache_init(void)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate int i;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock));
49261961e0fSrobinson _rpc_authdes_cache =
49361961e0fSrobinson malloc(sizeof (struct cache_entry) * authdes_cachesz);
4947c478bd9Sstevel@tonic-gate if (_rpc_authdes_cache == NULL) {
4957c478bd9Sstevel@tonic-gate __msgout(LOG_CRIT, "cache_init:", "out of memory");
4967c478bd9Sstevel@tonic-gate return (-1);
4977c478bd9Sstevel@tonic-gate }
49861961e0fSrobinson (void) memset(_rpc_authdes_cache, 0,
4997c478bd9Sstevel@tonic-gate sizeof (struct cache_entry) * authdes_cachesz);
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate * Initialize the lru chain (linked-list)
5037c478bd9Sstevel@tonic-gate */
5047c478bd9Sstevel@tonic-gate for (i = 1; i < (authdes_cachesz - 1); i++) {
5057c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].index = i;
5067c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].next = &_rpc_authdes_cache[i + 1];
5077c478bd9Sstevel@tonic-gate _rpc_authdes_cache[i].prev = &_rpc_authdes_cache[i - 1];
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate cache_head = &_rpc_authdes_cache[0];
5107c478bd9Sstevel@tonic-gate cache_tail = &_rpc_authdes_cache[authdes_cachesz - 1];
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate * These elements of the chain need special attention...
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate cache_head->index = 0;
5167c478bd9Sstevel@tonic-gate cache_tail->index = authdes_cachesz - 1;
5177c478bd9Sstevel@tonic-gate cache_head->next = &_rpc_authdes_cache[1];
5187c478bd9Sstevel@tonic-gate cache_head->prev = cache_tail;
5197c478bd9Sstevel@tonic-gate cache_tail->next = cache_head;
5207c478bd9Sstevel@tonic-gate cache_tail->prev = &_rpc_authdes_cache[authdes_cachesz - 2];
5217c478bd9Sstevel@tonic-gate return (0);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * Find the lru victim
5277c478bd9Sstevel@tonic-gate */
5287c478bd9Sstevel@tonic-gate static uint32_t
cache_victim(void)52961961e0fSrobinson cache_victim(void)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock));
5347c478bd9Sstevel@tonic-gate return (cache_head->index); /* list in lru order */
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Note that sid was referenced
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate static void
cache_ref(uint32_t sid)5417c478bd9Sstevel@tonic-gate cache_ref(uint32_t sid)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate struct cache_entry *curr = &_rpc_authdes_cache[sid];
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock));
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate * move referenced item from its place on the LRU chain
5527c478bd9Sstevel@tonic-gate * to the tail of the chain while checking for special
5537c478bd9Sstevel@tonic-gate * conditions (mainly for performance).
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate if (cache_tail == curr) { /* no work to do */
5567c478bd9Sstevel@tonic-gate /*EMPTY*/;
5577c478bd9Sstevel@tonic-gate } else if (cache_head == curr) {
5587c478bd9Sstevel@tonic-gate cache_head = cache_head->next;
5597c478bd9Sstevel@tonic-gate cache_tail = curr;
5607c478bd9Sstevel@tonic-gate } else {
5617c478bd9Sstevel@tonic-gate (curr->next)->prev = curr->prev; /* fix thy neighbor */
5627c478bd9Sstevel@tonic-gate (curr->prev)->next = curr->next;
5637c478bd9Sstevel@tonic-gate curr->next = cache_head; /* fix thy self... */
5647c478bd9Sstevel@tonic-gate curr->prev = cache_tail;
5657c478bd9Sstevel@tonic-gate cache_head->prev = curr; /* fix the head */
5667c478bd9Sstevel@tonic-gate cache_tail->next = curr; /* fix the tail */
5677c478bd9Sstevel@tonic-gate cache_tail = curr; /* move the tail */
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate * Find a spot in the cache for a credential containing
5737c478bd9Sstevel@tonic-gate * the items given. Return -1 if a replay is detected, otherwise
5747c478bd9Sstevel@tonic-gate * return the spot in the cache.
5757c478bd9Sstevel@tonic-gate */
5767c478bd9Sstevel@tonic-gate static int
cache_spot(des_block * key,char * name,struct timeval * timestamp)5777c478bd9Sstevel@tonic-gate cache_spot(des_block *key, char *name, struct timeval *timestamp)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate struct cache_entry *cp;
5807c478bd9Sstevel@tonic-gate int i;
5817c478bd9Sstevel@tonic-gate uint32_t hi;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate /* LOCK HELD ON ENTRY: authdes_lock */
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&authdes_lock));
5867c478bd9Sstevel@tonic-gate hi = key->key.high;
5877c478bd9Sstevel@tonic-gate for (cp = _rpc_authdes_cache, i = 0; i < authdes_cachesz; i++, cp++) {
5887c478bd9Sstevel@tonic-gate if (cp->key.key.high == hi &&
5897c478bd9Sstevel@tonic-gate cp->key.key.low == key->key.low &&
5907c478bd9Sstevel@tonic-gate cp->rname != NULL &&
5917c478bd9Sstevel@tonic-gate memcmp(cp->rname, name, strlen(name) + 1) == 0) {
5927c478bd9Sstevel@tonic-gate if (BEFORE(timestamp, &cp->laststamp)) {
5937c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachereplays++;
5947c478bd9Sstevel@tonic-gate return (-1); /* replay */
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachehits++;
5977c478bd9Sstevel@tonic-gate return (i);
5987c478bd9Sstevel@tonic-gate /* refresh */
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate svcauthdes_stats.ncachemisses++;
60261961e0fSrobinson return (cache_victim());
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * Local credential handling stuff.
6087c478bd9Sstevel@tonic-gate * NOTE: bsd unix dependent.
6097c478bd9Sstevel@tonic-gate * Other operating systems should put something else here.
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate #define UNKNOWN -2 /* grouplen, if cached cred is unknown user */
6127c478bd9Sstevel@tonic-gate #define INVALID -1 /* grouplen, if cache entry is invalid */
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate struct bsdcred {
6157c478bd9Sstevel@tonic-gate uid_t uid; /* cached uid */
6167c478bd9Sstevel@tonic-gate gid_t gid; /* cached gid */
6177c478bd9Sstevel@tonic-gate short grouplen; /* length of cached groups */
61867dbe2beSCasper H.S. Dik gid_t groups[1]; /* cached groups allocate _SC_NGROUPS_MAX */
6197c478bd9Sstevel@tonic-gate };
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate static void
invalidate(char * cred)6227c478bd9Sstevel@tonic-gate invalidate(char *cred)
6237c478bd9Sstevel@tonic-gate {
62461961e0fSrobinson if (cred == NULL)
6257c478bd9Sstevel@tonic-gate return;
62661961e0fSrobinson /* LINTED pointer cast */
6277c478bd9Sstevel@tonic-gate ((struct bsdcred *)cred)->grouplen = INVALID;
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate * Map a des credential into a unix cred.
6327c478bd9Sstevel@tonic-gate * We cache the credential here so the application does
6337c478bd9Sstevel@tonic-gate * not have to make an rpc call every time to interpret
6347c478bd9Sstevel@tonic-gate * the credential.
6357c478bd9Sstevel@tonic-gate */
6367c478bd9Sstevel@tonic-gate int
authdes_getucred(const struct authdes_cred * adc,uid_t * uid,gid_t * gid,short * grouplen,gid_t * groups)6377c478bd9Sstevel@tonic-gate authdes_getucred(const struct authdes_cred *adc, uid_t *uid, gid_t *gid,
6387c478bd9Sstevel@tonic-gate short *grouplen, gid_t *groups)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate uint32_t sid;
6417c478bd9Sstevel@tonic-gate int i;
6427c478bd9Sstevel@tonic-gate uid_t i_uid;
6437c478bd9Sstevel@tonic-gate gid_t i_gid;
6447c478bd9Sstevel@tonic-gate int i_grouplen;
6457c478bd9Sstevel@tonic-gate struct bsdcred *cred;
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate sid = adc->adc_nickname;
6487c478bd9Sstevel@tonic-gate if (sid >= authdes_cachesz) {
6497c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "invalid nickname");
6507c478bd9Sstevel@tonic-gate return (0);
6517c478bd9Sstevel@tonic-gate }
65261961e0fSrobinson (void) mutex_lock(&authdes_lock);
65361961e0fSrobinson /* LINTED pointer cast */
6547c478bd9Sstevel@tonic-gate cred = (struct bsdcred *)_rpc_authdes_cache[sid].localcred;
6557c478bd9Sstevel@tonic-gate if (cred == NULL) {
65667dbe2beSCasper H.S. Dik static size_t bsdcred_sz;
65767dbe2beSCasper H.S. Dik
65867dbe2beSCasper H.S. Dik if (bsdcred_sz == 0) {
65967dbe2beSCasper H.S. Dik bsdcred_sz = sizeof (struct bsdcred) +
66067dbe2beSCasper H.S. Dik (sysconf(_SC_NGROUPS_MAX) - 1) * sizeof (gid_t);
66167dbe2beSCasper H.S. Dik }
66267dbe2beSCasper H.S. Dik cred = malloc(bsdcred_sz);
6637c478bd9Sstevel@tonic-gate if (cred == NULL) {
6647c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "out of memory");
66561961e0fSrobinson (void) mutex_unlock(&authdes_lock);
6667c478bd9Sstevel@tonic-gate return (0);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate _rpc_authdes_cache[sid].localcred = (char *)cred;
6697c478bd9Sstevel@tonic-gate cred->grouplen = INVALID;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate if (cred->grouplen == INVALID) {
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate * not in cache: lookup
6747c478bd9Sstevel@tonic-gate */
6757c478bd9Sstevel@tonic-gate if (!netname2user(adc->adc_fullname.name, (uid_t *)&i_uid,
6767c478bd9Sstevel@tonic-gate (gid_t *)&i_gid, &i_grouplen, (gid_t *)groups)) {
6777c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "unknown netname");
6787c478bd9Sstevel@tonic-gate /* mark as lookup up, but not found */
6797c478bd9Sstevel@tonic-gate cred->grouplen = UNKNOWN;
68061961e0fSrobinson (void) mutex_unlock(&authdes_lock);
6817c478bd9Sstevel@tonic-gate return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate __msgout2(__getucredstr, "missed ucred cache");
6847c478bd9Sstevel@tonic-gate *uid = cred->uid = i_uid;
6857c478bd9Sstevel@tonic-gate *gid = cred->gid = i_gid;
6867c478bd9Sstevel@tonic-gate *grouplen = cred->grouplen = i_grouplen;
6877c478bd9Sstevel@tonic-gate for (i = i_grouplen - 1; i >= 0; i--) {
68867dbe2beSCasper H.S. Dik cred->groups[i] = groups[i];
6897c478bd9Sstevel@tonic-gate }
69061961e0fSrobinson (void) mutex_unlock(&authdes_lock);
6917c478bd9Sstevel@tonic-gate return (1);
69261961e0fSrobinson }
69361961e0fSrobinson if (cred->grouplen == UNKNOWN) {
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate * Already lookup up, but no match found
6967c478bd9Sstevel@tonic-gate */
69761961e0fSrobinson (void) mutex_unlock(&authdes_lock);
6987c478bd9Sstevel@tonic-gate return (0);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate * cached credentials
7037c478bd9Sstevel@tonic-gate */
7047c478bd9Sstevel@tonic-gate *uid = cred->uid;
7057c478bd9Sstevel@tonic-gate *gid = cred->gid;
7067c478bd9Sstevel@tonic-gate *grouplen = cred->grouplen;
7077c478bd9Sstevel@tonic-gate for (i = cred->grouplen - 1; i >= 0; i--) {
70867dbe2beSCasper H.S. Dik groups[i] = cred->groups[i];
7097c478bd9Sstevel@tonic-gate }
71061961e0fSrobinson (void) mutex_unlock(&authdes_lock);
7117c478bd9Sstevel@tonic-gate return (1);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate static void
__msgout(int level,const char * str,const char * strarg)7167c478bd9Sstevel@tonic-gate __msgout(int level, const char *str, const char *strarg)
7177c478bd9Sstevel@tonic-gate {
71861961e0fSrobinson (void) syslog(level, "%s %s", str, strarg);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate static void
__msgout2(const char * str,const char * str2)7237c478bd9Sstevel@tonic-gate __msgout2(const char *str, const char *str2)
7247c478bd9Sstevel@tonic-gate {
72561961e0fSrobinson (void) syslog(LOG_DEBUG, "%s %s", str, str2);
7267c478bd9Sstevel@tonic-gate }
727