1 /* $NetBSD: auth_unix.c,v 1.28 2024/01/23 17:24:38 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #if defined(LIBC_SCCS) && !defined(lint) 36 #if 0 37 static char *sccsid = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; 38 static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC"; 39 #else 40 __RCSID("$NetBSD: auth_unix.c,v 1.28 2024/01/23 17:24:38 christos Exp $"); 41 #endif 42 #endif 43 44 /* 45 * auth_unix.c, Implements UNIX style authentication parameters. 46 * 47 * Copyright (C) 1984, Sun Microsystems, Inc. 48 * 49 * The system is very weak. The client uses no encryption for its 50 * credentials and only sends null verifiers. The server sends backs 51 * null verifiers or optionally a verifier that suggests a new short hand 52 * for the credentials. 53 * 54 */ 55 56 #include "namespace.h" 57 #include "reentrant.h" 58 #include <sys/param.h> 59 60 #include <assert.h> 61 #include <err.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include <rpc/types.h> 68 #include <rpc/xdr.h> 69 #include <rpc/rpc.h> 70 #include <rpc/auth.h> 71 #include <rpc/auth_unix.h> 72 73 #include "rpc_internal.h" 74 75 #ifdef __weak_alias 76 __weak_alias(authunix_create,_authunix_create) 77 __weak_alias(authunix_create_default,_authunix_create_default) 78 #endif 79 80 81 /* auth_unix.c */ 82 static void authunix_nextverf(AUTH *); 83 static bool_t authunix_marshal(AUTH *, XDR *); 84 static bool_t authunix_validate(AUTH *, struct opaque_auth *); 85 static bool_t authunix_refresh(AUTH *); 86 static void authunix_destroy(AUTH *); 87 static void marshal_new_auth(AUTH *); 88 static const struct auth_ops *authunix_ops(void); 89 90 /* 91 * This struct is pointed to by the ah_private field of an auth_handle. 92 */ 93 struct audata { 94 struct opaque_auth au_origcred; /* original credentials */ 95 struct opaque_auth au_shcred; /* short hand cred */ 96 u_long au_shfaults; /* short hand cache faults */ 97 char au_marshed[MAX_AUTH_BYTES]; 98 u_int au_mpos; /* xdr pos at end of marshed */ 99 }; 100 #define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) 101 102 /* 103 * Create a unix style authenticator. 104 * Returns an auth handle with the given stuff in it. 105 */ 106 AUTH * 107 authunix_create(char *machname, int uid, int gid, int len, int *aup_gids) 108 { 109 struct authunix_parms aup; 110 char mymem[MAX_AUTH_BYTES]; 111 struct timeval now; 112 XDR xdrs; 113 AUTH *auth; 114 struct audata *au; 115 116 /* 117 * Allocate and set up auth handle 118 */ 119 au = NULL; 120 auth = mem_alloc(sizeof(*auth)); 121 #ifndef KERNEL 122 if (auth == NULL) { 123 warn("%s: out of memory", __func__); 124 goto cleanup_authunix_create; 125 } 126 #endif 127 au = mem_alloc(sizeof(*au)); 128 #ifndef KERNEL 129 if (au == NULL) { 130 warn("%s: out of memory", __func__); 131 goto cleanup_authunix_create; 132 } 133 #endif 134 auth->ah_ops = authunix_ops(); 135 auth->ah_private = au; 136 auth->ah_verf = au->au_shcred = _null_auth; 137 au->au_shfaults = 0; 138 au->au_origcred.oa_base = NULL; 139 140 /* 141 * fill in param struct from the given params 142 */ 143 (void)gettimeofday(&now, NULL); 144 aup.aup_time = (u_long)now.tv_sec; /* XXX: truncate on 32 bit */ 145 aup.aup_machname = machname; 146 aup.aup_uid = uid; 147 aup.aup_gid = gid; 148 aup.aup_len = (u_int)len; 149 aup.aup_gids = aup_gids; 150 151 /* 152 * Serialize the parameters into origcred 153 */ 154 xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); 155 if (! xdr_authunix_parms(&xdrs, &aup)) 156 abort(); 157 au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); 158 au->au_origcred.oa_flavor = AUTH_UNIX; 159 #ifdef KERNEL 160 au->au_origcred.oa_base = mem_alloc((size_t)len); 161 #else 162 if ((au->au_origcred.oa_base = mem_alloc((size_t)len)) == NULL) { 163 warn("%s: out of memory", __func__); 164 goto cleanup_authunix_create; 165 } 166 #endif 167 memmove(au->au_origcred.oa_base, mymem, (size_t)len); 168 169 /* 170 * set auth handle to reflect new cred. 171 */ 172 auth->ah_cred = au->au_origcred; 173 marshal_new_auth(auth); 174 return (auth); 175 #ifndef KERNEL 176 cleanup_authunix_create: 177 if (auth) 178 mem_free(auth, sizeof(*auth)); 179 if (au) { 180 if (au->au_origcred.oa_base) 181 mem_free(au->au_origcred.oa_base, (u_int)len); 182 mem_free(au, sizeof(*au)); 183 } 184 return (NULL); 185 #endif 186 } 187 188 /* 189 * Some servers will refuse mounts if the group list is larger 190 * than it expects (like 8). This allows the application to set 191 * the maximum size of the group list that will be sent. 192 */ 193 static int maxgrplist = NGROUPS; 194 195 void 196 set_rpc_maxgrouplist(int num) 197 { 198 if (num < NGROUPS) 199 maxgrplist = num; 200 } 201 202 /* 203 * Returns an auth handle with parameters determined by doing lots of 204 * syscalls. 205 */ 206 AUTH * 207 authunix_create_default(void) 208 { 209 int len; 210 char machname[MAXHOSTNAMELEN + 1]; 211 uid_t uid; 212 gid_t gid; 213 gid_t gids[NGRPS]; 214 215 if (gethostname(machname, sizeof machname) == -1) 216 abort(); 217 machname[sizeof(machname) - 1] = 0; 218 uid = geteuid(); 219 gid = getegid(); 220 if ((len = getgroups(NGRPS, gids)) < 0) 221 abort(); 222 if (len > maxgrplist) 223 len = maxgrplist; 224 /* XXX: interface problem; those should all have been unsigned */ 225 return (authunix_create(machname, (int)uid, (int)gid, len, 226 (int *)gids)); 227 } 228 229 /* 230 * authunix operations 231 */ 232 233 /* ARGSUSED */ 234 static void 235 authunix_nextverf(AUTH *auth) 236 { 237 /* no action necessary */ 238 } 239 240 static bool_t 241 authunix_marshal(AUTH *auth, XDR *xdrs) 242 { 243 struct audata *au; 244 245 _DIAGASSERT(auth != NULL); 246 _DIAGASSERT(xdrs != NULL); 247 248 au = AUTH_PRIVATE(auth); 249 return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); 250 } 251 252 static bool_t 253 authunix_validate(AUTH *auth, struct opaque_auth *verf) 254 { 255 struct audata *au; 256 XDR xdrs; 257 258 _DIAGASSERT(auth != NULL); 259 _DIAGASSERT(verf != NULL); 260 261 if (verf->oa_flavor == AUTH_SHORT) { 262 au = AUTH_PRIVATE(auth); 263 xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, 264 XDR_DECODE); 265 266 if (au->au_shcred.oa_base != NULL) { 267 mem_free(au->au_shcred.oa_base, 268 au->au_shcred.oa_length); 269 au->au_shcred.oa_base = NULL; 270 } 271 if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { 272 auth->ah_cred = au->au_shcred; 273 } else { 274 xdrs.x_op = XDR_FREE; 275 (void)xdr_opaque_auth(&xdrs, &au->au_shcred); 276 au->au_shcred.oa_base = NULL; 277 auth->ah_cred = au->au_origcred; 278 } 279 marshal_new_auth(auth); 280 } 281 return (TRUE); 282 } 283 284 static bool_t 285 authunix_refresh(AUTH *auth) 286 { 287 struct audata *au = AUTH_PRIVATE(auth); 288 struct authunix_parms aup; 289 struct timeval now; 290 XDR xdrs; 291 int stat; 292 293 _DIAGASSERT(auth != NULL); 294 295 if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { 296 /* there is no hope. Punt */ 297 return (FALSE); 298 } 299 au->au_shfaults++; 300 301 /* first deserialize the creds back into a struct authunix_parms */ 302 aup.aup_machname = NULL; 303 aup.aup_gids = NULL; 304 xdrmem_create(&xdrs, au->au_origcred.oa_base, 305 au->au_origcred.oa_length, XDR_DECODE); 306 stat = xdr_authunix_parms(&xdrs, &aup); 307 if (! stat) 308 goto done; 309 310 /* update the time and serialize in place */ 311 (void)gettimeofday(&now, NULL); 312 aup.aup_time = (u_long)now.tv_sec; /* XXX: truncate on 32 bit */ 313 xdrs.x_op = XDR_ENCODE; 314 XDR_SETPOS(&xdrs, 0); 315 stat = xdr_authunix_parms(&xdrs, &aup); 316 if (! stat) 317 goto done; 318 auth->ah_cred = au->au_origcred; 319 marshal_new_auth(auth); 320 done: 321 /* free the struct authunix_parms created by deserializing */ 322 xdrs.x_op = XDR_FREE; 323 (void)xdr_authunix_parms(&xdrs, &aup); 324 XDR_DESTROY(&xdrs); 325 return (stat); 326 } 327 328 static void 329 authunix_destroy(AUTH *auth) 330 { 331 struct audata *au; 332 333 _DIAGASSERT(auth != NULL); 334 335 au = AUTH_PRIVATE(auth); 336 mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); 337 338 if (au->au_shcred.oa_base != NULL) 339 mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); 340 341 mem_free(auth->ah_private, sizeof(struct audata)); 342 343 if (auth->ah_verf.oa_base != NULL) 344 mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); 345 346 mem_free(auth, sizeof(*auth)); 347 } 348 349 /* 350 * Marshals (pre-serializes) an auth struct. 351 * sets private data, au_marshed and au_mpos 352 */ 353 static void 354 marshal_new_auth(AUTH *auth) 355 { 356 XDR xdr_stream; 357 XDR *xdrs = &xdr_stream; 358 struct audata *au; 359 360 _DIAGASSERT(auth != NULL); 361 362 au = AUTH_PRIVATE(auth); 363 xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); 364 if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || 365 (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) 366 warnx("%s: Fatal marshalling problem", __func__); 367 else 368 au->au_mpos = XDR_GETPOS(xdrs); 369 XDR_DESTROY(xdrs); 370 } 371 372 static const struct auth_ops * 373 authunix_ops(void) 374 { 375 static struct auth_ops ops; 376 377 /* VARIABLES PROTECTED BY ops_lock: ops */ 378 379 mutex_lock(&ops_lock); 380 if (ops.ah_nextverf == NULL) { 381 ops.ah_nextverf = authunix_nextverf; 382 ops.ah_marshal = authunix_marshal; 383 ops.ah_validate = authunix_validate; 384 ops.ah_refresh = authunix_refresh; 385 ops.ah_destroy = authunix_destroy; 386 } 387 mutex_unlock(&ops_lock); 388 return (&ops); 389 } 390