1177633Sdfr/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */ 2177633Sdfr 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6177633Sdfr * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17261046Smav * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr 31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 32177633Sdfrstatic char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; 33177633Sdfrstatic char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC"; 34177633Sdfr#endif 35177633Sdfr#include <sys/cdefs.h> 36177633Sdfr__FBSDID("$FreeBSD$"); 37177633Sdfr 38177633Sdfr/* 39177633Sdfr * auth_unix.c, Implements UNIX style authentication parameters. 40177633Sdfr * 41177633Sdfr * Copyright (C) 1984, Sun Microsystems, Inc. 42177633Sdfr * 43177633Sdfr * The system is very weak. The client uses no encryption for it's 44177633Sdfr * credentials and only sends null verifiers. The server sends backs 45177633Sdfr * null verifiers or optionally a verifier that suggests a new short hand 46177633Sdfr * for the credentials. 47177633Sdfr * 48177633Sdfr */ 49177633Sdfr 50177633Sdfr#include <sys/param.h> 51177633Sdfr#include <sys/systm.h> 52180025Sdfr#include <sys/hash.h> 53180025Sdfr#include <sys/kernel.h> 54177633Sdfr#include <sys/lock.h> 55177633Sdfr#include <sys/malloc.h> 56180064Sdfr#include <sys/pcpu.h> 57180743Sdfr#include <sys/refcount.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> 64184588Sdfr#include <rpc/clnt.h> 65177633Sdfr 66177685Sdfr#include <rpc/rpc_com.h> 67177633Sdfr 68177633Sdfr/* auth_unix.c */ 69177633Sdfrstatic void authunix_nextverf (AUTH *); 70184588Sdfrstatic bool_t authunix_marshal (AUTH *, uint32_t, XDR *, struct mbuf *); 71184588Sdfrstatic bool_t authunix_validate (AUTH *, uint32_t, struct opaque_auth *, 72184588Sdfr struct mbuf **); 73177633Sdfrstatic bool_t authunix_refresh (AUTH *, void *); 74177633Sdfrstatic void authunix_destroy (AUTH *); 75177633Sdfrstatic void marshal_new_auth (AUTH *); 76177633Sdfr 77177633Sdfrstatic struct auth_ops authunix_ops = { 78177633Sdfr .ah_nextverf = authunix_nextverf, 79177633Sdfr .ah_marshal = authunix_marshal, 80177633Sdfr .ah_validate = authunix_validate, 81177633Sdfr .ah_refresh = authunix_refresh, 82184588Sdfr .ah_destroy = authunix_destroy, 83177633Sdfr}; 84177633Sdfr 85177633Sdfr/* 86177633Sdfr * This struct is pointed to by the ah_private field of an auth_handle. 87177633Sdfr */ 88177633Sdfrstruct audata { 89180025Sdfr TAILQ_ENTRY(audata) au_link; 90180025Sdfr TAILQ_ENTRY(audata) au_alllink; 91180743Sdfr volatile u_int au_refs; 92180025Sdfr struct xucred au_xcred; 93177633Sdfr struct opaque_auth au_origcred; /* original credentials */ 94177633Sdfr struct opaque_auth au_shcred; /* short hand cred */ 95177633Sdfr u_long au_shfaults; /* short hand cache faults */ 96177633Sdfr char au_marshed[MAX_AUTH_BYTES]; 97177633Sdfr u_int au_mpos; /* xdr pos at end of marshed */ 98180025Sdfr AUTH *au_auth; /* link back to AUTH */ 99177633Sdfr}; 100180025SdfrTAILQ_HEAD(audata_list, audata); 101177633Sdfr#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) 102177633Sdfr 103180025Sdfr#define AUTH_UNIX_HASH_SIZE 16 104180025Sdfr#define AUTH_UNIX_MAX 256 105180025Sdfrstatic struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE]; 106180025Sdfrstatic struct audata_list auth_unix_all; 107180025Sdfrstatic struct sx auth_unix_lock; 108180025Sdfrstatic int auth_unix_count; 109180025Sdfr 110180025Sdfrstatic void 111180025Sdfrauthunix_init(void *dummy) 112180025Sdfr{ 113180025Sdfr int i; 114180025Sdfr 115180025Sdfr for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++) 116180025Sdfr TAILQ_INIT(&auth_unix_cache[i]); 117180025Sdfr TAILQ_INIT(&auth_unix_all); 118180025Sdfr sx_init(&auth_unix_lock, "auth_unix_lock"); 119180025Sdfr} 120180025SdfrSYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL); 121180025Sdfr 122177633Sdfr/* 123177633Sdfr * Create a unix style authenticator. 124177633Sdfr * Returns an auth handle with the given stuff in it. 125177633Sdfr */ 126177633SdfrAUTH * 127177633Sdfrauthunix_create(struct ucred *cred) 128177633Sdfr{ 129180025Sdfr uint32_t h, th; 130177633Sdfr struct xucred xcr; 131177633Sdfr char mymem[MAX_AUTH_BYTES]; 132177633Sdfr XDR xdrs; 133177633Sdfr AUTH *auth; 134180025Sdfr struct audata *au, *tau; 135177633Sdfr struct timeval now; 136177633Sdfr uint32_t time; 137177633Sdfr int len; 138177633Sdfr 139180025Sdfr if (auth_unix_count > AUTH_UNIX_MAX) { 140180025Sdfr while (auth_unix_count > AUTH_UNIX_MAX) { 141180025Sdfr sx_xlock(&auth_unix_lock); 142180025Sdfr tau = TAILQ_FIRST(&auth_unix_all); 143180025Sdfr th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid) 144180025Sdfr % AUTH_UNIX_HASH_SIZE; 145180025Sdfr TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link); 146180025Sdfr TAILQ_REMOVE(&auth_unix_all, tau, au_alllink); 147180025Sdfr auth_unix_count--; 148180025Sdfr sx_xunlock(&auth_unix_lock); 149180025Sdfr AUTH_DESTROY(tau->au_auth); 150180025Sdfr } 151180025Sdfr } 152180025Sdfr 153177633Sdfr /* 154180025Sdfr * Hash the uid to see if we already have an AUTH with this cred. 155180025Sdfr */ 156180025Sdfr h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE; 157180025Sdfr cru2x(cred, &xcr); 158180025Sdfragain: 159180025Sdfr sx_slock(&auth_unix_lock); 160180025Sdfr TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) { 161180025Sdfr if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) { 162180743Sdfr refcount_acquire(&au->au_refs); 163180025Sdfr if (sx_try_upgrade(&auth_unix_lock)) { 164180025Sdfr /* 165180025Sdfr * Keep auth_unix_all LRU sorted. 166180025Sdfr */ 167180025Sdfr TAILQ_REMOVE(&auth_unix_all, au, au_alllink); 168180025Sdfr TAILQ_INSERT_TAIL(&auth_unix_all, au, 169180025Sdfr au_alllink); 170180025Sdfr sx_xunlock(&auth_unix_lock); 171180025Sdfr } else { 172180025Sdfr sx_sunlock(&auth_unix_lock); 173180025Sdfr } 174180743Sdfr return (au->au_auth); 175180025Sdfr } 176180025Sdfr } 177180025Sdfr 178180743Sdfr sx_sunlock(&auth_unix_lock); 179180743Sdfr 180180025Sdfr /* 181177633Sdfr * Allocate and set up auth handle 182177633Sdfr */ 183177633Sdfr au = NULL; 184177633Sdfr auth = mem_alloc(sizeof(*auth)); 185177633Sdfr au = mem_alloc(sizeof(*au)); 186177633Sdfr auth->ah_ops = &authunix_ops; 187177633Sdfr auth->ah_private = (caddr_t)au; 188177633Sdfr auth->ah_verf = au->au_shcred = _null_auth; 189180743Sdfr refcount_init(&au->au_refs, 1); 190180025Sdfr au->au_xcred = xcr; 191177633Sdfr au->au_shfaults = 0; 192177633Sdfr au->au_origcred.oa_base = NULL; 193180025Sdfr au->au_auth = auth; 194177633Sdfr 195177633Sdfr getmicrotime(&now); 196177633Sdfr time = now.tv_sec; 197177633Sdfr 198177633Sdfr /* 199177633Sdfr * Serialize the parameters into origcred 200177633Sdfr */ 201177633Sdfr xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); 202177633Sdfr cru2x(cred, &xcr); 203177633Sdfr if (! xdr_authunix_parms(&xdrs, &time, &xcr)) 204177633Sdfr panic("authunix_create: failed to encode creds"); 205177633Sdfr au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); 206177633Sdfr au->au_origcred.oa_flavor = AUTH_UNIX; 207177633Sdfr au->au_origcred.oa_base = mem_alloc((u_int) len); 208177633Sdfr memcpy(au->au_origcred.oa_base, mymem, (size_t)len); 209177633Sdfr 210177633Sdfr /* 211177633Sdfr * set auth handle to reflect new cred. 212177633Sdfr */ 213177633Sdfr auth->ah_cred = au->au_origcred; 214177633Sdfr marshal_new_auth(auth); 215180025Sdfr 216180743Sdfr sx_xlock(&auth_unix_lock); 217180743Sdfr TAILQ_FOREACH(tau, &auth_unix_cache[h], au_link) { 218180743Sdfr if (!memcmp(&xcr, &tau->au_xcred, sizeof(xcr))) { 219180743Sdfr /* 220180743Sdfr * We lost a race to create the AUTH that 221180743Sdfr * matches this cred. 222180743Sdfr */ 223180743Sdfr sx_xunlock(&auth_unix_lock); 224180743Sdfr AUTH_DESTROY(auth); 225180743Sdfr goto again; 226180743Sdfr } 227177633Sdfr } 228180743Sdfr 229180743Sdfr auth_unix_count++; 230180743Sdfr TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link); 231180743Sdfr TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink); 232180743Sdfr refcount_acquire(&au->au_refs); /* one for the cache, one for user */ 233180743Sdfr sx_xunlock(&auth_unix_lock); 234180743Sdfr 235180743Sdfr return (auth); 236177633Sdfr} 237177633Sdfr 238177633Sdfr/* 239177633Sdfr * authunix operations 240177633Sdfr */ 241177633Sdfr 242177633Sdfr/* ARGSUSED */ 243177633Sdfrstatic void 244177633Sdfrauthunix_nextverf(AUTH *auth) 245177633Sdfr{ 246177633Sdfr /* no action necessary */ 247177633Sdfr} 248177633Sdfr 249177633Sdfrstatic bool_t 250184588Sdfrauthunix_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args) 251177633Sdfr{ 252177633Sdfr struct audata *au; 253177633Sdfr 254177633Sdfr au = AUTH_PRIVATE(auth); 255184588Sdfr if (!XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)) 256184588Sdfr return (FALSE); 257184588Sdfr 258184588Sdfr xdrmbuf_append(xdrs, args); 259184588Sdfr 260184588Sdfr return (TRUE); 261177633Sdfr} 262177633Sdfr 263177633Sdfrstatic bool_t 264184588Sdfrauthunix_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf, 265184588Sdfr struct mbuf **mrepp) 266177633Sdfr{ 267177633Sdfr struct audata *au; 268184588Sdfr XDR txdrs; 269177633Sdfr 270184588Sdfr if (!verf) 271184588Sdfr return (TRUE); 272184588Sdfr 273177633Sdfr if (verf->oa_flavor == AUTH_SHORT) { 274177633Sdfr au = AUTH_PRIVATE(auth); 275184588Sdfr xdrmem_create(&txdrs, verf->oa_base, verf->oa_length, 276177633Sdfr XDR_DECODE); 277177633Sdfr 278177633Sdfr if (au->au_shcred.oa_base != NULL) { 279177633Sdfr mem_free(au->au_shcred.oa_base, 280177633Sdfr au->au_shcred.oa_length); 281177633Sdfr au->au_shcred.oa_base = NULL; 282177633Sdfr } 283184588Sdfr if (xdr_opaque_auth(&txdrs, &au->au_shcred)) { 284177633Sdfr auth->ah_cred = au->au_shcred; 285177633Sdfr } else { 286184588Sdfr txdrs.x_op = XDR_FREE; 287184588Sdfr (void)xdr_opaque_auth(&txdrs, &au->au_shcred); 288177633Sdfr au->au_shcred.oa_base = NULL; 289177633Sdfr auth->ah_cred = au->au_origcred; 290177633Sdfr } 291177633Sdfr marshal_new_auth(auth); 292177633Sdfr } 293184588Sdfr 294177633Sdfr return (TRUE); 295177633Sdfr} 296177633Sdfr 297177633Sdfrstatic bool_t 298177633Sdfrauthunix_refresh(AUTH *auth, void *dummy) 299177633Sdfr{ 300177633Sdfr struct audata *au = AUTH_PRIVATE(auth); 301177633Sdfr struct xucred xcr; 302177633Sdfr uint32_t time; 303177633Sdfr struct timeval now; 304177633Sdfr XDR xdrs; 305177633Sdfr int stat; 306177633Sdfr 307177633Sdfr if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { 308177633Sdfr /* there is no hope. Punt */ 309177633Sdfr return (FALSE); 310177633Sdfr } 311177633Sdfr au->au_shfaults ++; 312177633Sdfr 313177633Sdfr /* first deserialize the creds back into a struct ucred */ 314177633Sdfr xdrmem_create(&xdrs, au->au_origcred.oa_base, 315177633Sdfr au->au_origcred.oa_length, XDR_DECODE); 316177633Sdfr stat = xdr_authunix_parms(&xdrs, &time, &xcr); 317177633Sdfr if (! stat) 318177633Sdfr goto done; 319177633Sdfr 320177633Sdfr /* update the time and serialize in place */ 321177633Sdfr getmicrotime(&now); 322177633Sdfr time = now.tv_sec; 323177633Sdfr xdrs.x_op = XDR_ENCODE; 324177633Sdfr XDR_SETPOS(&xdrs, 0); 325177633Sdfr 326177633Sdfr stat = xdr_authunix_parms(&xdrs, &time, &xcr); 327177633Sdfr if (! stat) 328177633Sdfr goto done; 329177633Sdfr auth->ah_cred = au->au_origcred; 330177633Sdfr marshal_new_auth(auth); 331177633Sdfrdone: 332177633Sdfr XDR_DESTROY(&xdrs); 333177633Sdfr return (stat); 334177633Sdfr} 335177633Sdfr 336177633Sdfrstatic void 337177633Sdfrauthunix_destroy(AUTH *auth) 338177633Sdfr{ 339177633Sdfr struct audata *au; 340177633Sdfr 341177633Sdfr au = AUTH_PRIVATE(auth); 342180025Sdfr 343180743Sdfr if (!refcount_release(&au->au_refs)) 344180025Sdfr return; 345180025Sdfr 346177633Sdfr mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); 347177633Sdfr 348177633Sdfr if (au->au_shcred.oa_base != NULL) 349177633Sdfr mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); 350177633Sdfr 351177633Sdfr mem_free(auth->ah_private, sizeof(struct audata)); 352177633Sdfr 353177633Sdfr if (auth->ah_verf.oa_base != NULL) 354177633Sdfr mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); 355177633Sdfr 356177633Sdfr mem_free(auth, sizeof(*auth)); 357177633Sdfr} 358177633Sdfr 359177633Sdfr/* 360177633Sdfr * Marshals (pre-serializes) an auth struct. 361177633Sdfr * sets private data, au_marshed and au_mpos 362177633Sdfr */ 363177633Sdfrstatic void 364177633Sdfrmarshal_new_auth(AUTH *auth) 365177633Sdfr{ 366177633Sdfr XDR xdr_stream; 367177633Sdfr XDR *xdrs = &xdr_stream; 368177633Sdfr struct audata *au; 369177633Sdfr 370177633Sdfr au = AUTH_PRIVATE(auth); 371177633Sdfr xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); 372177633Sdfr if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || 373177633Sdfr (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) 374177633Sdfr printf("auth_none.c - Fatal marshalling problem"); 375177633Sdfr else 376177633Sdfr au->au_mpos = XDR_GETPOS(xdrs); 377177633Sdfr XDR_DESTROY(xdrs); 378177633Sdfr} 379