126219Swpaul 226219Swpaul/* 326219Swpaul * Copyright (c) 1988 by Sun Microsystems, Inc. 426219Swpaul */ 526219Swpaul 6261057Smav/*- 7261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 8261057Smav * All rights reserved. 9261057Smav * 10261057Smav * Redistribution and use in source and binary forms, with or without 11261057Smav * modification, are permitted provided that the following conditions are met: 12261057Smav * - Redistributions of source code must retain the above copyright notice, 13261057Smav * this list of conditions and the following disclaimer. 14261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 15261057Smav * this list of conditions and the following disclaimer in the documentation 16261057Smav * and/or other materials provided with the distribution. 17261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 18261057Smav * contributors may be used to endorse or promote products derived 19261057Smav * from this software without specific prior written permission. 2026219Swpaul * 21261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31261057Smav * POSSIBILITY OF SUCH DAMAGE. 3226219Swpaul */ 3326219Swpaul 3426219Swpaul/* 3526219Swpaul * svcauth_des.c, server-side des authentication 3626219Swpaul * 3726219Swpaul * We insure for the service the following: 3826219Swpaul * (1) The timestamp microseconds do not exceed 1 million. 3926219Swpaul * (2) The timestamp plus the window is less than the current time. 4026219Swpaul * (3) The timestamp is not less than the one previously 4126219Swpaul * seen in the current session. 4226219Swpaul * 4326219Swpaul * It is up to the server to determine if the window size is 4426219Swpaul * too small . 4526219Swpaul * 4626219Swpaul */ 4726219Swpaul 4875094Siedowse#include "namespace.h" 4974462Salfred#include "reentrant.h" 5026219Swpaul#include <string.h> 5126219Swpaul#include <stdlib.h> 5271579Sdeischen#include <stdio.h> 5326219Swpaul#include <unistd.h> 5426219Swpaul#include <rpc/des_crypt.h> 5526219Swpaul#include <sys/param.h> 5626219Swpaul#include <netinet/in.h> 5726219Swpaul#include <rpc/types.h> 5826219Swpaul#include <rpc/xdr.h> 5926219Swpaul#include <rpc/auth.h> 6026219Swpaul#include <rpc/auth_des.h> 6126219Swpaul#include <rpc/svc.h> 6226219Swpaul#include <rpc/rpc_msg.h> 6326219Swpaul#include <rpc/svc_auth.h> 6474462Salfred#include "libc_private.h" 6526219Swpaul 6626219Swpaul#if defined(LIBC_SCCS) && !defined(lint) 6792990Sobrienstatic char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; 6826219Swpaul#endif 6992990Sobrien#include <sys/cdefs.h> 7092990Sobrien__FBSDID("$FreeBSD$"); 7126219Swpaul 7290271Salfredextern int key_decryptsession_pk(const char *, netobj *, des_block *); 7390271Salfred 7426219Swpaul#define debug(msg) printf("svcauth_des: %s\n", msg) 7526219Swpaul 7626219Swpaul#define USEC_PER_SEC ((u_long) 1000000L) 7726219Swpaul#define BEFORE(t1, t2) timercmp(t1, t2, <) 7826219Swpaul 7926219Swpaul/* 8026219Swpaul * LRU cache of conversation keys and some other useful items. 8126219Swpaul */ 8226219Swpaul#define AUTHDES_CACHESZ 64 8326219Swpaulstruct cache_entry { 8426219Swpaul des_block key; /* conversation key */ 8526219Swpaul char *rname; /* client's name */ 8626219Swpaul u_int window; /* credential lifetime window */ 8726219Swpaul struct timeval laststamp; /* detect replays of creds */ 8826219Swpaul char *localcred; /* generic local credential */ 8926219Swpaul}; 9026219Swpaulstatic struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; 9126219Swpaulstatic short *authdes_lru/* [AUTHDES_CACHESZ] */; 9226219Swpaul 9326219Swpaulstatic void cache_init(); /* initialize the cache */ 9426219Swpaulstatic short cache_spot(); /* find an entry in the cache */ 9526219Swpaulstatic void cache_ref(/*short sid*/); /* note that sid was ref'd */ 9626219Swpaul 9726219Swpaulstatic void invalidate(); /* invalidate entry in cache */ 9826219Swpaul 9926219Swpaul/* 10026219Swpaul * cache statistics 10126219Swpaul */ 10226219Swpaulstatic struct { 10326219Swpaul u_long ncachehits; /* times cache hit, and is not replay */ 10426219Swpaul u_long ncachereplays; /* times cache hit, and is replay */ 10526219Swpaul u_long ncachemisses; /* times cache missed */ 10626219Swpaul} svcauthdes_stats; 10726219Swpaul 10826219Swpaul/* 10926219Swpaul * Service side authenticator for AUTH_DES 11026219Swpaul */ 11126219Swpaulenum auth_stat 11226219Swpaul_svcauth_des(rqst, msg) 11392889Sobrien struct svc_req *rqst; 11492889Sobrien struct rpc_msg *msg; 11526219Swpaul{ 11626219Swpaul 11792889Sobrien long *ixdr; 11826219Swpaul des_block cryptbuf[2]; 11992889Sobrien struct authdes_cred *cred; 12026219Swpaul struct authdes_verf verf; 12126219Swpaul int status; 12292889Sobrien struct cache_entry *entry; 12326219Swpaul short sid = 0; 12426219Swpaul des_block *sessionkey; 12526219Swpaul des_block ivec; 12626219Swpaul u_int window; 12726219Swpaul struct timeval timestamp; 12826219Swpaul u_long namelen; 12926219Swpaul struct area { 13026219Swpaul struct authdes_cred area_cred; 13126219Swpaul char area_netname[MAXNETNAMELEN+1]; 13226219Swpaul } *area; 13326219Swpaul 13426219Swpaul if (authdes_cache == NULL) { 13526219Swpaul cache_init(); 13626219Swpaul } 13726219Swpaul 13826219Swpaul area = (struct area *)rqst->rq_clntcred; 13926219Swpaul cred = (struct authdes_cred *)&area->area_cred; 14026219Swpaul 14126219Swpaul /* 14226219Swpaul * Get the credential 14326219Swpaul */ 14426219Swpaul ixdr = (long *)msg->rm_call.cb_cred.oa_base; 14526219Swpaul cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 14626219Swpaul switch (cred->adc_namekind) { 14726219Swpaul case ADN_FULLNAME: 14826219Swpaul namelen = IXDR_GET_U_LONG(ixdr); 14926219Swpaul if (namelen > MAXNETNAMELEN) { 15026219Swpaul return (AUTH_BADCRED); 15126219Swpaul } 15226219Swpaul cred->adc_fullname.name = area->area_netname; 15326219Swpaul bcopy((char *)ixdr, cred->adc_fullname.name, 15426219Swpaul (u_int)namelen); 15526219Swpaul cred->adc_fullname.name[namelen] = 0; 15626219Swpaul ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 15726219Swpaul cred->adc_fullname.key.key.high = (u_long)*ixdr++; 15826219Swpaul cred->adc_fullname.key.key.low = (u_long)*ixdr++; 15926219Swpaul cred->adc_fullname.window = (u_long)*ixdr++; 16026219Swpaul break; 16126219Swpaul case ADN_NICKNAME: 16226219Swpaul cred->adc_nickname = (u_long)*ixdr++; 16326219Swpaul break; 16426219Swpaul default: 16526219Swpaul return (AUTH_BADCRED); 16626219Swpaul } 16726219Swpaul 16826219Swpaul /* 16926219Swpaul * Get the verifier 17026219Swpaul */ 17126219Swpaul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 17226219Swpaul verf.adv_xtimestamp.key.high = (u_long)*ixdr++; 17326219Swpaul verf.adv_xtimestamp.key.low = (u_long)*ixdr++; 17426219Swpaul verf.adv_int_u = (u_long)*ixdr++; 17526219Swpaul 17626219Swpaul 17726219Swpaul /* 17826219Swpaul * Get the conversation key 17926219Swpaul */ 18026219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 18126219Swpaul netobj pkey; 18226219Swpaul char pkey_data[1024]; 18326219Swpaul 18426219Swpaul sessionkey = &cred->adc_fullname.key; 18526219Swpaul if (! getpublickey(cred->adc_fullname.name, pkey_data)) { 18626219Swpaul debug("getpublickey"); 18726219Swpaul return(AUTH_BADCRED); 18826219Swpaul } 18926219Swpaul pkey.n_bytes = pkey_data; 19026219Swpaul pkey.n_len = strlen(pkey_data) + 1; 19126219Swpaul if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, 19226219Swpaul sessionkey) < 0) { 19326219Swpaul debug("decryptsessionkey"); 19426219Swpaul return (AUTH_BADCRED); /* key not found */ 19526219Swpaul } 19626219Swpaul } else { /* ADN_NICKNAME */ 19726219Swpaul sid = (short)cred->adc_nickname; 19874462Salfred if (sid < 0 || sid >= AUTHDES_CACHESZ) { 19926219Swpaul debug("bad nickname"); 20026219Swpaul return (AUTH_BADCRED); /* garbled credential */ 20126219Swpaul } 20226219Swpaul sessionkey = &authdes_cache[sid].key; 20326219Swpaul } 20426219Swpaul 20526219Swpaul 20626219Swpaul /* 20726219Swpaul * Decrypt the timestamp 20826219Swpaul */ 20926219Swpaul cryptbuf[0] = verf.adv_xtimestamp; 21026219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 21126219Swpaul cryptbuf[1].key.high = cred->adc_fullname.window; 21226219Swpaul cryptbuf[1].key.low = verf.adv_winverf; 21326219Swpaul ivec.key.high = ivec.key.low = 0; 21426219Swpaul status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 21526219Swpaul 2*sizeof(des_block), DES_DECRYPT | DES_HW, 21626219Swpaul (char *)&ivec); 21726219Swpaul } else { 21826219Swpaul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 21926219Swpaul sizeof(des_block), DES_DECRYPT | DES_HW); 22026219Swpaul } 22126219Swpaul if (DES_FAILED(status)) { 22226219Swpaul debug("decryption failure"); 22326219Swpaul return (AUTH_FAILED); /* system error */ 22426219Swpaul } 22526219Swpaul 22626219Swpaul /* 22726219Swpaul * XDR the decrypted timestamp 22826219Swpaul */ 22926219Swpaul ixdr = (long *)cryptbuf; 23026219Swpaul timestamp.tv_sec = IXDR_GET_LONG(ixdr); 23126219Swpaul timestamp.tv_usec = IXDR_GET_LONG(ixdr); 23226219Swpaul 23326219Swpaul /* 23426219Swpaul * Check for valid credentials and verifiers. 23526219Swpaul * They could be invalid because the key was flushed 23626219Swpaul * out of the cache, and so a new session should begin. 23726219Swpaul * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 23826219Swpaul */ 23926219Swpaul { 24026219Swpaul struct timeval current; 24126219Swpaul int nick; 24226219Swpaul int winverf; 24326219Swpaul 24426219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 24526219Swpaul window = IXDR_GET_U_LONG(ixdr); 24626219Swpaul winverf = IXDR_GET_U_LONG(ixdr); 24726219Swpaul if (winverf != window - 1) { 24826219Swpaul debug("window verifier mismatch"); 24926219Swpaul return (AUTH_BADCRED); /* garbled credential */ 25026219Swpaul } 25126219Swpaul sid = cache_spot(sessionkey, cred->adc_fullname.name, 25226219Swpaul ×tamp); 25326219Swpaul if (sid < 0) { 25426219Swpaul debug("replayed credential"); 25526219Swpaul return (AUTH_REJECTEDCRED); /* replay */ 25626219Swpaul } 25726219Swpaul nick = 0; 25826219Swpaul } else { /* ADN_NICKNAME */ 25926219Swpaul window = authdes_cache[sid].window; 26026219Swpaul nick = 1; 26126219Swpaul } 26226219Swpaul 26326219Swpaul if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { 26426219Swpaul debug("invalid usecs"); 26526219Swpaul /* cached out (bad key), or garbled verifier */ 26626219Swpaul return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 26726219Swpaul } 26826219Swpaul if (nick && BEFORE(×tamp, 26926219Swpaul &authdes_cache[sid].laststamp)) { 27026219Swpaul debug("timestamp before last seen"); 27126219Swpaul return (AUTH_REJECTEDVERF); /* replay */ 27226219Swpaul } 27326219Swpaul (void) gettimeofday(¤t, (struct timezone *)NULL); 27426219Swpaul current.tv_sec -= window; /* allow for expiration */ 27526219Swpaul if (!BEFORE(¤t, ×tamp)) { 27626219Swpaul debug("timestamp expired"); 27726219Swpaul /* replay, or garbled credential */ 27826219Swpaul return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 27926219Swpaul } 28026219Swpaul } 28126219Swpaul 28226219Swpaul /* 28326219Swpaul * Set up the reply verifier 28426219Swpaul */ 28526219Swpaul verf.adv_nickname = (u_long)sid; 28626219Swpaul 28726219Swpaul /* 28826219Swpaul * xdr the timestamp before encrypting 28926219Swpaul */ 29026219Swpaul ixdr = (long *)cryptbuf; 29126219Swpaul IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); 29226219Swpaul IXDR_PUT_LONG(ixdr, timestamp.tv_usec); 29326219Swpaul 29426219Swpaul /* 29526219Swpaul * encrypt the timestamp 29626219Swpaul */ 29726219Swpaul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 29826219Swpaul sizeof(des_block), DES_ENCRYPT | DES_HW); 29926219Swpaul if (DES_FAILED(status)) { 30026219Swpaul debug("encryption failure"); 30126219Swpaul return (AUTH_FAILED); /* system error */ 30226219Swpaul } 30326219Swpaul verf.adv_xtimestamp = cryptbuf[0]; 30426219Swpaul 30526219Swpaul /* 30626219Swpaul * Serialize the reply verifier, and update rqst 30726219Swpaul */ 30826219Swpaul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 30926219Swpaul *ixdr++ = (long)verf.adv_xtimestamp.key.high; 31026219Swpaul *ixdr++ = (long)verf.adv_xtimestamp.key.low; 31126219Swpaul *ixdr++ = (long)verf.adv_int_u; 31226219Swpaul 31326219Swpaul rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 31426219Swpaul rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 31526219Swpaul rqst->rq_xprt->xp_verf.oa_length = 31626219Swpaul (char *)ixdr - msg->rm_call.cb_verf.oa_base; 31726219Swpaul 31826219Swpaul /* 31926219Swpaul * We succeeded, commit the data to the cache now and 32026219Swpaul * finish cooking the credential. 32126219Swpaul */ 32226219Swpaul entry = &authdes_cache[sid]; 32326219Swpaul entry->laststamp = timestamp; 32426219Swpaul cache_ref(sid); 32526219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 32626219Swpaul cred->adc_fullname.window = window; 32726219Swpaul cred->adc_nickname = (u_long)sid; /* save nickname */ 32826219Swpaul if (entry->rname != NULL) { 32926219Swpaul mem_free(entry->rname, strlen(entry->rname) + 1); 33026219Swpaul } 33126219Swpaul entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name) 33226219Swpaul + 1); 33326219Swpaul if (entry->rname != NULL) { 33426219Swpaul (void) strcpy(entry->rname, cred->adc_fullname.name); 33526219Swpaul } else { 33626219Swpaul debug("out of memory"); 33726219Swpaul } 33826219Swpaul entry->key = *sessionkey; 33926219Swpaul entry->window = window; 34026219Swpaul invalidate(entry->localcred); /* mark any cached cred invalid */ 34126219Swpaul } else { /* ADN_NICKNAME */ 34226219Swpaul /* 34326219Swpaul * nicknames are cooked into fullnames 34426219Swpaul */ 34526219Swpaul cred->adc_namekind = ADN_FULLNAME; 34626219Swpaul cred->adc_fullname.name = entry->rname; 34726219Swpaul cred->adc_fullname.key = entry->key; 34826219Swpaul cred->adc_fullname.window = entry->window; 34926219Swpaul } 35026219Swpaul return (AUTH_OK); /* we made it!*/ 35126219Swpaul} 35226219Swpaul 35326219Swpaul 35426219Swpaul/* 35526219Swpaul * Initialize the cache 35626219Swpaul */ 35726219Swpaulstatic void 35826219Swpaulcache_init() 35926219Swpaul{ 36092889Sobrien int i; 36126219Swpaul 36226219Swpaul authdes_cache = (struct cache_entry *) 36326219Swpaul mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ); 36426219Swpaul bzero((char *)authdes_cache, 36526219Swpaul sizeof(struct cache_entry) * AUTHDES_CACHESZ); 36626219Swpaul 36726219Swpaul authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); 36826219Swpaul /* 36926219Swpaul * Initialize the lru list 37026219Swpaul */ 37126219Swpaul for (i = 0; i < AUTHDES_CACHESZ; i++) { 37226219Swpaul authdes_lru[i] = i; 37326219Swpaul } 37426219Swpaul} 37526219Swpaul 37626219Swpaul 37726219Swpaul/* 37826219Swpaul * Find the lru victim 37926219Swpaul */ 38026219Swpaulstatic short 38126219Swpaulcache_victim() 38226219Swpaul{ 38326219Swpaul return (authdes_lru[AUTHDES_CACHESZ-1]); 38426219Swpaul} 38526219Swpaul 38626219Swpaul/* 38726219Swpaul * Note that sid was referenced 38826219Swpaul */ 38926219Swpaulstatic void 39026219Swpaulcache_ref(sid) 39192889Sobrien short sid; 39226219Swpaul{ 39392889Sobrien int i; 39492889Sobrien short curr; 39592889Sobrien short prev; 39626219Swpaul 39726219Swpaul prev = authdes_lru[0]; 39826219Swpaul authdes_lru[0] = sid; 39926219Swpaul for (i = 1; prev != sid; i++) { 40026219Swpaul curr = authdes_lru[i]; 40126219Swpaul authdes_lru[i] = prev; 40226219Swpaul prev = curr; 40326219Swpaul } 40426219Swpaul} 40526219Swpaul 40626219Swpaul 40726219Swpaul/* 40826219Swpaul * Find a spot in the cache for a credential containing 40926219Swpaul * the items given. Return -1 if a replay is detected, otherwise 41026219Swpaul * return the spot in the cache. 41126219Swpaul */ 41226219Swpaulstatic short 41326219Swpaulcache_spot(key, name, timestamp) 41492889Sobrien des_block *key; 41526219Swpaul char *name; 41626219Swpaul struct timeval *timestamp; 41726219Swpaul{ 41892889Sobrien struct cache_entry *cp; 41992889Sobrien int i; 42092889Sobrien u_long hi; 42126219Swpaul 42226219Swpaul hi = key->key.high; 42326219Swpaul for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { 42426219Swpaul if (cp->key.key.high == hi && 42526219Swpaul cp->key.key.low == key->key.low && 42626219Swpaul cp->rname != NULL && 42726219Swpaul bcmp(cp->rname, name, strlen(name) + 1) == 0) { 42826219Swpaul if (BEFORE(timestamp, &cp->laststamp)) { 42926219Swpaul svcauthdes_stats.ncachereplays++; 43026219Swpaul return (-1); /* replay */ 43126219Swpaul } 43226219Swpaul svcauthdes_stats.ncachehits++; 43326219Swpaul return (i); /* refresh */ 43426219Swpaul } 43526219Swpaul } 43626219Swpaul svcauthdes_stats.ncachemisses++; 43726219Swpaul return (cache_victim()); /* new credential */ 43826219Swpaul} 43926219Swpaul 44026219Swpaul 44126219Swpaul#if (defined(sun) || defined(vax) || defined(__FreeBSD__)) 44226219Swpaul/* 44326219Swpaul * Local credential handling stuff. 44426219Swpaul * NOTE: bsd unix dependent. 44526219Swpaul * Other operating systems should put something else here. 44626219Swpaul */ 44726219Swpaul#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ 44826219Swpaul#define INVALID -1 /* grouplen, if cache entry is invalid */ 44926219Swpaul 45026219Swpaulstruct bsdcred { 451201959Sbrooks uid_t uid; /* cached uid */ 452201959Sbrooks gid_t gid; /* cached gid */ 453201959Sbrooks int grouplen; /* length of cached groups */ 454201959Sbrooks gid_t groups[NGRPS]; /* cached groups */ 45526219Swpaul}; 45626219Swpaul 45726219Swpaul/* 45826219Swpaul * Map a des credential into a unix cred. 45926219Swpaul * We cache the credential here so the application does 46026219Swpaul * not have to make an rpc call every time to interpret 46126219Swpaul * the credential. 46226219Swpaul */ 46326219Swpaulint 46426219Swpaulauthdes_getucred(adc, uid, gid, grouplen, groups) 46526219Swpaul struct authdes_cred *adc; 46626219Swpaul uid_t *uid; 46726219Swpaul gid_t *gid; 46826219Swpaul int *grouplen; 46992889Sobrien gid_t *groups; 47026219Swpaul{ 47126219Swpaul unsigned sid; 47292889Sobrien int i; 47326219Swpaul uid_t i_uid; 47426219Swpaul gid_t i_gid; 47526219Swpaul int i_grouplen; 47626219Swpaul struct bsdcred *cred; 47726219Swpaul 47826219Swpaul sid = adc->adc_nickname; 47926219Swpaul if (sid >= AUTHDES_CACHESZ) { 48026219Swpaul debug("invalid nickname"); 48126219Swpaul return (0); 48226219Swpaul } 48326219Swpaul cred = (struct bsdcred *)authdes_cache[sid].localcred; 48426219Swpaul if (cred == NULL) { 48526219Swpaul cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); 48626219Swpaul authdes_cache[sid].localcred = (char *)cred; 48726219Swpaul cred->grouplen = INVALID; 48826219Swpaul } 48926219Swpaul if (cred->grouplen == INVALID) { 49026219Swpaul /* 49126219Swpaul * not in cache: lookup 49226219Swpaul */ 49326219Swpaul if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, 49426219Swpaul &i_grouplen, groups)) 49526219Swpaul { 49626219Swpaul debug("unknown netname"); 49726219Swpaul cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ 49826219Swpaul return (0); 49926219Swpaul } 50026219Swpaul debug("missed ucred cache"); 50126219Swpaul *uid = cred->uid = i_uid; 50226219Swpaul *gid = cred->gid = i_gid; 50326219Swpaul *grouplen = cred->grouplen = i_grouplen; 50426219Swpaul for (i = i_grouplen - 1; i >= 0; i--) { 50526219Swpaul cred->groups[i] = groups[i]; /* int to short */ 50626219Swpaul } 50726219Swpaul return (1); 50826219Swpaul } else if (cred->grouplen == UNKNOWN) { 50926219Swpaul /* 51026219Swpaul * Already lookup up, but no match found 51126219Swpaul */ 51226219Swpaul return (0); 51326219Swpaul } 51426219Swpaul 51526219Swpaul /* 51626219Swpaul * cached credentials 51726219Swpaul */ 51826219Swpaul *uid = cred->uid; 51926219Swpaul *gid = cred->gid; 52026219Swpaul *grouplen = cred->grouplen; 52126219Swpaul for (i = cred->grouplen - 1; i >= 0; i--) { 52226219Swpaul groups[i] = cred->groups[i]; /* short to int */ 52326219Swpaul } 52426219Swpaul return (1); 52526219Swpaul} 52626219Swpaul 52726219Swpaulstatic void 52826219Swpaulinvalidate(cred) 52926219Swpaul char *cred; 53026219Swpaul{ 53126219Swpaul if (cred == NULL) { 53226219Swpaul return; 53326219Swpaul } 53426219Swpaul ((struct bsdcred *)cred)->grouplen = INVALID; 53526219Swpaul} 53626219Swpaul#endif 53726219Swpaul 538