auth_unix.c revision 180064
1177633Sdfr/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */ 2177633Sdfr 3177633Sdfr/* 4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5177633Sdfr * unrestricted use provided that this legend is included on all tape 6177633Sdfr * media and as a part of the software program in whole or part. Users 7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized 8177633Sdfr * to license or distribute it to anyone else except as part of a product or 9177633Sdfr * program developed by the user. 10177633Sdfr * 11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14177633Sdfr * 15177633Sdfr * Sun RPC is provided with no support and without any obligation on the 16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction, 17177633Sdfr * modification or enhancement. 18177633Sdfr * 19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21177633Sdfr * OR ANY PART THEREOF. 22177633Sdfr * 23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24177633Sdfr * or profits or other special, indirect and consequential damages, even if 25177633Sdfr * Sun has been advised of the possibility of such damages. 26177633Sdfr * 27177633Sdfr * Sun Microsystems, Inc. 28177633Sdfr * 2550 Garcia Avenue 29177633Sdfr * Mountain View, California 94043 30177633Sdfr */ 31177633Sdfr 32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 33177633Sdfrstatic char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; 34177633Sdfrstatic char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC"; 35177633Sdfr#endif 36177633Sdfr#include <sys/cdefs.h> 37177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/auth_unix.c 180064 2008-06-27 14:35:05Z dfr $"); 38177633Sdfr 39177633Sdfr/* 40177633Sdfr * auth_unix.c, Implements UNIX style authentication parameters. 41177633Sdfr * 42177633Sdfr * Copyright (C) 1984, Sun Microsystems, Inc. 43177633Sdfr * 44177633Sdfr * The system is very weak. The client uses no encryption for it's 45177633Sdfr * credentials and only sends null verifiers. The server sends backs 46177633Sdfr * null verifiers or optionally a verifier that suggests a new short hand 47177633Sdfr * for the credentials. 48177633Sdfr * 49177633Sdfr */ 50177633Sdfr 51177633Sdfr#include <sys/param.h> 52177633Sdfr#include <sys/systm.h> 53180025Sdfr#include <sys/hash.h> 54180025Sdfr#include <sys/kernel.h> 55177633Sdfr#include <sys/lock.h> 56177633Sdfr#include <sys/malloc.h> 57180064Sdfr#include <sys/pcpu.h> 58180025Sdfr#include <sys/sx.h> 59177633Sdfr#include <sys/ucred.h> 60177633Sdfr 61177633Sdfr#include <rpc/types.h> 62177633Sdfr#include <rpc/xdr.h> 63177633Sdfr#include <rpc/auth.h> 64177633Sdfr 65177685Sdfr#include <rpc/rpc_com.h> 66177633Sdfr 67177633Sdfr/* auth_unix.c */ 68177633Sdfrstatic void authunix_nextverf (AUTH *); 69177633Sdfrstatic bool_t authunix_marshal (AUTH *, XDR *); 70177633Sdfrstatic bool_t authunix_validate (AUTH *, struct opaque_auth *); 71177633Sdfrstatic bool_t authunix_refresh (AUTH *, void *); 72177633Sdfrstatic void authunix_destroy (AUTH *); 73177633Sdfrstatic void marshal_new_auth (AUTH *); 74177633Sdfr 75177633Sdfrstatic struct auth_ops authunix_ops = { 76177633Sdfr .ah_nextverf = authunix_nextverf, 77177633Sdfr .ah_marshal = authunix_marshal, 78177633Sdfr .ah_validate = authunix_validate, 79177633Sdfr .ah_refresh = authunix_refresh, 80177633Sdfr .ah_destroy = authunix_destroy 81177633Sdfr}; 82177633Sdfr 83177633Sdfr/* 84177633Sdfr * This struct is pointed to by the ah_private field of an auth_handle. 85177633Sdfr */ 86177633Sdfrstruct audata { 87180025Sdfr TAILQ_ENTRY(audata) au_link; 88180025Sdfr TAILQ_ENTRY(audata) au_alllink; 89180025Sdfr int au_refs; 90180025Sdfr struct xucred au_xcred; 91177633Sdfr struct opaque_auth au_origcred; /* original credentials */ 92177633Sdfr struct opaque_auth au_shcred; /* short hand cred */ 93177633Sdfr u_long au_shfaults; /* short hand cache faults */ 94177633Sdfr char au_marshed[MAX_AUTH_BYTES]; 95177633Sdfr u_int au_mpos; /* xdr pos at end of marshed */ 96180025Sdfr AUTH *au_auth; /* link back to AUTH */ 97177633Sdfr}; 98180025SdfrTAILQ_HEAD(audata_list, audata); 99177633Sdfr#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) 100177633Sdfr 101180025Sdfr#define AUTH_UNIX_HASH_SIZE 16 102180025Sdfr#define AUTH_UNIX_MAX 256 103180025Sdfrstatic struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE]; 104180025Sdfrstatic struct audata_list auth_unix_all; 105180025Sdfrstatic struct sx auth_unix_lock; 106180025Sdfrstatic int auth_unix_count; 107180025Sdfr 108180025Sdfrstatic void 109180025Sdfrauthunix_init(void *dummy) 110180025Sdfr{ 111180025Sdfr int i; 112180025Sdfr 113180025Sdfr for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++) 114180025Sdfr TAILQ_INIT(&auth_unix_cache[i]); 115180025Sdfr TAILQ_INIT(&auth_unix_all); 116180025Sdfr sx_init(&auth_unix_lock, "auth_unix_lock"); 117180025Sdfr} 118180025SdfrSYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL); 119180025Sdfr 120177633Sdfr/* 121177633Sdfr * Create a unix style authenticator. 122177633Sdfr * Returns an auth handle with the given stuff in it. 123177633Sdfr */ 124177633SdfrAUTH * 125177633Sdfrauthunix_create(struct ucred *cred) 126177633Sdfr{ 127180025Sdfr uint32_t h, th; 128177633Sdfr struct xucred xcr; 129177633Sdfr char mymem[MAX_AUTH_BYTES]; 130177633Sdfr XDR xdrs; 131177633Sdfr AUTH *auth; 132180025Sdfr struct audata *au, *tau; 133177633Sdfr struct timeval now; 134177633Sdfr uint32_t time; 135177633Sdfr int len; 136177633Sdfr 137180025Sdfr if (auth_unix_count > AUTH_UNIX_MAX) { 138180025Sdfr while (auth_unix_count > AUTH_UNIX_MAX) { 139180025Sdfr sx_xlock(&auth_unix_lock); 140180025Sdfr tau = TAILQ_FIRST(&auth_unix_all); 141180025Sdfr th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid) 142180025Sdfr % AUTH_UNIX_HASH_SIZE; 143180025Sdfr TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link); 144180025Sdfr TAILQ_REMOVE(&auth_unix_all, tau, au_alllink); 145180025Sdfr auth_unix_count--; 146180025Sdfr sx_xunlock(&auth_unix_lock); 147180025Sdfr AUTH_DESTROY(tau->au_auth); 148180025Sdfr } 149180025Sdfr } 150180025Sdfr 151177633Sdfr /* 152180025Sdfr * Hash the uid to see if we already have an AUTH with this cred. 153180025Sdfr */ 154180025Sdfr h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE; 155180025Sdfr cru2x(cred, &xcr); 156180025Sdfragain: 157180025Sdfr sx_slock(&auth_unix_lock); 158180025Sdfr TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) { 159180025Sdfr if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) { 160180025Sdfr if (sx_try_upgrade(&auth_unix_lock)) { 161180025Sdfr /* 162180025Sdfr * Keep auth_unix_all LRU sorted. 163180025Sdfr */ 164180025Sdfr TAILQ_REMOVE(&auth_unix_all, au, au_alllink); 165180025Sdfr TAILQ_INSERT_TAIL(&auth_unix_all, au, 166180025Sdfr au_alllink); 167180025Sdfr au->au_refs++; 168180025Sdfr sx_xunlock(&auth_unix_lock); 169180025Sdfr return (au->au_auth); 170180025Sdfr } else { 171180025Sdfr sx_sunlock(&auth_unix_lock); 172180025Sdfr goto again; 173180025Sdfr } 174180025Sdfr } 175180025Sdfr } 176180025Sdfr 177180025Sdfr /* 178177633Sdfr * Allocate and set up auth handle 179177633Sdfr */ 180177633Sdfr au = NULL; 181177633Sdfr auth = mem_alloc(sizeof(*auth)); 182177633Sdfr au = mem_alloc(sizeof(*au)); 183177633Sdfr auth->ah_ops = &authunix_ops; 184177633Sdfr auth->ah_private = (caddr_t)au; 185177633Sdfr auth->ah_verf = au->au_shcred = _null_auth; 186180025Sdfr au->au_refs = 1; 187180025Sdfr au->au_xcred = xcr; 188177633Sdfr au->au_shfaults = 0; 189177633Sdfr au->au_origcred.oa_base = NULL; 190180025Sdfr au->au_auth = auth; 191177633Sdfr 192177633Sdfr getmicrotime(&now); 193177633Sdfr time = now.tv_sec; 194177633Sdfr 195177633Sdfr /* 196177633Sdfr * Serialize the parameters into origcred 197177633Sdfr */ 198177633Sdfr xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); 199177633Sdfr cru2x(cred, &xcr); 200177633Sdfr if (! xdr_authunix_parms(&xdrs, &time, &xcr)) 201177633Sdfr panic("authunix_create: failed to encode creds"); 202177633Sdfr au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); 203177633Sdfr au->au_origcred.oa_flavor = AUTH_UNIX; 204177633Sdfr au->au_origcred.oa_base = mem_alloc((u_int) len); 205177633Sdfr memcpy(au->au_origcred.oa_base, mymem, (size_t)len); 206177633Sdfr 207177633Sdfr /* 208177633Sdfr * set auth handle to reflect new cred. 209177633Sdfr */ 210177633Sdfr auth->ah_cred = au->au_origcred; 211177633Sdfr marshal_new_auth(auth); 212180025Sdfr 213180025Sdfr if (sx_try_upgrade(&auth_unix_lock)) { 214180025Sdfr auth_unix_count++; 215180025Sdfr TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link); 216180025Sdfr TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink); 217180025Sdfr au->au_refs++; /* one for the cache, one for user */ 218180025Sdfr sx_xunlock(&auth_unix_lock); 219180025Sdfr return (auth); 220180025Sdfr } else { 221180025Sdfr sx_sunlock(&auth_unix_lock); 222180025Sdfr AUTH_DESTROY(auth); 223180025Sdfr goto again; 224177633Sdfr } 225177633Sdfr} 226177633Sdfr 227177633Sdfr/* 228177633Sdfr * authunix operations 229177633Sdfr */ 230177633Sdfr 231177633Sdfr/* ARGSUSED */ 232177633Sdfrstatic void 233177633Sdfrauthunix_nextverf(AUTH *auth) 234177633Sdfr{ 235177633Sdfr /* no action necessary */ 236177633Sdfr} 237177633Sdfr 238177633Sdfrstatic bool_t 239177633Sdfrauthunix_marshal(AUTH *auth, XDR *xdrs) 240177633Sdfr{ 241177633Sdfr struct audata *au; 242177633Sdfr 243177633Sdfr au = AUTH_PRIVATE(auth); 244177633Sdfr return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); 245177633Sdfr} 246177633Sdfr 247177633Sdfrstatic bool_t 248177633Sdfrauthunix_validate(AUTH *auth, struct opaque_auth *verf) 249177633Sdfr{ 250177633Sdfr struct audata *au; 251177633Sdfr XDR xdrs; 252177633Sdfr 253177633Sdfr if (verf->oa_flavor == AUTH_SHORT) { 254177633Sdfr au = AUTH_PRIVATE(auth); 255177633Sdfr xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, 256177633Sdfr XDR_DECODE); 257177633Sdfr 258177633Sdfr if (au->au_shcred.oa_base != NULL) { 259177633Sdfr mem_free(au->au_shcred.oa_base, 260177633Sdfr au->au_shcred.oa_length); 261177633Sdfr au->au_shcred.oa_base = NULL; 262177633Sdfr } 263177633Sdfr if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { 264177633Sdfr auth->ah_cred = au->au_shcred; 265177633Sdfr } else { 266177633Sdfr xdrs.x_op = XDR_FREE; 267177633Sdfr (void)xdr_opaque_auth(&xdrs, &au->au_shcred); 268177633Sdfr au->au_shcred.oa_base = NULL; 269177633Sdfr auth->ah_cred = au->au_origcred; 270177633Sdfr } 271177633Sdfr marshal_new_auth(auth); 272177633Sdfr } 273177633Sdfr return (TRUE); 274177633Sdfr} 275177633Sdfr 276177633Sdfrstatic bool_t 277177633Sdfrauthunix_refresh(AUTH *auth, void *dummy) 278177633Sdfr{ 279177633Sdfr struct audata *au = AUTH_PRIVATE(auth); 280177633Sdfr struct xucred xcr; 281177633Sdfr uint32_t time; 282177633Sdfr struct timeval now; 283177633Sdfr XDR xdrs; 284177633Sdfr int stat; 285177633Sdfr 286177633Sdfr if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { 287177633Sdfr /* there is no hope. Punt */ 288177633Sdfr return (FALSE); 289177633Sdfr } 290177633Sdfr au->au_shfaults ++; 291177633Sdfr 292177633Sdfr /* first deserialize the creds back into a struct ucred */ 293177633Sdfr xdrmem_create(&xdrs, au->au_origcred.oa_base, 294177633Sdfr au->au_origcred.oa_length, XDR_DECODE); 295177633Sdfr stat = xdr_authunix_parms(&xdrs, &time, &xcr); 296177633Sdfr if (! stat) 297177633Sdfr goto done; 298177633Sdfr 299177633Sdfr /* update the time and serialize in place */ 300177633Sdfr getmicrotime(&now); 301177633Sdfr time = now.tv_sec; 302177633Sdfr xdrs.x_op = XDR_ENCODE; 303177633Sdfr XDR_SETPOS(&xdrs, 0); 304177633Sdfr 305177633Sdfr stat = xdr_authunix_parms(&xdrs, &time, &xcr); 306177633Sdfr if (! stat) 307177633Sdfr goto done; 308177633Sdfr auth->ah_cred = au->au_origcred; 309177633Sdfr marshal_new_auth(auth); 310177633Sdfrdone: 311177633Sdfr XDR_DESTROY(&xdrs); 312177633Sdfr return (stat); 313177633Sdfr} 314177633Sdfr 315177633Sdfrstatic void 316177633Sdfrauthunix_destroy(AUTH *auth) 317177633Sdfr{ 318177633Sdfr struct audata *au; 319180025Sdfr int refs; 320177633Sdfr 321177633Sdfr au = AUTH_PRIVATE(auth); 322180025Sdfr 323180025Sdfr sx_xlock(&auth_unix_lock); 324180025Sdfr au->au_refs--; 325180025Sdfr refs = au->au_refs; 326180025Sdfr sx_xunlock(&auth_unix_lock); 327180025Sdfr 328180025Sdfr if (refs > 0) 329180025Sdfr return; 330180025Sdfr 331177633Sdfr mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); 332177633Sdfr 333177633Sdfr if (au->au_shcred.oa_base != NULL) 334177633Sdfr mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); 335177633Sdfr 336177633Sdfr mem_free(auth->ah_private, sizeof(struct audata)); 337177633Sdfr 338177633Sdfr if (auth->ah_verf.oa_base != NULL) 339177633Sdfr mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); 340177633Sdfr 341177633Sdfr mem_free(auth, sizeof(*auth)); 342177633Sdfr} 343177633Sdfr 344177633Sdfr/* 345177633Sdfr * Marshals (pre-serializes) an auth struct. 346177633Sdfr * sets private data, au_marshed and au_mpos 347177633Sdfr */ 348177633Sdfrstatic void 349177633Sdfrmarshal_new_auth(AUTH *auth) 350177633Sdfr{ 351177633Sdfr XDR xdr_stream; 352177633Sdfr XDR *xdrs = &xdr_stream; 353177633Sdfr struct audata *au; 354177633Sdfr 355177633Sdfr au = AUTH_PRIVATE(auth); 356177633Sdfr xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); 357177633Sdfr if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || 358177633Sdfr (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) 359177633Sdfr printf("auth_none.c - Fatal marshalling problem"); 360177633Sdfr else 361177633Sdfr au->au_mpos = XDR_GETPOS(xdrs); 362177633Sdfr XDR_DESTROY(xdrs); 363177633Sdfr} 364