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