1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 /* 36 * auth_loopb.c, implements UNIX style authentication parameters in the 37 * kernel. Interfaces with svc_auth_loopback on the server. See 38 * auth_loopb.c for the user level implementation of the loopback auth. 39 * 40 */ 41 42 #include <sys/param.h> 43 #include <sys/time.h> 44 #include <sys/types.h> 45 #include <sys/systm.h> 46 #include <sys/user.h> 47 #include <sys/proc.h> 48 #include <sys/utsname.h> 49 #include <sys/cred.h> 50 #include <sys/kmem.h> 51 #include <sys/sysmacros.h> 52 #include <sys/cmn_err.h> 53 54 #include <rpc/types.h> 55 #include <rpc/xdr.h> 56 #include <rpc/auth.h> 57 #include <rpc/auth_unix.h> 58 #include <rpc/clnt.h> 59 #include <rpc/rpc_msg.h> 60 61 /* 62 * Unix authenticator operations vector 63 */ 64 static void authloopback_nextverf(AUTH *); 65 static bool_t authloopback_marshal(AUTH *, XDR *, struct cred *); 66 static bool_t authloopback_validate(AUTH *, struct opaque_auth *); 67 static bool_t authloopback_refresh(AUTH *, struct rpc_msg *, cred_t *); 68 static void authloopback_destroy(AUTH *); 69 70 static struct auth_ops authloopback_ops = { 71 authloopback_nextverf, 72 authloopback_marshal, 73 authloopback_validate, 74 authloopback_refresh, 75 authloopback_destroy, 76 authany_wrap, 77 authany_unwrap 78 }; 79 80 /* 81 * Create a kernel unix style authenticator. 82 * Returns an auth handle. 83 */ 84 AUTH * 85 authloopback_create(void) 86 { 87 /* 88 * Allocate and set up auth handle 89 */ 90 return (kmem_cache_alloc(authloopback_cache, KM_SLEEP)); 91 } 92 93 /* 94 * The constructor of the authloopback_cache. 95 */ 96 /* ARGSUSED */ 97 int 98 authloopback_init(void *buf, void *cdrarg, int kmflags) 99 { 100 AUTH *auth = (AUTH *)buf; 101 102 auth->ah_ops = &authloopback_ops; 103 auth->ah_cred.oa_flavor = AUTH_LOOPBACK; 104 auth->ah_verf = _null_auth; 105 106 return (0); 107 } 108 109 /* 110 * authloopback operations 111 */ 112 /* ARGSUSED */ 113 static void 114 authloopback_nextverf(AUTH *auth) 115 { 116 117 /* no action necessary */ 118 } 119 120 static bool_t 121 authloopback_marshal(AUTH *auth, XDR *xdrs, struct cred *cr) 122 { 123 char *sercred; 124 XDR xdrm; 125 bool_t ret; 126 uint32_t gidlen, credsize, namelen, rounded_namelen; 127 int32_t *ptr; 128 char *nodename = uts_nodename(); 129 uint32_t maxgidlen; 130 uint_t startpos; 131 132 ASSERT(xdrs->x_op == XDR_ENCODE); 133 ASSERT(auth->ah_cred.oa_flavor == AUTH_LOOPBACK); 134 ASSERT(auth->ah_verf.oa_flavor == AUTH_NONE); 135 ASSERT(auth->ah_verf.oa_length == 0); 136 137 /* 138 * First we try a fast path to get through 139 * this very common operation. 140 */ 141 namelen = (uint32_t)strlen(nodename); 142 if (namelen > MAX_MACHINE_NAME) 143 return (FALSE); 144 rounded_namelen = RNDUP(namelen); 145 146 /* 147 * NFIELDS is a number of the following fields we are going to encode: 148 * - stamp 149 * - strlen(machinename) 150 * - uid 151 * - gid 152 * - the number of gids 153 */ 154 #define NFIELDS 5 155 CTASSERT(NFIELDS * BYTES_PER_XDR_UNIT + RNDUP(MAX_MACHINE_NAME) <= 156 MAX_AUTH_BYTES); 157 maxgidlen = (MAX_AUTH_BYTES - NFIELDS * BYTES_PER_XDR_UNIT - 158 rounded_namelen) / BYTES_PER_XDR_UNIT; 159 160 gidlen = crgetngroups(cr); 161 if (gidlen > maxgidlen) 162 return (FALSE); 163 164 credsize = NFIELDS * BYTES_PER_XDR_UNIT + rounded_namelen + 165 gidlen * BYTES_PER_XDR_UNIT; 166 ASSERT(credsize <= MAX_AUTH_BYTES); 167 #undef NFIELDS 168 169 /* 170 * We need to marshal both cred and verf parts of the rpc_msg body 171 * (call_body). For the cred part we need to inline the auth_flavor 172 * and the opaque auth body size. Then we inline the credsize bytes of 173 * the opaque auth body for the cred part. Finally we add the 174 * AUTH_NONE verifier (its auth_flavor and the opaque auth body size). 175 */ 176 ptr = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT + credsize + 177 2 * BYTES_PER_XDR_UNIT); 178 if (ptr != NULL) { 179 /* 180 * We can do the fast path. 181 */ 182 const gid_t *gp = crgetgroups(cr); 183 184 IXDR_PUT_U_INT32(ptr, AUTH_LOOPBACK); /* cred flavor */ 185 IXDR_PUT_U_INT32(ptr, credsize); /* cred len */ 186 187 IXDR_PUT_INT32(ptr, gethrestime_sec()); 188 IXDR_PUT_U_INT32(ptr, namelen); 189 bcopy(nodename, ptr, namelen); 190 if ((rounded_namelen - namelen) > 0) 191 bzero((char *)ptr + namelen, rounded_namelen - namelen); 192 ptr += rounded_namelen / BYTES_PER_XDR_UNIT; 193 IXDR_PUT_U_INT32(ptr, crgetuid(cr)); 194 IXDR_PUT_U_INT32(ptr, crgetgid(cr)); 195 IXDR_PUT_U_INT32(ptr, gidlen); 196 while (gidlen-- > 0) 197 IXDR_PUT_U_INT32(ptr, *gp++); 198 199 IXDR_PUT_U_INT32(ptr, AUTH_NONE); /* verf flavor */ 200 IXDR_PUT_U_INT32(ptr, 0); /* verf len */ 201 202 return (TRUE); 203 } 204 205 sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP); 206 207 /* 208 * Serialize the auth body data into sercred. 209 */ 210 xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE); 211 startpos = XDR_GETPOS(&xdrm); 212 if (!xdr_authloopback(&xdrm, cr)) { 213 printf("authloopback_marshal: xdr_authloopback failed\n"); 214 ret = FALSE; 215 goto done; 216 } 217 218 /* 219 * Make opaque auth credentials to point at the serialized auth body 220 * data. 221 */ 222 auth->ah_cred.oa_base = sercred; 223 auth->ah_cred.oa_length = XDR_GETPOS(&xdrm) - startpos; 224 ASSERT(auth->ah_cred.oa_length <= MAX_AUTH_BYTES); 225 226 /* 227 * serialize credentials and verifier (null) 228 */ 229 if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) && 230 (xdr_opaque_auth(xdrs, &(auth->ah_verf)))) 231 ret = TRUE; 232 else 233 ret = FALSE; 234 235 done: 236 XDR_DESTROY(&xdrm); 237 kmem_free(sercred, MAX_AUTH_BYTES); 238 239 return (ret); 240 } 241 242 /* ARGSUSED */ 243 static bool_t 244 authloopback_validate(AUTH *auth, struct opaque_auth *verf) 245 { 246 return (TRUE); 247 } 248 249 /* ARGSUSED */ 250 static bool_t 251 authloopback_refresh(AUTH *auth, struct rpc_msg *msg, cred_t *cr) 252 { 253 return (FALSE); 254 } 255 256 static void 257 authloopback_destroy(register AUTH *auth) 258 { 259 kmem_cache_free(authloopback_cache, auth); 260 } 261