126219Swpaul 226219Swpaul/* 326219Swpaul * Copyright (c) 1988 by Sun Microsystems, Inc. 426219Swpaul */ 526219Swpaul 626219Swpaul/* 726219Swpaul * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 826219Swpaul * unrestricted use provided that this legend is included on all tape 926219Swpaul * media and as a part of the software program in whole or part. Users 1026219Swpaul * may copy or modify Sun RPC without charge, but are not authorized 1126219Swpaul * to license or distribute it to anyone else except as part of a product or 1226219Swpaul * program developed by the user. 1326219Swpaul * 1426219Swpaul * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1526219Swpaul * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1626219Swpaul * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1726219Swpaul * 1826219Swpaul * Sun RPC is provided with no support and without any obligation on the 1926219Swpaul * part of Sun Microsystems, Inc. to assist in its use, correction, 2026219Swpaul * modification or enhancement. 2126219Swpaul * 2226219Swpaul * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2326219Swpaul * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2426219Swpaul * OR ANY PART THEREOF. 2526219Swpaul * 2626219Swpaul * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2726219Swpaul * or profits or other special, indirect and consequential damages, even if 2826219Swpaul * Sun has been advised of the possibility of such damages. 2926219Swpaul * 3026219Swpaul * Sun Microsystems, Inc. 3126219Swpaul * 2550 Garcia Avenue 3226219Swpaul * Mountain View, California 94043 3326219Swpaul */ 3426219Swpaul 3526219Swpaul/* 3626219Swpaul * svcauth_des.c, server-side des authentication 3726219Swpaul * 3826219Swpaul * We insure for the service the following: 3926219Swpaul * (1) The timestamp microseconds do not exceed 1 million. 4026219Swpaul * (2) The timestamp plus the window is less than the current time. 4126219Swpaul * (3) The timestamp is not less than the one previously 4226219Swpaul * seen in the current session. 4326219Swpaul * 4426219Swpaul * It is up to the server to determine if the window size is 4526219Swpaul * too small . 4626219Swpaul * 4726219Swpaul */ 4826219Swpaul 4975094Siedowse#include "namespace.h" 5074462Salfred#include "reentrant.h" 5126219Swpaul#include <string.h> 5226219Swpaul#include <stdlib.h> 5371579Sdeischen#include <stdio.h> 5426219Swpaul#include <unistd.h> 5526219Swpaul#include <rpc/des_crypt.h> 5626219Swpaul#include <sys/param.h> 5726219Swpaul#include <netinet/in.h> 5826219Swpaul#include <rpc/types.h> 5926219Swpaul#include <rpc/xdr.h> 6026219Swpaul#include <rpc/auth.h> 6126219Swpaul#include <rpc/auth_des.h> 6226219Swpaul#include <rpc/svc.h> 6326219Swpaul#include <rpc/rpc_msg.h> 6426219Swpaul#include <rpc/svc_auth.h> 6574462Salfred#include "libc_private.h" 6626219Swpaul 6726219Swpaul#if defined(LIBC_SCCS) && !defined(lint) 6892990Sobrienstatic char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; 6926219Swpaul#endif 7092990Sobrien#include <sys/cdefs.h> 7192990Sobrien__FBSDID("$FreeBSD$"); 7226219Swpaul 7390271Salfredextern int key_decryptsession_pk(const char *, netobj *, des_block *); 7490271Salfred 7526219Swpaul#define debug(msg) printf("svcauth_des: %s\n", msg) 7626219Swpaul 7726219Swpaul#define USEC_PER_SEC ((u_long) 1000000L) 7826219Swpaul#define BEFORE(t1, t2) timercmp(t1, t2, <) 7926219Swpaul 8026219Swpaul/* 8126219Swpaul * LRU cache of conversation keys and some other useful items. 8226219Swpaul */ 8326219Swpaul#define AUTHDES_CACHESZ 64 8426219Swpaulstruct cache_entry { 8526219Swpaul des_block key; /* conversation key */ 8626219Swpaul char *rname; /* client's name */ 8726219Swpaul u_int window; /* credential lifetime window */ 8826219Swpaul struct timeval laststamp; /* detect replays of creds */ 8926219Swpaul char *localcred; /* generic local credential */ 9026219Swpaul}; 9126219Swpaulstatic struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; 9226219Swpaulstatic short *authdes_lru/* [AUTHDES_CACHESZ] */; 9326219Swpaul 9426219Swpaulstatic void cache_init(); /* initialize the cache */ 9526219Swpaulstatic short cache_spot(); /* find an entry in the cache */ 9626219Swpaulstatic void cache_ref(/*short sid*/); /* note that sid was ref'd */ 9726219Swpaul 9826219Swpaulstatic void invalidate(); /* invalidate entry in cache */ 9926219Swpaul 10026219Swpaul/* 10126219Swpaul * cache statistics 10226219Swpaul */ 10326219Swpaulstatic struct { 10426219Swpaul u_long ncachehits; /* times cache hit, and is not replay */ 10526219Swpaul u_long ncachereplays; /* times cache hit, and is replay */ 10626219Swpaul u_long ncachemisses; /* times cache missed */ 10726219Swpaul} svcauthdes_stats; 10826219Swpaul 10926219Swpaul/* 11026219Swpaul * Service side authenticator for AUTH_DES 11126219Swpaul */ 11226219Swpaulenum auth_stat 11326219Swpaul_svcauth_des(rqst, msg) 11492889Sobrien struct svc_req *rqst; 11592889Sobrien struct rpc_msg *msg; 11626219Swpaul{ 11726219Swpaul 11892889Sobrien long *ixdr; 11926219Swpaul des_block cryptbuf[2]; 12092889Sobrien struct authdes_cred *cred; 12126219Swpaul struct authdes_verf verf; 12226219Swpaul int status; 12392889Sobrien struct cache_entry *entry; 12426219Swpaul short sid = 0; 12526219Swpaul des_block *sessionkey; 12626219Swpaul des_block ivec; 12726219Swpaul u_int window; 12826219Swpaul struct timeval timestamp; 12926219Swpaul u_long namelen; 13026219Swpaul struct area { 13126219Swpaul struct authdes_cred area_cred; 13226219Swpaul char area_netname[MAXNETNAMELEN+1]; 13326219Swpaul } *area; 13426219Swpaul 13526219Swpaul if (authdes_cache == NULL) { 13626219Swpaul cache_init(); 13726219Swpaul } 13826219Swpaul 13926219Swpaul area = (struct area *)rqst->rq_clntcred; 14026219Swpaul cred = (struct authdes_cred *)&area->area_cred; 14126219Swpaul 14226219Swpaul /* 14326219Swpaul * Get the credential 14426219Swpaul */ 14526219Swpaul ixdr = (long *)msg->rm_call.cb_cred.oa_base; 14626219Swpaul cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 14726219Swpaul switch (cred->adc_namekind) { 14826219Swpaul case ADN_FULLNAME: 14926219Swpaul namelen = IXDR_GET_U_LONG(ixdr); 15026219Swpaul if (namelen > MAXNETNAMELEN) { 15126219Swpaul return (AUTH_BADCRED); 15226219Swpaul } 15326219Swpaul cred->adc_fullname.name = area->area_netname; 15426219Swpaul bcopy((char *)ixdr, cred->adc_fullname.name, 15526219Swpaul (u_int)namelen); 15626219Swpaul cred->adc_fullname.name[namelen] = 0; 15726219Swpaul ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 15826219Swpaul cred->adc_fullname.key.key.high = (u_long)*ixdr++; 15926219Swpaul cred->adc_fullname.key.key.low = (u_long)*ixdr++; 16026219Swpaul cred->adc_fullname.window = (u_long)*ixdr++; 16126219Swpaul break; 16226219Swpaul case ADN_NICKNAME: 16326219Swpaul cred->adc_nickname = (u_long)*ixdr++; 16426219Swpaul break; 16526219Swpaul default: 16626219Swpaul return (AUTH_BADCRED); 16726219Swpaul } 16826219Swpaul 16926219Swpaul /* 17026219Swpaul * Get the verifier 17126219Swpaul */ 17226219Swpaul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 17326219Swpaul verf.adv_xtimestamp.key.high = (u_long)*ixdr++; 17426219Swpaul verf.adv_xtimestamp.key.low = (u_long)*ixdr++; 17526219Swpaul verf.adv_int_u = (u_long)*ixdr++; 17626219Swpaul 17726219Swpaul 17826219Swpaul /* 17926219Swpaul * Get the conversation key 18026219Swpaul */ 18126219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 18226219Swpaul netobj pkey; 18326219Swpaul char pkey_data[1024]; 18426219Swpaul 18526219Swpaul sessionkey = &cred->adc_fullname.key; 18626219Swpaul if (! getpublickey(cred->adc_fullname.name, pkey_data)) { 18726219Swpaul debug("getpublickey"); 18826219Swpaul return(AUTH_BADCRED); 18926219Swpaul } 19026219Swpaul pkey.n_bytes = pkey_data; 19126219Swpaul pkey.n_len = strlen(pkey_data) + 1; 19226219Swpaul if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, 19326219Swpaul sessionkey) < 0) { 19426219Swpaul debug("decryptsessionkey"); 19526219Swpaul return (AUTH_BADCRED); /* key not found */ 19626219Swpaul } 19726219Swpaul } else { /* ADN_NICKNAME */ 19826219Swpaul sid = (short)cred->adc_nickname; 19974462Salfred if (sid < 0 || sid >= AUTHDES_CACHESZ) { 20026219Swpaul debug("bad nickname"); 20126219Swpaul return (AUTH_BADCRED); /* garbled credential */ 20226219Swpaul } 20326219Swpaul sessionkey = &authdes_cache[sid].key; 20426219Swpaul } 20526219Swpaul 20626219Swpaul 20726219Swpaul /* 20826219Swpaul * Decrypt the timestamp 20926219Swpaul */ 21026219Swpaul cryptbuf[0] = verf.adv_xtimestamp; 21126219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 21226219Swpaul cryptbuf[1].key.high = cred->adc_fullname.window; 21326219Swpaul cryptbuf[1].key.low = verf.adv_winverf; 21426219Swpaul ivec.key.high = ivec.key.low = 0; 21526219Swpaul status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 21626219Swpaul 2*sizeof(des_block), DES_DECRYPT | DES_HW, 21726219Swpaul (char *)&ivec); 21826219Swpaul } else { 21926219Swpaul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 22026219Swpaul sizeof(des_block), DES_DECRYPT | DES_HW); 22126219Swpaul } 22226219Swpaul if (DES_FAILED(status)) { 22326219Swpaul debug("decryption failure"); 22426219Swpaul return (AUTH_FAILED); /* system error */ 22526219Swpaul } 22626219Swpaul 22726219Swpaul /* 22826219Swpaul * XDR the decrypted timestamp 22926219Swpaul */ 23026219Swpaul ixdr = (long *)cryptbuf; 23126219Swpaul timestamp.tv_sec = IXDR_GET_LONG(ixdr); 23226219Swpaul timestamp.tv_usec = IXDR_GET_LONG(ixdr); 23326219Swpaul 23426219Swpaul /* 23526219Swpaul * Check for valid credentials and verifiers. 23626219Swpaul * They could be invalid because the key was flushed 23726219Swpaul * out of the cache, and so a new session should begin. 23826219Swpaul * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 23926219Swpaul */ 24026219Swpaul { 24126219Swpaul struct timeval current; 24226219Swpaul int nick; 24326219Swpaul int winverf; 24426219Swpaul 24526219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 24626219Swpaul window = IXDR_GET_U_LONG(ixdr); 24726219Swpaul winverf = IXDR_GET_U_LONG(ixdr); 24826219Swpaul if (winverf != window - 1) { 24926219Swpaul debug("window verifier mismatch"); 25026219Swpaul return (AUTH_BADCRED); /* garbled credential */ 25126219Swpaul } 25226219Swpaul sid = cache_spot(sessionkey, cred->adc_fullname.name, 25326219Swpaul ×tamp); 25426219Swpaul if (sid < 0) { 25526219Swpaul debug("replayed credential"); 25626219Swpaul return (AUTH_REJECTEDCRED); /* replay */ 25726219Swpaul } 25826219Swpaul nick = 0; 25926219Swpaul } else { /* ADN_NICKNAME */ 26026219Swpaul window = authdes_cache[sid].window; 26126219Swpaul nick = 1; 26226219Swpaul } 26326219Swpaul 26426219Swpaul if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { 26526219Swpaul debug("invalid usecs"); 26626219Swpaul /* cached out (bad key), or garbled verifier */ 26726219Swpaul return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 26826219Swpaul } 26926219Swpaul if (nick && BEFORE(×tamp, 27026219Swpaul &authdes_cache[sid].laststamp)) { 27126219Swpaul debug("timestamp before last seen"); 27226219Swpaul return (AUTH_REJECTEDVERF); /* replay */ 27326219Swpaul } 274239991Sed (void)gettimeofday(¤t, NULL); 27526219Swpaul current.tv_sec -= window; /* allow for expiration */ 27626219Swpaul if (!BEFORE(¤t, ×tamp)) { 27726219Swpaul debug("timestamp expired"); 27826219Swpaul /* replay, or garbled credential */ 27926219Swpaul return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 28026219Swpaul } 28126219Swpaul } 28226219Swpaul 28326219Swpaul /* 28426219Swpaul * Set up the reply verifier 28526219Swpaul */ 28626219Swpaul verf.adv_nickname = (u_long)sid; 28726219Swpaul 28826219Swpaul /* 28926219Swpaul * xdr the timestamp before encrypting 29026219Swpaul */ 29126219Swpaul ixdr = (long *)cryptbuf; 29226219Swpaul IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); 29326219Swpaul IXDR_PUT_LONG(ixdr, timestamp.tv_usec); 29426219Swpaul 29526219Swpaul /* 29626219Swpaul * encrypt the timestamp 29726219Swpaul */ 29826219Swpaul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 29926219Swpaul sizeof(des_block), DES_ENCRYPT | DES_HW); 30026219Swpaul if (DES_FAILED(status)) { 30126219Swpaul debug("encryption failure"); 30226219Swpaul return (AUTH_FAILED); /* system error */ 30326219Swpaul } 30426219Swpaul verf.adv_xtimestamp = cryptbuf[0]; 30526219Swpaul 30626219Swpaul /* 30726219Swpaul * Serialize the reply verifier, and update rqst 30826219Swpaul */ 30926219Swpaul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 31026219Swpaul *ixdr++ = (long)verf.adv_xtimestamp.key.high; 31126219Swpaul *ixdr++ = (long)verf.adv_xtimestamp.key.low; 31226219Swpaul *ixdr++ = (long)verf.adv_int_u; 31326219Swpaul 31426219Swpaul rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 31526219Swpaul rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 31626219Swpaul rqst->rq_xprt->xp_verf.oa_length = 31726219Swpaul (char *)ixdr - msg->rm_call.cb_verf.oa_base; 31826219Swpaul 31926219Swpaul /* 32026219Swpaul * We succeeded, commit the data to the cache now and 32126219Swpaul * finish cooking the credential. 32226219Swpaul */ 32326219Swpaul entry = &authdes_cache[sid]; 32426219Swpaul entry->laststamp = timestamp; 32526219Swpaul cache_ref(sid); 32626219Swpaul if (cred->adc_namekind == ADN_FULLNAME) { 32726219Swpaul cred->adc_fullname.window = window; 32826219Swpaul cred->adc_nickname = (u_long)sid; /* save nickname */ 32926219Swpaul if (entry->rname != NULL) { 33026219Swpaul mem_free(entry->rname, strlen(entry->rname) + 1); 33126219Swpaul } 33226219Swpaul entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name) 33326219Swpaul + 1); 33426219Swpaul if (entry->rname != NULL) { 33526219Swpaul (void) strcpy(entry->rname, cred->adc_fullname.name); 33626219Swpaul } else { 33726219Swpaul debug("out of memory"); 33826219Swpaul } 33926219Swpaul entry->key = *sessionkey; 34026219Swpaul entry->window = window; 34126219Swpaul invalidate(entry->localcred); /* mark any cached cred invalid */ 34226219Swpaul } else { /* ADN_NICKNAME */ 34326219Swpaul /* 34426219Swpaul * nicknames are cooked into fullnames 34526219Swpaul */ 34626219Swpaul cred->adc_namekind = ADN_FULLNAME; 34726219Swpaul cred->adc_fullname.name = entry->rname; 34826219Swpaul cred->adc_fullname.key = entry->key; 34926219Swpaul cred->adc_fullname.window = entry->window; 35026219Swpaul } 35126219Swpaul return (AUTH_OK); /* we made it!*/ 35226219Swpaul} 35326219Swpaul 35426219Swpaul 35526219Swpaul/* 35626219Swpaul * Initialize the cache 35726219Swpaul */ 35826219Swpaulstatic void 35926219Swpaulcache_init() 36026219Swpaul{ 36192889Sobrien int i; 36226219Swpaul 36326219Swpaul authdes_cache = (struct cache_entry *) 36426219Swpaul mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ); 36526219Swpaul bzero((char *)authdes_cache, 36626219Swpaul sizeof(struct cache_entry) * AUTHDES_CACHESZ); 36726219Swpaul 36826219Swpaul authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); 36926219Swpaul /* 37026219Swpaul * Initialize the lru list 37126219Swpaul */ 37226219Swpaul for (i = 0; i < AUTHDES_CACHESZ; i++) { 37326219Swpaul authdes_lru[i] = i; 37426219Swpaul } 37526219Swpaul} 37626219Swpaul 37726219Swpaul 37826219Swpaul/* 37926219Swpaul * Find the lru victim 38026219Swpaul */ 38126219Swpaulstatic short 38226219Swpaulcache_victim() 38326219Swpaul{ 38426219Swpaul return (authdes_lru[AUTHDES_CACHESZ-1]); 38526219Swpaul} 38626219Swpaul 38726219Swpaul/* 38826219Swpaul * Note that sid was referenced 38926219Swpaul */ 39026219Swpaulstatic void 39126219Swpaulcache_ref(sid) 39292889Sobrien short sid; 39326219Swpaul{ 39492889Sobrien int i; 39592889Sobrien short curr; 39692889Sobrien short prev; 39726219Swpaul 39826219Swpaul prev = authdes_lru[0]; 39926219Swpaul authdes_lru[0] = sid; 40026219Swpaul for (i = 1; prev != sid; i++) { 40126219Swpaul curr = authdes_lru[i]; 40226219Swpaul authdes_lru[i] = prev; 40326219Swpaul prev = curr; 40426219Swpaul } 40526219Swpaul} 40626219Swpaul 40726219Swpaul 40826219Swpaul/* 40926219Swpaul * Find a spot in the cache for a credential containing 41026219Swpaul * the items given. Return -1 if a replay is detected, otherwise 41126219Swpaul * return the spot in the cache. 41226219Swpaul */ 41326219Swpaulstatic short 41426219Swpaulcache_spot(key, name, timestamp) 41592889Sobrien des_block *key; 41626219Swpaul char *name; 41726219Swpaul struct timeval *timestamp; 41826219Swpaul{ 41992889Sobrien struct cache_entry *cp; 42092889Sobrien int i; 42192889Sobrien u_long hi; 42226219Swpaul 42326219Swpaul hi = key->key.high; 42426219Swpaul for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { 42526219Swpaul if (cp->key.key.high == hi && 42626219Swpaul cp->key.key.low == key->key.low && 42726219Swpaul cp->rname != NULL && 42826219Swpaul bcmp(cp->rname, name, strlen(name) + 1) == 0) { 42926219Swpaul if (BEFORE(timestamp, &cp->laststamp)) { 43026219Swpaul svcauthdes_stats.ncachereplays++; 43126219Swpaul return (-1); /* replay */ 43226219Swpaul } 43326219Swpaul svcauthdes_stats.ncachehits++; 43426219Swpaul return (i); /* refresh */ 43526219Swpaul } 43626219Swpaul } 43726219Swpaul svcauthdes_stats.ncachemisses++; 43826219Swpaul return (cache_victim()); /* new credential */ 43926219Swpaul} 44026219Swpaul 44126219Swpaul 44226219Swpaul#if (defined(sun) || defined(vax) || defined(__FreeBSD__)) 44326219Swpaul/* 44426219Swpaul * Local credential handling stuff. 44526219Swpaul * NOTE: bsd unix dependent. 44626219Swpaul * Other operating systems should put something else here. 44726219Swpaul */ 44826219Swpaul#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ 44926219Swpaul#define INVALID -1 /* grouplen, if cache entry is invalid */ 45026219Swpaul 45126219Swpaulstruct bsdcred { 452201959Sbrooks uid_t uid; /* cached uid */ 453201959Sbrooks gid_t gid; /* cached gid */ 454201959Sbrooks int grouplen; /* length of cached groups */ 455201959Sbrooks gid_t groups[NGRPS]; /* cached groups */ 45626219Swpaul}; 45726219Swpaul 45826219Swpaul/* 45926219Swpaul * Map a des credential into a unix cred. 46026219Swpaul * We cache the credential here so the application does 46126219Swpaul * not have to make an rpc call every time to interpret 46226219Swpaul * the credential. 46326219Swpaul */ 46426219Swpaulint 46526219Swpaulauthdes_getucred(adc, uid, gid, grouplen, groups) 46626219Swpaul struct authdes_cred *adc; 46726219Swpaul uid_t *uid; 46826219Swpaul gid_t *gid; 46926219Swpaul int *grouplen; 47092889Sobrien gid_t *groups; 47126219Swpaul{ 47226219Swpaul unsigned sid; 47392889Sobrien int i; 47426219Swpaul uid_t i_uid; 47526219Swpaul gid_t i_gid; 47626219Swpaul int i_grouplen; 47726219Swpaul struct bsdcred *cred; 47826219Swpaul 47926219Swpaul sid = adc->adc_nickname; 48026219Swpaul if (sid >= AUTHDES_CACHESZ) { 48126219Swpaul debug("invalid nickname"); 48226219Swpaul return (0); 48326219Swpaul } 48426219Swpaul cred = (struct bsdcred *)authdes_cache[sid].localcred; 48526219Swpaul if (cred == NULL) { 48626219Swpaul cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); 48726219Swpaul authdes_cache[sid].localcred = (char *)cred; 48826219Swpaul cred->grouplen = INVALID; 48926219Swpaul } 49026219Swpaul if (cred->grouplen == INVALID) { 49126219Swpaul /* 49226219Swpaul * not in cache: lookup 49326219Swpaul */ 49426219Swpaul if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, 49526219Swpaul &i_grouplen, groups)) 49626219Swpaul { 49726219Swpaul debug("unknown netname"); 49826219Swpaul cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ 49926219Swpaul return (0); 50026219Swpaul } 50126219Swpaul debug("missed ucred cache"); 50226219Swpaul *uid = cred->uid = i_uid; 50326219Swpaul *gid = cred->gid = i_gid; 50426219Swpaul *grouplen = cred->grouplen = i_grouplen; 50526219Swpaul for (i = i_grouplen - 1; i >= 0; i--) { 50626219Swpaul cred->groups[i] = groups[i]; /* int to short */ 50726219Swpaul } 50826219Swpaul return (1); 50926219Swpaul } else if (cred->grouplen == UNKNOWN) { 51026219Swpaul /* 51126219Swpaul * Already lookup up, but no match found 51226219Swpaul */ 51326219Swpaul return (0); 51426219Swpaul } 51526219Swpaul 51626219Swpaul /* 51726219Swpaul * cached credentials 51826219Swpaul */ 51926219Swpaul *uid = cred->uid; 52026219Swpaul *gid = cred->gid; 52126219Swpaul *grouplen = cred->grouplen; 52226219Swpaul for (i = cred->grouplen - 1; i >= 0; i--) { 52326219Swpaul groups[i] = cred->groups[i]; /* short to int */ 52426219Swpaul } 52526219Swpaul return (1); 52626219Swpaul} 52726219Swpaul 52826219Swpaulstatic void 52926219Swpaulinvalidate(cred) 53026219Swpaul char *cred; 53126219Swpaul{ 53226219Swpaul if (cred == NULL) { 53326219Swpaul return; 53426219Swpaul } 53526219Swpaul ((struct bsdcred *)cred)->grouplen = INVALID; 53626219Swpaul} 53726219Swpaul#endif 53826219Swpaul 539