1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/net/sunrpc/auth_unix.c 4 * 5 * UNIX-style authentication; no AUTH_SHORT support 6 * 7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/slab.h> 11 #include <linux/types.h> 12 #include <linux/sched.h> 13 #include <linux/module.h> 14 #include <linux/mempool.h> 15 #include <linux/sunrpc/clnt.h> 16 #include <linux/sunrpc/auth.h> 17 #include <linux/user_namespace.h> 18 19 20 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 21 # define RPCDBG_FACILITY RPCDBG_AUTH 22 #endif 23 24 static struct rpc_auth unix_auth; 25 static const struct rpc_credops unix_credops; 26 static mempool_t *unix_pool; 27 28 static struct rpc_auth * 29 unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 30 { 31 dprintk("RPC: creating UNIX authenticator for client %p\n", 32 clnt); 33 refcount_inc(&unix_auth.au_count); 34 return &unix_auth; 35 } 36 37 static void 38 unx_destroy(struct rpc_auth *auth) 39 { 40 dprintk("RPC: destroying UNIX authenticator %p\n", auth); 41 } 42 43 /* 44 * Lookup AUTH_UNIX creds for current process 45 */ 46 static struct rpc_cred * 47 unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 48 { 49 struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS); 50 51 dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", 52 from_kuid(&init_user_ns, acred->cred->fsuid), 53 from_kgid(&init_user_ns, acred->cred->fsgid)); 54 55 rpcauth_init_cred(ret, acred, auth, &unix_credops); 56 ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; 57 return ret; 58 } 59 60 static void 61 unx_free_cred_callback(struct rcu_head *head) 62 { 63 struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu); 64 dprintk("RPC: unx_free_cred %p\n", rpc_cred); 65 put_cred(rpc_cred->cr_cred); 66 mempool_free(rpc_cred, unix_pool); 67 } 68 69 static void 70 unx_destroy_cred(struct rpc_cred *cred) 71 { 72 call_rcu(&cred->cr_rcu, unx_free_cred_callback); 73 } 74 75 /* 76 * Match credentials against current the auth_cred. 77 */ 78 static int 79 unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) 80 { 81 unsigned int groups = 0; 82 unsigned int i; 83 84 if (cred->cr_cred == acred->cred) 85 return 1; 86 87 if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid)) 88 return 0; 89 90 if (acred->cred && acred->cred->group_info != NULL) 91 groups = acred->cred->group_info->ngroups; 92 if (groups > UNX_NGROUPS) 93 groups = UNX_NGROUPS; 94 if (cred->cr_cred->group_info == NULL) 95 return groups == 0; 96 if (groups != cred->cr_cred->group_info->ngroups) 97 return 0; 98 99 for (i = 0; i < groups ; i++) 100 if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i])) 101 return 0; 102 return 1; 103 } 104 105 /* 106 * Marshal credentials. 107 * Maybe we should keep a cached credential for performance reasons. 108 */ 109 static __be32 * 110 unx_marshal(struct rpc_task *task, __be32 *p) 111 { 112 struct rpc_clnt *clnt = task->tk_client; 113 struct rpc_cred *cred = task->tk_rqstp->rq_cred; 114 __be32 *base, *hold; 115 int i; 116 struct group_info *gi = cred->cr_cred->group_info; 117 118 *p++ = htonl(RPC_AUTH_UNIX); 119 base = p++; 120 *p++ = htonl(jiffies/HZ); 121 122 /* 123 * Copy the UTS nodename captured when the client was created. 124 */ 125 p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); 126 127 *p++ = htonl((u32) from_kuid(&init_user_ns, cred->cr_cred->fsuid)); 128 *p++ = htonl((u32) from_kgid(&init_user_ns, cred->cr_cred->fsgid)); 129 hold = p++; 130 if (gi) 131 for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++) 132 *p++ = htonl((u32) from_kgid(&init_user_ns, gi->gid[i])); 133 *hold = htonl(p - hold - 1); /* gid array length */ 134 *base = htonl((p - base - 1) << 2); /* cred length */ 135 136 *p++ = htonl(RPC_AUTH_NULL); 137 *p++ = htonl(0); 138 139 return p; 140 } 141 142 /* 143 * Refresh credentials. This is a no-op for AUTH_UNIX 144 */ 145 static int 146 unx_refresh(struct rpc_task *task) 147 { 148 set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); 149 return 0; 150 } 151 152 static __be32 * 153 unx_validate(struct rpc_task *task, __be32 *p) 154 { 155 rpc_authflavor_t flavor; 156 u32 size; 157 158 flavor = ntohl(*p++); 159 if (flavor != RPC_AUTH_NULL && 160 flavor != RPC_AUTH_UNIX && 161 flavor != RPC_AUTH_SHORT) { 162 printk("RPC: bad verf flavor: %u\n", flavor); 163 return ERR_PTR(-EIO); 164 } 165 166 size = ntohl(*p++); 167 if (size > RPC_MAX_AUTH_SIZE) { 168 printk("RPC: giant verf size: %u\n", size); 169 return ERR_PTR(-EIO); 170 } 171 task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; 172 p += (size >> 2); 173 174 return p; 175 } 176 177 int __init rpc_init_authunix(void) 178 { 179 unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred)); 180 return unix_pool ? 0 : -ENOMEM; 181 } 182 183 void rpc_destroy_authunix(void) 184 { 185 mempool_destroy(unix_pool); 186 } 187 188 const struct rpc_authops authunix_ops = { 189 .owner = THIS_MODULE, 190 .au_flavor = RPC_AUTH_UNIX, 191 .au_name = "UNIX", 192 .create = unx_create, 193 .destroy = unx_destroy, 194 .lookup_cred = unx_lookup_cred, 195 }; 196 197 static 198 struct rpc_auth unix_auth = { 199 .au_cslack = UNX_CALLSLACK, 200 .au_rslack = NUL_REPLYSLACK, 201 .au_ops = &authunix_ops, 202 .au_flavor = RPC_AUTH_UNIX, 203 .au_count = REFCOUNT_INIT(1), 204 }; 205 206 static 207 const struct rpc_credops unix_credops = { 208 .cr_name = "AUTH_UNIX", 209 .crdestroy = unx_destroy_cred, 210 .crmatch = unx_match, 211 .crmarshal = unx_marshal, 212 .crrefresh = unx_refresh, 213 .crvalidate = unx_validate, 214 }; 215