1 /* 2 * linux/net/sunrpc/auth_unix.c 3 * 4 * UNIX-style authentication; no AUTH_SHORT support 5 * 6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/slab.h> 10 #include <linux/types.h> 11 #include <linux/sched.h> 12 #include <linux/module.h> 13 #include <linux/sunrpc/clnt.h> 14 #include <linux/sunrpc/auth.h> 15 #include <linux/user_namespace.h> 16 17 struct unx_cred { 18 struct rpc_cred uc_base; 19 kgid_t uc_gid; 20 kgid_t uc_gids[UNX_NGROUPS]; 21 }; 22 #define uc_uid uc_base.cr_uid 23 24 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 25 # define RPCDBG_FACILITY RPCDBG_AUTH 26 #endif 27 28 static struct rpc_auth unix_auth; 29 static const struct rpc_credops unix_credops; 30 31 static struct rpc_auth * 32 unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 33 { 34 dprintk("RPC: creating UNIX authenticator for client %p\n", 35 clnt); 36 atomic_inc(&unix_auth.au_count); 37 return &unix_auth; 38 } 39 40 static void 41 unx_destroy(struct rpc_auth *auth) 42 { 43 dprintk("RPC: destroying UNIX authenticator %p\n", auth); 44 rpcauth_clear_credcache(auth->au_credcache); 45 } 46 47 static int 48 unx_hash_cred(struct auth_cred *acred, unsigned int hashbits) 49 { 50 return hash_64(from_kgid(&init_user_ns, acred->gid) | 51 ((u64)from_kuid(&init_user_ns, acred->uid) << 52 (sizeof(gid_t) * 8)), hashbits); 53 } 54 55 /* 56 * Lookup AUTH_UNIX creds for current process 57 */ 58 static struct rpc_cred * 59 unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 60 { 61 return rpcauth_lookup_credcache(auth, acred, flags, GFP_NOFS); 62 } 63 64 static struct rpc_cred * 65 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t gfp) 66 { 67 struct unx_cred *cred; 68 unsigned int groups = 0; 69 unsigned int i; 70 71 dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", 72 from_kuid(&init_user_ns, acred->uid), 73 from_kgid(&init_user_ns, acred->gid)); 74 75 if (!(cred = kmalloc(sizeof(*cred), gfp))) 76 return ERR_PTR(-ENOMEM); 77 78 rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); 79 cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; 80 81 if (acred->group_info != NULL) 82 groups = acred->group_info->ngroups; 83 if (groups > UNX_NGROUPS) 84 groups = UNX_NGROUPS; 85 86 cred->uc_gid = acred->gid; 87 for (i = 0; i < groups; i++) 88 cred->uc_gids[i] = acred->group_info->gid[i]; 89 if (i < UNX_NGROUPS) 90 cred->uc_gids[i] = INVALID_GID; 91 92 return &cred->uc_base; 93 } 94 95 static void 96 unx_free_cred(struct unx_cred *unx_cred) 97 { 98 dprintk("RPC: unx_free_cred %p\n", unx_cred); 99 kfree(unx_cred); 100 } 101 102 static void 103 unx_free_cred_callback(struct rcu_head *head) 104 { 105 struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu); 106 unx_free_cred(unx_cred); 107 } 108 109 static void 110 unx_destroy_cred(struct rpc_cred *cred) 111 { 112 call_rcu(&cred->cr_rcu, unx_free_cred_callback); 113 } 114 115 /* 116 * Match credentials against current process creds. 117 * The root_override argument takes care of cases where the caller may 118 * request root creds (e.g. for NFS swapping). 119 */ 120 static int 121 unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) 122 { 123 struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); 124 unsigned int groups = 0; 125 unsigned int i; 126 127 128 if (!uid_eq(cred->uc_uid, acred->uid) || !gid_eq(cred->uc_gid, acred->gid)) 129 return 0; 130 131 if (acred->group_info != NULL) 132 groups = acred->group_info->ngroups; 133 if (groups > UNX_NGROUPS) 134 groups = UNX_NGROUPS; 135 for (i = 0; i < groups ; i++) 136 if (!gid_eq(cred->uc_gids[i], acred->group_info->gid[i])) 137 return 0; 138 if (groups < UNX_NGROUPS && gid_valid(cred->uc_gids[groups])) 139 return 0; 140 return 1; 141 } 142 143 /* 144 * Marshal credentials. 145 * Maybe we should keep a cached credential for performance reasons. 146 */ 147 static __be32 * 148 unx_marshal(struct rpc_task *task, __be32 *p) 149 { 150 struct rpc_clnt *clnt = task->tk_client; 151 struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base); 152 __be32 *base, *hold; 153 int i; 154 155 *p++ = htonl(RPC_AUTH_UNIX); 156 base = p++; 157 *p++ = htonl(jiffies/HZ); 158 159 /* 160 * Copy the UTS nodename captured when the client was created. 161 */ 162 p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); 163 164 *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid)); 165 *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid)); 166 hold = p++; 167 for (i = 0; i < UNX_NGROUPS && gid_valid(cred->uc_gids[i]); i++) 168 *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i])); 169 *hold = htonl(p - hold - 1); /* gid array length */ 170 *base = htonl((p - base - 1) << 2); /* cred length */ 171 172 *p++ = htonl(RPC_AUTH_NULL); 173 *p++ = htonl(0); 174 175 return p; 176 } 177 178 /* 179 * Refresh credentials. This is a no-op for AUTH_UNIX 180 */ 181 static int 182 unx_refresh(struct rpc_task *task) 183 { 184 set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); 185 return 0; 186 } 187 188 static __be32 * 189 unx_validate(struct rpc_task *task, __be32 *p) 190 { 191 rpc_authflavor_t flavor; 192 u32 size; 193 194 flavor = ntohl(*p++); 195 if (flavor != RPC_AUTH_NULL && 196 flavor != RPC_AUTH_UNIX && 197 flavor != RPC_AUTH_SHORT) { 198 printk("RPC: bad verf flavor: %u\n", flavor); 199 return ERR_PTR(-EIO); 200 } 201 202 size = ntohl(*p++); 203 if (size > RPC_MAX_AUTH_SIZE) { 204 printk("RPC: giant verf size: %u\n", size); 205 return ERR_PTR(-EIO); 206 } 207 task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; 208 p += (size >> 2); 209 210 return p; 211 } 212 213 int __init rpc_init_authunix(void) 214 { 215 return rpcauth_init_credcache(&unix_auth); 216 } 217 218 void rpc_destroy_authunix(void) 219 { 220 rpcauth_destroy_credcache(&unix_auth); 221 } 222 223 const struct rpc_authops authunix_ops = { 224 .owner = THIS_MODULE, 225 .au_flavor = RPC_AUTH_UNIX, 226 .au_name = "UNIX", 227 .create = unx_create, 228 .destroy = unx_destroy, 229 .hash_cred = unx_hash_cred, 230 .lookup_cred = unx_lookup_cred, 231 .crcreate = unx_create_cred, 232 }; 233 234 static 235 struct rpc_auth unix_auth = { 236 .au_cslack = UNX_CALLSLACK, 237 .au_rslack = NUL_REPLYSLACK, 238 .au_flags = RPCAUTH_AUTH_NO_CRKEY_TIMEOUT, 239 .au_ops = &authunix_ops, 240 .au_flavor = RPC_AUTH_UNIX, 241 .au_count = ATOMIC_INIT(0), 242 }; 243 244 static 245 const struct rpc_credops unix_credops = { 246 .cr_name = "AUTH_UNIX", 247 .crdestroy = unx_destroy_cred, 248 .crbind = rpcauth_generic_bind_cred, 249 .crmatch = unx_match, 250 .crmarshal = unx_marshal, 251 .crrefresh = unx_refresh, 252 .crvalidate = unx_validate, 253 }; 254