1e8636dfdSBill Paul 2e8636dfdSBill Paul /* 3e8636dfdSBill Paul * Copyright (c) 1988 by Sun Microsystems, Inc. 4e8636dfdSBill Paul */ 5e8636dfdSBill Paul 6*2e322d37SHiroki Sato /*- 7*2e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc. 8*2e322d37SHiroki Sato * All rights reserved. 9e8636dfdSBill Paul * 10*2e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without 11*2e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met: 12*2e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 13*2e322d37SHiroki Sato * this list of conditions and the following disclaimer. 14*2e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 15*2e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation 16*2e322d37SHiroki Sato * and/or other materials provided with the distribution. 17*2e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its 18*2e322d37SHiroki Sato * contributors may be used to endorse or promote products derived 19*2e322d37SHiroki Sato * from this software without specific prior written permission. 20e8636dfdSBill Paul * 21*2e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22*2e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*2e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*2e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25*2e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26*2e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27*2e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28*2e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29*2e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30*2e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31*2e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE. 32e8636dfdSBill Paul */ 33e8636dfdSBill Paul 34e8636dfdSBill Paul /* 35e8636dfdSBill Paul * svcauth_des.c, server-side des authentication 36e8636dfdSBill Paul * 37e8636dfdSBill Paul * We insure for the service the following: 38e8636dfdSBill Paul * (1) The timestamp microseconds do not exceed 1 million. 39e8636dfdSBill Paul * (2) The timestamp plus the window is less than the current time. 40e8636dfdSBill Paul * (3) The timestamp is not less than the one previously 41e8636dfdSBill Paul * seen in the current session. 42e8636dfdSBill Paul * 43e8636dfdSBill Paul * It is up to the server to determine if the window size is 44e8636dfdSBill Paul * too small . 45e8636dfdSBill Paul * 46e8636dfdSBill Paul */ 47e8636dfdSBill Paul 488360efbdSAlfred Perlstein #include "namespace.h" 499f5afc13SIan Dowse #include "reentrant.h" 50e8636dfdSBill Paul #include <string.h> 51e8636dfdSBill Paul #include <stdlib.h> 52d201fe46SDaniel Eischen #include <stdio.h> 53e8636dfdSBill Paul #include <unistd.h> 54e8636dfdSBill Paul #include <rpc/des_crypt.h> 55e8636dfdSBill Paul #include <sys/param.h> 56e8636dfdSBill Paul #include <netinet/in.h> 57e8636dfdSBill Paul #include <rpc/types.h> 58e8636dfdSBill Paul #include <rpc/xdr.h> 59e8636dfdSBill Paul #include <rpc/auth.h> 60e8636dfdSBill Paul #include <rpc/auth_des.h> 61e8636dfdSBill Paul #include <rpc/svc.h> 62e8636dfdSBill Paul #include <rpc/rpc_msg.h> 63e8636dfdSBill Paul #include <rpc/svc_auth.h> 648360efbdSAlfred Perlstein #include "libc_private.h" 65e8636dfdSBill Paul 66e8636dfdSBill Paul #if defined(LIBC_SCCS) && !defined(lint) 67d3d20c82SDavid E. O'Brien static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; 68e8636dfdSBill Paul #endif 69d3d20c82SDavid E. O'Brien #include <sys/cdefs.h> 70d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$"); 71e8636dfdSBill Paul 728d630135SAlfred Perlstein extern int key_decryptsession_pk(const char *, netobj *, des_block *); 738d630135SAlfred Perlstein 74e8636dfdSBill Paul #define debug(msg) printf("svcauth_des: %s\n", msg) 75e8636dfdSBill Paul 76e8636dfdSBill Paul #define USEC_PER_SEC ((u_long) 1000000L) 77e8636dfdSBill Paul #define BEFORE(t1, t2) timercmp(t1, t2, <) 78e8636dfdSBill Paul 79e8636dfdSBill Paul /* 80e8636dfdSBill Paul * LRU cache of conversation keys and some other useful items. 81e8636dfdSBill Paul */ 82e8636dfdSBill Paul #define AUTHDES_CACHESZ 64 83e8636dfdSBill Paul struct cache_entry { 84e8636dfdSBill Paul des_block key; /* conversation key */ 85e8636dfdSBill Paul char *rname; /* client's name */ 86e8636dfdSBill Paul u_int window; /* credential lifetime window */ 87e8636dfdSBill Paul struct timeval laststamp; /* detect replays of creds */ 88e8636dfdSBill Paul char *localcred; /* generic local credential */ 89e8636dfdSBill Paul }; 90e8636dfdSBill Paul static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; 91e8636dfdSBill Paul static short *authdes_lru/* [AUTHDES_CACHESZ] */; 92e8636dfdSBill Paul 93e8636dfdSBill Paul static void cache_init(); /* initialize the cache */ 94e8636dfdSBill Paul static short cache_spot(); /* find an entry in the cache */ 95e8636dfdSBill Paul static void cache_ref(/*short sid*/); /* note that sid was ref'd */ 96e8636dfdSBill Paul 97e8636dfdSBill Paul static void invalidate(); /* invalidate entry in cache */ 98e8636dfdSBill Paul 99e8636dfdSBill Paul /* 100e8636dfdSBill Paul * cache statistics 101e8636dfdSBill Paul */ 102e8636dfdSBill Paul static struct { 103e8636dfdSBill Paul u_long ncachehits; /* times cache hit, and is not replay */ 104e8636dfdSBill Paul u_long ncachereplays; /* times cache hit, and is replay */ 105e8636dfdSBill Paul u_long ncachemisses; /* times cache missed */ 106e8636dfdSBill Paul } svcauthdes_stats; 107e8636dfdSBill Paul 108e8636dfdSBill Paul /* 109e8636dfdSBill Paul * Service side authenticator for AUTH_DES 110e8636dfdSBill Paul */ 111e8636dfdSBill Paul enum auth_stat 112e8636dfdSBill Paul _svcauth_des(rqst, msg) 1138fb3f3f6SDavid E. O'Brien struct svc_req *rqst; 1148fb3f3f6SDavid E. O'Brien struct rpc_msg *msg; 115e8636dfdSBill Paul { 116e8636dfdSBill Paul 1178fb3f3f6SDavid E. O'Brien long *ixdr; 118e8636dfdSBill Paul des_block cryptbuf[2]; 1198fb3f3f6SDavid E. O'Brien struct authdes_cred *cred; 120e8636dfdSBill Paul struct authdes_verf verf; 121e8636dfdSBill Paul int status; 1228fb3f3f6SDavid E. O'Brien struct cache_entry *entry; 123e8636dfdSBill Paul short sid = 0; 124e8636dfdSBill Paul des_block *sessionkey; 125e8636dfdSBill Paul des_block ivec; 126e8636dfdSBill Paul u_int window; 127e8636dfdSBill Paul struct timeval timestamp; 128e8636dfdSBill Paul u_long namelen; 129e8636dfdSBill Paul struct area { 130e8636dfdSBill Paul struct authdes_cred area_cred; 131e8636dfdSBill Paul char area_netname[MAXNETNAMELEN+1]; 132e8636dfdSBill Paul } *area; 133e8636dfdSBill Paul 134e8636dfdSBill Paul if (authdes_cache == NULL) { 135e8636dfdSBill Paul cache_init(); 136e8636dfdSBill Paul } 137e8636dfdSBill Paul 138e8636dfdSBill Paul area = (struct area *)rqst->rq_clntcred; 139e8636dfdSBill Paul cred = (struct authdes_cred *)&area->area_cred; 140e8636dfdSBill Paul 141e8636dfdSBill Paul /* 142e8636dfdSBill Paul * Get the credential 143e8636dfdSBill Paul */ 144e8636dfdSBill Paul ixdr = (long *)msg->rm_call.cb_cred.oa_base; 145e8636dfdSBill Paul cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); 146e8636dfdSBill Paul switch (cred->adc_namekind) { 147e8636dfdSBill Paul case ADN_FULLNAME: 148e8636dfdSBill Paul namelen = IXDR_GET_U_LONG(ixdr); 149e8636dfdSBill Paul if (namelen > MAXNETNAMELEN) { 150e8636dfdSBill Paul return (AUTH_BADCRED); 151e8636dfdSBill Paul } 152e8636dfdSBill Paul cred->adc_fullname.name = area->area_netname; 153e8636dfdSBill Paul bcopy((char *)ixdr, cred->adc_fullname.name, 154e8636dfdSBill Paul (u_int)namelen); 155e8636dfdSBill Paul cred->adc_fullname.name[namelen] = 0; 156e8636dfdSBill Paul ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); 157e8636dfdSBill Paul cred->adc_fullname.key.key.high = (u_long)*ixdr++; 158e8636dfdSBill Paul cred->adc_fullname.key.key.low = (u_long)*ixdr++; 159e8636dfdSBill Paul cred->adc_fullname.window = (u_long)*ixdr++; 160e8636dfdSBill Paul break; 161e8636dfdSBill Paul case ADN_NICKNAME: 162e8636dfdSBill Paul cred->adc_nickname = (u_long)*ixdr++; 163e8636dfdSBill Paul break; 164e8636dfdSBill Paul default: 165e8636dfdSBill Paul return (AUTH_BADCRED); 166e8636dfdSBill Paul } 167e8636dfdSBill Paul 168e8636dfdSBill Paul /* 169e8636dfdSBill Paul * Get the verifier 170e8636dfdSBill Paul */ 171e8636dfdSBill Paul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 172e8636dfdSBill Paul verf.adv_xtimestamp.key.high = (u_long)*ixdr++; 173e8636dfdSBill Paul verf.adv_xtimestamp.key.low = (u_long)*ixdr++; 174e8636dfdSBill Paul verf.adv_int_u = (u_long)*ixdr++; 175e8636dfdSBill Paul 176e8636dfdSBill Paul 177e8636dfdSBill Paul /* 178e8636dfdSBill Paul * Get the conversation key 179e8636dfdSBill Paul */ 180e8636dfdSBill Paul if (cred->adc_namekind == ADN_FULLNAME) { 181e8636dfdSBill Paul netobj pkey; 182e8636dfdSBill Paul char pkey_data[1024]; 183e8636dfdSBill Paul 184e8636dfdSBill Paul sessionkey = &cred->adc_fullname.key; 185e8636dfdSBill Paul if (! getpublickey(cred->adc_fullname.name, pkey_data)) { 186e8636dfdSBill Paul debug("getpublickey"); 187e8636dfdSBill Paul return(AUTH_BADCRED); 188e8636dfdSBill Paul } 189e8636dfdSBill Paul pkey.n_bytes = pkey_data; 190e8636dfdSBill Paul pkey.n_len = strlen(pkey_data) + 1; 191e8636dfdSBill Paul if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, 192e8636dfdSBill Paul sessionkey) < 0) { 193e8636dfdSBill Paul debug("decryptsessionkey"); 194e8636dfdSBill Paul return (AUTH_BADCRED); /* key not found */ 195e8636dfdSBill Paul } 196e8636dfdSBill Paul } else { /* ADN_NICKNAME */ 197e8636dfdSBill Paul sid = (short)cred->adc_nickname; 1988360efbdSAlfred Perlstein if (sid < 0 || sid >= AUTHDES_CACHESZ) { 199e8636dfdSBill Paul debug("bad nickname"); 200e8636dfdSBill Paul return (AUTH_BADCRED); /* garbled credential */ 201e8636dfdSBill Paul } 202e8636dfdSBill Paul sessionkey = &authdes_cache[sid].key; 203e8636dfdSBill Paul } 204e8636dfdSBill Paul 205e8636dfdSBill Paul 206e8636dfdSBill Paul /* 207e8636dfdSBill Paul * Decrypt the timestamp 208e8636dfdSBill Paul */ 209e8636dfdSBill Paul cryptbuf[0] = verf.adv_xtimestamp; 210e8636dfdSBill Paul if (cred->adc_namekind == ADN_FULLNAME) { 211e8636dfdSBill Paul cryptbuf[1].key.high = cred->adc_fullname.window; 212e8636dfdSBill Paul cryptbuf[1].key.low = verf.adv_winverf; 213e8636dfdSBill Paul ivec.key.high = ivec.key.low = 0; 214e8636dfdSBill Paul status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, 215e8636dfdSBill Paul 2*sizeof(des_block), DES_DECRYPT | DES_HW, 216e8636dfdSBill Paul (char *)&ivec); 217e8636dfdSBill Paul } else { 218e8636dfdSBill Paul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 219e8636dfdSBill Paul sizeof(des_block), DES_DECRYPT | DES_HW); 220e8636dfdSBill Paul } 221e8636dfdSBill Paul if (DES_FAILED(status)) { 222e8636dfdSBill Paul debug("decryption failure"); 223e8636dfdSBill Paul return (AUTH_FAILED); /* system error */ 224e8636dfdSBill Paul } 225e8636dfdSBill Paul 226e8636dfdSBill Paul /* 227e8636dfdSBill Paul * XDR the decrypted timestamp 228e8636dfdSBill Paul */ 229e8636dfdSBill Paul ixdr = (long *)cryptbuf; 230e8636dfdSBill Paul timestamp.tv_sec = IXDR_GET_LONG(ixdr); 231e8636dfdSBill Paul timestamp.tv_usec = IXDR_GET_LONG(ixdr); 232e8636dfdSBill Paul 233e8636dfdSBill Paul /* 234e8636dfdSBill Paul * Check for valid credentials and verifiers. 235e8636dfdSBill Paul * They could be invalid because the key was flushed 236e8636dfdSBill Paul * out of the cache, and so a new session should begin. 237e8636dfdSBill Paul * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. 238e8636dfdSBill Paul */ 239e8636dfdSBill Paul { 240e8636dfdSBill Paul struct timeval current; 241e8636dfdSBill Paul int nick; 242e8636dfdSBill Paul int winverf; 243e8636dfdSBill Paul 244e8636dfdSBill Paul if (cred->adc_namekind == ADN_FULLNAME) { 245e8636dfdSBill Paul window = IXDR_GET_U_LONG(ixdr); 246e8636dfdSBill Paul winverf = IXDR_GET_U_LONG(ixdr); 247e8636dfdSBill Paul if (winverf != window - 1) { 248e8636dfdSBill Paul debug("window verifier mismatch"); 249e8636dfdSBill Paul return (AUTH_BADCRED); /* garbled credential */ 250e8636dfdSBill Paul } 251e8636dfdSBill Paul sid = cache_spot(sessionkey, cred->adc_fullname.name, 252e8636dfdSBill Paul ×tamp); 253e8636dfdSBill Paul if (sid < 0) { 254e8636dfdSBill Paul debug("replayed credential"); 255e8636dfdSBill Paul return (AUTH_REJECTEDCRED); /* replay */ 256e8636dfdSBill Paul } 257e8636dfdSBill Paul nick = 0; 258e8636dfdSBill Paul } else { /* ADN_NICKNAME */ 259e8636dfdSBill Paul window = authdes_cache[sid].window; 260e8636dfdSBill Paul nick = 1; 261e8636dfdSBill Paul } 262e8636dfdSBill Paul 263e8636dfdSBill Paul if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { 264e8636dfdSBill Paul debug("invalid usecs"); 265e8636dfdSBill Paul /* cached out (bad key), or garbled verifier */ 266e8636dfdSBill Paul return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); 267e8636dfdSBill Paul } 268e8636dfdSBill Paul if (nick && BEFORE(×tamp, 269e8636dfdSBill Paul &authdes_cache[sid].laststamp)) { 270e8636dfdSBill Paul debug("timestamp before last seen"); 271e8636dfdSBill Paul return (AUTH_REJECTEDVERF); /* replay */ 272e8636dfdSBill Paul } 273902d9eafSEd Schouten (void)gettimeofday(¤t, NULL); 274e8636dfdSBill Paul current.tv_sec -= window; /* allow for expiration */ 275e8636dfdSBill Paul if (!BEFORE(¤t, ×tamp)) { 276e8636dfdSBill Paul debug("timestamp expired"); 277e8636dfdSBill Paul /* replay, or garbled credential */ 278e8636dfdSBill Paul return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); 279e8636dfdSBill Paul } 280e8636dfdSBill Paul } 281e8636dfdSBill Paul 282e8636dfdSBill Paul /* 283e8636dfdSBill Paul * Set up the reply verifier 284e8636dfdSBill Paul */ 285e8636dfdSBill Paul verf.adv_nickname = (u_long)sid; 286e8636dfdSBill Paul 287e8636dfdSBill Paul /* 288e8636dfdSBill Paul * xdr the timestamp before encrypting 289e8636dfdSBill Paul */ 290e8636dfdSBill Paul ixdr = (long *)cryptbuf; 291e8636dfdSBill Paul IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); 292e8636dfdSBill Paul IXDR_PUT_LONG(ixdr, timestamp.tv_usec); 293e8636dfdSBill Paul 294e8636dfdSBill Paul /* 295e8636dfdSBill Paul * encrypt the timestamp 296e8636dfdSBill Paul */ 297e8636dfdSBill Paul status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, 298e8636dfdSBill Paul sizeof(des_block), DES_ENCRYPT | DES_HW); 299e8636dfdSBill Paul if (DES_FAILED(status)) { 300e8636dfdSBill Paul debug("encryption failure"); 301e8636dfdSBill Paul return (AUTH_FAILED); /* system error */ 302e8636dfdSBill Paul } 303e8636dfdSBill Paul verf.adv_xtimestamp = cryptbuf[0]; 304e8636dfdSBill Paul 305e8636dfdSBill Paul /* 306e8636dfdSBill Paul * Serialize the reply verifier, and update rqst 307e8636dfdSBill Paul */ 308e8636dfdSBill Paul ixdr = (long *)msg->rm_call.cb_verf.oa_base; 309e8636dfdSBill Paul *ixdr++ = (long)verf.adv_xtimestamp.key.high; 310e8636dfdSBill Paul *ixdr++ = (long)verf.adv_xtimestamp.key.low; 311e8636dfdSBill Paul *ixdr++ = (long)verf.adv_int_u; 312e8636dfdSBill Paul 313e8636dfdSBill Paul rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; 314e8636dfdSBill Paul rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 315e8636dfdSBill Paul rqst->rq_xprt->xp_verf.oa_length = 316e8636dfdSBill Paul (char *)ixdr - msg->rm_call.cb_verf.oa_base; 317e8636dfdSBill Paul 318e8636dfdSBill Paul /* 319e8636dfdSBill Paul * We succeeded, commit the data to the cache now and 320e8636dfdSBill Paul * finish cooking the credential. 321e8636dfdSBill Paul */ 322e8636dfdSBill Paul entry = &authdes_cache[sid]; 323e8636dfdSBill Paul entry->laststamp = timestamp; 324e8636dfdSBill Paul cache_ref(sid); 325e8636dfdSBill Paul if (cred->adc_namekind == ADN_FULLNAME) { 326e8636dfdSBill Paul cred->adc_fullname.window = window; 327e8636dfdSBill Paul cred->adc_nickname = (u_long)sid; /* save nickname */ 328e8636dfdSBill Paul if (entry->rname != NULL) { 329e8636dfdSBill Paul mem_free(entry->rname, strlen(entry->rname) + 1); 330e8636dfdSBill Paul } 331e8636dfdSBill Paul entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name) 332e8636dfdSBill Paul + 1); 333e8636dfdSBill Paul if (entry->rname != NULL) { 334e8636dfdSBill Paul (void) strcpy(entry->rname, cred->adc_fullname.name); 335e8636dfdSBill Paul } else { 336e8636dfdSBill Paul debug("out of memory"); 337e8636dfdSBill Paul } 338e8636dfdSBill Paul entry->key = *sessionkey; 339e8636dfdSBill Paul entry->window = window; 340e8636dfdSBill Paul invalidate(entry->localcred); /* mark any cached cred invalid */ 341e8636dfdSBill Paul } else { /* ADN_NICKNAME */ 342e8636dfdSBill Paul /* 343e8636dfdSBill Paul * nicknames are cooked into fullnames 344e8636dfdSBill Paul */ 345e8636dfdSBill Paul cred->adc_namekind = ADN_FULLNAME; 346e8636dfdSBill Paul cred->adc_fullname.name = entry->rname; 347e8636dfdSBill Paul cred->adc_fullname.key = entry->key; 348e8636dfdSBill Paul cred->adc_fullname.window = entry->window; 349e8636dfdSBill Paul } 350e8636dfdSBill Paul return (AUTH_OK); /* we made it!*/ 351e8636dfdSBill Paul } 352e8636dfdSBill Paul 353e8636dfdSBill Paul 354e8636dfdSBill Paul /* 355e8636dfdSBill Paul * Initialize the cache 356e8636dfdSBill Paul */ 357e8636dfdSBill Paul static void 358e8636dfdSBill Paul cache_init() 359e8636dfdSBill Paul { 3608fb3f3f6SDavid E. O'Brien int i; 361e8636dfdSBill Paul 362e8636dfdSBill Paul authdes_cache = (struct cache_entry *) 363e8636dfdSBill Paul mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ); 364e8636dfdSBill Paul bzero((char *)authdes_cache, 365e8636dfdSBill Paul sizeof(struct cache_entry) * AUTHDES_CACHESZ); 366e8636dfdSBill Paul 367e8636dfdSBill Paul authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); 368e8636dfdSBill Paul /* 369e8636dfdSBill Paul * Initialize the lru list 370e8636dfdSBill Paul */ 371e8636dfdSBill Paul for (i = 0; i < AUTHDES_CACHESZ; i++) { 372e8636dfdSBill Paul authdes_lru[i] = i; 373e8636dfdSBill Paul } 374e8636dfdSBill Paul } 375e8636dfdSBill Paul 376e8636dfdSBill Paul 377e8636dfdSBill Paul /* 378e8636dfdSBill Paul * Find the lru victim 379e8636dfdSBill Paul */ 380e8636dfdSBill Paul static short 381e8636dfdSBill Paul cache_victim() 382e8636dfdSBill Paul { 383e8636dfdSBill Paul return (authdes_lru[AUTHDES_CACHESZ-1]); 384e8636dfdSBill Paul } 385e8636dfdSBill Paul 386e8636dfdSBill Paul /* 387e8636dfdSBill Paul * Note that sid was referenced 388e8636dfdSBill Paul */ 389e8636dfdSBill Paul static void 390e8636dfdSBill Paul cache_ref(sid) 3918fb3f3f6SDavid E. O'Brien short sid; 392e8636dfdSBill Paul { 3938fb3f3f6SDavid E. O'Brien int i; 3948fb3f3f6SDavid E. O'Brien short curr; 3958fb3f3f6SDavid E. O'Brien short prev; 396e8636dfdSBill Paul 397e8636dfdSBill Paul prev = authdes_lru[0]; 398e8636dfdSBill Paul authdes_lru[0] = sid; 399e8636dfdSBill Paul for (i = 1; prev != sid; i++) { 400e8636dfdSBill Paul curr = authdes_lru[i]; 401e8636dfdSBill Paul authdes_lru[i] = prev; 402e8636dfdSBill Paul prev = curr; 403e8636dfdSBill Paul } 404e8636dfdSBill Paul } 405e8636dfdSBill Paul 406e8636dfdSBill Paul 407e8636dfdSBill Paul /* 408e8636dfdSBill Paul * Find a spot in the cache for a credential containing 409e8636dfdSBill Paul * the items given. Return -1 if a replay is detected, otherwise 410e8636dfdSBill Paul * return the spot in the cache. 411e8636dfdSBill Paul */ 412e8636dfdSBill Paul static short 413e8636dfdSBill Paul cache_spot(key, name, timestamp) 4148fb3f3f6SDavid E. O'Brien des_block *key; 415e8636dfdSBill Paul char *name; 416e8636dfdSBill Paul struct timeval *timestamp; 417e8636dfdSBill Paul { 4188fb3f3f6SDavid E. O'Brien struct cache_entry *cp; 4198fb3f3f6SDavid E. O'Brien int i; 4208fb3f3f6SDavid E. O'Brien u_long hi; 421e8636dfdSBill Paul 422e8636dfdSBill Paul hi = key->key.high; 423e8636dfdSBill Paul for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { 424e8636dfdSBill Paul if (cp->key.key.high == hi && 425e8636dfdSBill Paul cp->key.key.low == key->key.low && 426e8636dfdSBill Paul cp->rname != NULL && 427e8636dfdSBill Paul bcmp(cp->rname, name, strlen(name) + 1) == 0) { 428e8636dfdSBill Paul if (BEFORE(timestamp, &cp->laststamp)) { 429e8636dfdSBill Paul svcauthdes_stats.ncachereplays++; 430e8636dfdSBill Paul return (-1); /* replay */ 431e8636dfdSBill Paul } 432e8636dfdSBill Paul svcauthdes_stats.ncachehits++; 433e8636dfdSBill Paul return (i); /* refresh */ 434e8636dfdSBill Paul } 435e8636dfdSBill Paul } 436e8636dfdSBill Paul svcauthdes_stats.ncachemisses++; 437e8636dfdSBill Paul return (cache_victim()); /* new credential */ 438e8636dfdSBill Paul } 439e8636dfdSBill Paul 440e8636dfdSBill Paul 441e8636dfdSBill Paul #if (defined(sun) || defined(vax) || defined(__FreeBSD__)) 442e8636dfdSBill Paul /* 443e8636dfdSBill Paul * Local credential handling stuff. 444e8636dfdSBill Paul * NOTE: bsd unix dependent. 445e8636dfdSBill Paul * Other operating systems should put something else here. 446e8636dfdSBill Paul */ 447e8636dfdSBill Paul #define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ 448e8636dfdSBill Paul #define INVALID -1 /* grouplen, if cache entry is invalid */ 449e8636dfdSBill Paul 450e8636dfdSBill Paul struct bsdcred { 4519d8e1a83SBrooks Davis uid_t uid; /* cached uid */ 4529d8e1a83SBrooks Davis gid_t gid; /* cached gid */ 4539d8e1a83SBrooks Davis int grouplen; /* length of cached groups */ 4549d8e1a83SBrooks Davis gid_t groups[NGRPS]; /* cached groups */ 455e8636dfdSBill Paul }; 456e8636dfdSBill Paul 457e8636dfdSBill Paul /* 458e8636dfdSBill Paul * Map a des credential into a unix cred. 459e8636dfdSBill Paul * We cache the credential here so the application does 460e8636dfdSBill Paul * not have to make an rpc call every time to interpret 461e8636dfdSBill Paul * the credential. 462e8636dfdSBill Paul */ 463e8636dfdSBill Paul int 464e8636dfdSBill Paul authdes_getucred(adc, uid, gid, grouplen, groups) 465e8636dfdSBill Paul struct authdes_cred *adc; 466e8636dfdSBill Paul uid_t *uid; 467e8636dfdSBill Paul gid_t *gid; 468e8636dfdSBill Paul int *grouplen; 4698fb3f3f6SDavid E. O'Brien gid_t *groups; 470e8636dfdSBill Paul { 471e8636dfdSBill Paul unsigned sid; 4728fb3f3f6SDavid E. O'Brien int i; 473e8636dfdSBill Paul uid_t i_uid; 474e8636dfdSBill Paul gid_t i_gid; 475e8636dfdSBill Paul int i_grouplen; 476e8636dfdSBill Paul struct bsdcred *cred; 477e8636dfdSBill Paul 478e8636dfdSBill Paul sid = adc->adc_nickname; 479e8636dfdSBill Paul if (sid >= AUTHDES_CACHESZ) { 480e8636dfdSBill Paul debug("invalid nickname"); 481e8636dfdSBill Paul return (0); 482e8636dfdSBill Paul } 483e8636dfdSBill Paul cred = (struct bsdcred *)authdes_cache[sid].localcred; 484e8636dfdSBill Paul if (cred == NULL) { 485e8636dfdSBill Paul cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); 486e8636dfdSBill Paul authdes_cache[sid].localcred = (char *)cred; 487e8636dfdSBill Paul cred->grouplen = INVALID; 488e8636dfdSBill Paul } 489e8636dfdSBill Paul if (cred->grouplen == INVALID) { 490e8636dfdSBill Paul /* 491e8636dfdSBill Paul * not in cache: lookup 492e8636dfdSBill Paul */ 493e8636dfdSBill Paul if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, 494e8636dfdSBill Paul &i_grouplen, groups)) 495e8636dfdSBill Paul { 496e8636dfdSBill Paul debug("unknown netname"); 497e8636dfdSBill Paul cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ 498e8636dfdSBill Paul return (0); 499e8636dfdSBill Paul } 500e8636dfdSBill Paul debug("missed ucred cache"); 501e8636dfdSBill Paul *uid = cred->uid = i_uid; 502e8636dfdSBill Paul *gid = cred->gid = i_gid; 503e8636dfdSBill Paul *grouplen = cred->grouplen = i_grouplen; 504e8636dfdSBill Paul for (i = i_grouplen - 1; i >= 0; i--) { 505e8636dfdSBill Paul cred->groups[i] = groups[i]; /* int to short */ 506e8636dfdSBill Paul } 507e8636dfdSBill Paul return (1); 508e8636dfdSBill Paul } else if (cred->grouplen == UNKNOWN) { 509e8636dfdSBill Paul /* 510e8636dfdSBill Paul * Already lookup up, but no match found 511e8636dfdSBill Paul */ 512e8636dfdSBill Paul return (0); 513e8636dfdSBill Paul } 514e8636dfdSBill Paul 515e8636dfdSBill Paul /* 516e8636dfdSBill Paul * cached credentials 517e8636dfdSBill Paul */ 518e8636dfdSBill Paul *uid = cred->uid; 519e8636dfdSBill Paul *gid = cred->gid; 520e8636dfdSBill Paul *grouplen = cred->grouplen; 521e8636dfdSBill Paul for (i = cred->grouplen - 1; i >= 0; i--) { 522e8636dfdSBill Paul groups[i] = cred->groups[i]; /* short to int */ 523e8636dfdSBill Paul } 524e8636dfdSBill Paul return (1); 525e8636dfdSBill Paul } 526e8636dfdSBill Paul 527e8636dfdSBill Paul static void 528e8636dfdSBill Paul invalidate(cred) 529e8636dfdSBill Paul char *cred; 530e8636dfdSBill Paul { 531e8636dfdSBill Paul if (cred == NULL) { 532e8636dfdSBill Paul return; 533e8636dfdSBill Paul } 534e8636dfdSBill Paul ((struct bsdcred *)cred)->grouplen = INVALID; 535e8636dfdSBill Paul } 536e8636dfdSBill Paul #endif 537e8636dfdSBill Paul 538