1 #include <linux/types.h> 2 #include <linux/sched.h> 3 #include <linux/module.h> 4 #include <linux/sunrpc/types.h> 5 #include <linux/sunrpc/xdr.h> 6 #include <linux/sunrpc/svcsock.h> 7 #include <linux/sunrpc/svcauth.h> 8 #include <linux/err.h> 9 #include <linux/seq_file.h> 10 #include <linux/hash.h> 11 #include <linux/string.h> 12 13 #define RPCDBG_FACILITY RPCDBG_AUTH 14 15 16 /* 17 * AUTHUNIX and AUTHNULL credentials are both handled here. 18 * AUTHNULL is treated just like AUTHUNIX except that the uid/gid 19 * are always nobody (-2). i.e. we do the same IP address checks for 20 * AUTHNULL as for AUTHUNIX, and that is done here. 21 */ 22 23 24 struct unix_domain { 25 struct auth_domain h; 26 int addr_changes; 27 /* other stuff later */ 28 }; 29 30 struct auth_domain *unix_domain_find(char *name) 31 { 32 struct auth_domain *rv, ud; 33 struct unix_domain *new; 34 35 ud.name = name; 36 37 rv = auth_domain_lookup(&ud, 0); 38 39 foundit: 40 if (rv && rv->flavour != RPC_AUTH_UNIX) { 41 auth_domain_put(rv); 42 return NULL; 43 } 44 if (rv) 45 return rv; 46 47 new = kmalloc(sizeof(*new), GFP_KERNEL); 48 if (new == NULL) 49 return NULL; 50 cache_init(&new->h.h); 51 new->h.name = kstrdup(name, GFP_KERNEL); 52 new->h.flavour = RPC_AUTH_UNIX; 53 new->addr_changes = 0; 54 new->h.h.expiry_time = NEVER; 55 56 rv = auth_domain_lookup(&new->h, 2); 57 if (rv == &new->h) { 58 if (atomic_dec_and_test(&new->h.h.refcnt)) BUG(); 59 } else { 60 auth_domain_put(&new->h); 61 goto foundit; 62 } 63 64 return rv; 65 } 66 67 static void svcauth_unix_domain_release(struct auth_domain *dom) 68 { 69 struct unix_domain *ud = container_of(dom, struct unix_domain, h); 70 71 kfree(dom->name); 72 kfree(ud); 73 } 74 75 76 /************************************************** 77 * cache for IP address to unix_domain 78 * as needed by AUTH_UNIX 79 */ 80 #define IP_HASHBITS 8 81 #define IP_HASHMAX (1<<IP_HASHBITS) 82 #define IP_HASHMASK (IP_HASHMAX-1) 83 84 struct ip_map { 85 struct cache_head h; 86 char m_class[8]; /* e.g. "nfsd" */ 87 struct in_addr m_addr; 88 struct unix_domain *m_client; 89 int m_add_change; 90 }; 91 static struct cache_head *ip_table[IP_HASHMAX]; 92 93 static void ip_map_put(struct cache_head *item, struct cache_detail *cd) 94 { 95 struct ip_map *im = container_of(item, struct ip_map,h); 96 if (cache_put(item, cd)) { 97 if (test_bit(CACHE_VALID, &item->flags) && 98 !test_bit(CACHE_NEGATIVE, &item->flags)) 99 auth_domain_put(&im->m_client->h); 100 kfree(im); 101 } 102 } 103 104 static inline int ip_map_hash(struct ip_map *item) 105 { 106 return hash_str(item->m_class, IP_HASHBITS) ^ 107 hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS); 108 } 109 static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp) 110 { 111 return strcmp(tmp->m_class, item->m_class) == 0 112 && tmp->m_addr.s_addr == item->m_addr.s_addr; 113 } 114 static inline void ip_map_init(struct ip_map *new, struct ip_map *item) 115 { 116 strcpy(new->m_class, item->m_class); 117 new->m_addr.s_addr = item->m_addr.s_addr; 118 } 119 static inline void ip_map_update(struct ip_map *new, struct ip_map *item) 120 { 121 cache_get(&item->m_client->h.h); 122 new->m_client = item->m_client; 123 new->m_add_change = item->m_add_change; 124 } 125 126 static void ip_map_request(struct cache_detail *cd, 127 struct cache_head *h, 128 char **bpp, int *blen) 129 { 130 char text_addr[20]; 131 struct ip_map *im = container_of(h, struct ip_map, h); 132 __u32 addr = im->m_addr.s_addr; 133 134 snprintf(text_addr, 20, "%u.%u.%u.%u", 135 ntohl(addr) >> 24 & 0xff, 136 ntohl(addr) >> 16 & 0xff, 137 ntohl(addr) >> 8 & 0xff, 138 ntohl(addr) >> 0 & 0xff); 139 140 qword_add(bpp, blen, im->m_class); 141 qword_add(bpp, blen, text_addr); 142 (*bpp)[-1] = '\n'; 143 } 144 145 static struct ip_map *ip_map_lookup(struct ip_map *, int); 146 147 static int ip_map_parse(struct cache_detail *cd, 148 char *mesg, int mlen) 149 { 150 /* class ipaddress [domainname] */ 151 /* should be safe just to use the start of the input buffer 152 * for scratch: */ 153 char *buf = mesg; 154 int len; 155 int b1,b2,b3,b4; 156 char c; 157 struct ip_map ipm, *ipmp; 158 struct auth_domain *dom; 159 time_t expiry; 160 161 if (mesg[mlen-1] != '\n') 162 return -EINVAL; 163 mesg[mlen-1] = 0; 164 165 /* class */ 166 len = qword_get(&mesg, ipm.m_class, sizeof(ipm.m_class)); 167 if (len <= 0) return -EINVAL; 168 169 /* ip address */ 170 len = qword_get(&mesg, buf, mlen); 171 if (len <= 0) return -EINVAL; 172 173 if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) 174 return -EINVAL; 175 176 expiry = get_expiry(&mesg); 177 if (expiry ==0) 178 return -EINVAL; 179 180 /* domainname, or empty for NEGATIVE */ 181 len = qword_get(&mesg, buf, mlen); 182 if (len < 0) return -EINVAL; 183 184 if (len) { 185 dom = unix_domain_find(buf); 186 if (dom == NULL) 187 return -ENOENT; 188 } else 189 dom = NULL; 190 191 ipm.m_addr.s_addr = 192 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); 193 ipm.h.flags = 0; 194 if (dom) { 195 ipm.m_client = container_of(dom, struct unix_domain, h); 196 ipm.m_add_change = ipm.m_client->addr_changes; 197 } else 198 set_bit(CACHE_NEGATIVE, &ipm.h.flags); 199 ipm.h.expiry_time = expiry; 200 201 ipmp = ip_map_lookup(&ipm, 1); 202 if (ipmp) 203 ip_map_put(&ipmp->h, &ip_map_cache); 204 if (dom) 205 auth_domain_put(dom); 206 if (!ipmp) 207 return -ENOMEM; 208 cache_flush(); 209 return 0; 210 } 211 212 static int ip_map_show(struct seq_file *m, 213 struct cache_detail *cd, 214 struct cache_head *h) 215 { 216 struct ip_map *im; 217 struct in_addr addr; 218 char *dom = "-no-domain-"; 219 220 if (h == NULL) { 221 seq_puts(m, "#class IP domain\n"); 222 return 0; 223 } 224 im = container_of(h, struct ip_map, h); 225 /* class addr domain */ 226 addr = im->m_addr; 227 228 if (test_bit(CACHE_VALID, &h->flags) && 229 !test_bit(CACHE_NEGATIVE, &h->flags)) 230 dom = im->m_client->h.name; 231 232 seq_printf(m, "%s %d.%d.%d.%d %s\n", 233 im->m_class, 234 htonl(addr.s_addr) >> 24 & 0xff, 235 htonl(addr.s_addr) >> 16 & 0xff, 236 htonl(addr.s_addr) >> 8 & 0xff, 237 htonl(addr.s_addr) >> 0 & 0xff, 238 dom 239 ); 240 return 0; 241 } 242 243 244 struct cache_detail ip_map_cache = { 245 .hash_size = IP_HASHMAX, 246 .hash_table = ip_table, 247 .name = "auth.unix.ip", 248 .cache_put = ip_map_put, 249 .cache_request = ip_map_request, 250 .cache_parse = ip_map_parse, 251 .cache_show = ip_map_show, 252 }; 253 254 static DefineSimpleCacheLookup(ip_map, 0) 255 256 257 int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) 258 { 259 struct unix_domain *udom; 260 struct ip_map ip, *ipmp; 261 262 if (dom->flavour != RPC_AUTH_UNIX) 263 return -EINVAL; 264 udom = container_of(dom, struct unix_domain, h); 265 strcpy(ip.m_class, "nfsd"); 266 ip.m_addr = addr; 267 ip.m_client = udom; 268 ip.m_add_change = udom->addr_changes+1; 269 ip.h.flags = 0; 270 ip.h.expiry_time = NEVER; 271 272 ipmp = ip_map_lookup(&ip, 1); 273 274 if (ipmp) { 275 ip_map_put(&ipmp->h, &ip_map_cache); 276 return 0; 277 } else 278 return -ENOMEM; 279 } 280 281 int auth_unix_forget_old(struct auth_domain *dom) 282 { 283 struct unix_domain *udom; 284 285 if (dom->flavour != RPC_AUTH_UNIX) 286 return -EINVAL; 287 udom = container_of(dom, struct unix_domain, h); 288 udom->addr_changes++; 289 return 0; 290 } 291 292 struct auth_domain *auth_unix_lookup(struct in_addr addr) 293 { 294 struct ip_map key, *ipm; 295 struct auth_domain *rv; 296 297 strcpy(key.m_class, "nfsd"); 298 key.m_addr = addr; 299 300 ipm = ip_map_lookup(&key, 0); 301 302 if (!ipm) 303 return NULL; 304 if (cache_check(&ip_map_cache, &ipm->h, NULL)) 305 return NULL; 306 307 if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { 308 if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0) 309 auth_domain_put(&ipm->m_client->h); 310 rv = NULL; 311 } else { 312 rv = &ipm->m_client->h; 313 cache_get(&rv->h); 314 } 315 ip_map_put(&ipm->h, &ip_map_cache); 316 return rv; 317 } 318 319 void svcauth_unix_purge(void) 320 { 321 cache_purge(&ip_map_cache); 322 cache_purge(&auth_domain_cache); 323 } 324 325 static int 326 svcauth_unix_set_client(struct svc_rqst *rqstp) 327 { 328 struct ip_map key, *ipm; 329 330 rqstp->rq_client = NULL; 331 if (rqstp->rq_proc == 0) 332 return SVC_OK; 333 334 strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class); 335 key.m_addr = rqstp->rq_addr.sin_addr; 336 337 ipm = ip_map_lookup(&key, 0); 338 339 if (ipm == NULL) 340 return SVC_DENIED; 341 342 switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { 343 default: 344 BUG(); 345 case -EAGAIN: 346 return SVC_DROP; 347 case -ENOENT: 348 return SVC_DENIED; 349 case 0: 350 rqstp->rq_client = &ipm->m_client->h; 351 cache_get(&rqstp->rq_client->h); 352 ip_map_put(&ipm->h, &ip_map_cache); 353 break; 354 } 355 return SVC_OK; 356 } 357 358 static int 359 svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) 360 { 361 struct kvec *argv = &rqstp->rq_arg.head[0]; 362 struct kvec *resv = &rqstp->rq_res.head[0]; 363 struct svc_cred *cred = &rqstp->rq_cred; 364 365 cred->cr_group_info = NULL; 366 rqstp->rq_client = NULL; 367 368 if (argv->iov_len < 3*4) 369 return SVC_GARBAGE; 370 371 if (svc_getu32(argv) != 0) { 372 dprintk("svc: bad null cred\n"); 373 *authp = rpc_autherr_badcred; 374 return SVC_DENIED; 375 } 376 if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { 377 dprintk("svc: bad null verf\n"); 378 *authp = rpc_autherr_badverf; 379 return SVC_DENIED; 380 } 381 382 /* Signal that mapping to nobody uid/gid is required */ 383 cred->cr_uid = (uid_t) -1; 384 cred->cr_gid = (gid_t) -1; 385 cred->cr_group_info = groups_alloc(0); 386 if (cred->cr_group_info == NULL) 387 return SVC_DROP; /* kmalloc failure - client must retry */ 388 389 /* Put NULL verifier */ 390 svc_putu32(resv, RPC_AUTH_NULL); 391 svc_putu32(resv, 0); 392 393 return SVC_OK; 394 } 395 396 static int 397 svcauth_null_release(struct svc_rqst *rqstp) 398 { 399 if (rqstp->rq_client) 400 auth_domain_put(rqstp->rq_client); 401 rqstp->rq_client = NULL; 402 if (rqstp->rq_cred.cr_group_info) 403 put_group_info(rqstp->rq_cred.cr_group_info); 404 rqstp->rq_cred.cr_group_info = NULL; 405 406 return 0; /* don't drop */ 407 } 408 409 410 struct auth_ops svcauth_null = { 411 .name = "null", 412 .owner = THIS_MODULE, 413 .flavour = RPC_AUTH_NULL, 414 .accept = svcauth_null_accept, 415 .release = svcauth_null_release, 416 .set_client = svcauth_unix_set_client, 417 }; 418 419 420 static int 421 svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) 422 { 423 struct kvec *argv = &rqstp->rq_arg.head[0]; 424 struct kvec *resv = &rqstp->rq_res.head[0]; 425 struct svc_cred *cred = &rqstp->rq_cred; 426 u32 slen, i; 427 int len = argv->iov_len; 428 429 cred->cr_group_info = NULL; 430 rqstp->rq_client = NULL; 431 432 if ((len -= 3*4) < 0) 433 return SVC_GARBAGE; 434 435 svc_getu32(argv); /* length */ 436 svc_getu32(argv); /* time stamp */ 437 slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */ 438 if (slen > 64 || (len -= (slen + 3)*4) < 0) 439 goto badcred; 440 argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */ 441 argv->iov_len -= slen*4; 442 443 cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */ 444 cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */ 445 slen = ntohl(svc_getu32(argv)); /* gids length */ 446 if (slen > 16 || (len -= (slen + 2)*4) < 0) 447 goto badcred; 448 cred->cr_group_info = groups_alloc(slen); 449 if (cred->cr_group_info == NULL) 450 return SVC_DROP; 451 for (i = 0; i < slen; i++) 452 GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv)); 453 454 if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { 455 *authp = rpc_autherr_badverf; 456 return SVC_DENIED; 457 } 458 459 /* Put NULL verifier */ 460 svc_putu32(resv, RPC_AUTH_NULL); 461 svc_putu32(resv, 0); 462 463 return SVC_OK; 464 465 badcred: 466 *authp = rpc_autherr_badcred; 467 return SVC_DENIED; 468 } 469 470 static int 471 svcauth_unix_release(struct svc_rqst *rqstp) 472 { 473 /* Verifier (such as it is) is already in place. 474 */ 475 if (rqstp->rq_client) 476 auth_domain_put(rqstp->rq_client); 477 rqstp->rq_client = NULL; 478 if (rqstp->rq_cred.cr_group_info) 479 put_group_info(rqstp->rq_cred.cr_group_info); 480 rqstp->rq_cred.cr_group_info = NULL; 481 482 return 0; 483 } 484 485 486 struct auth_ops svcauth_unix = { 487 .name = "unix", 488 .owner = THIS_MODULE, 489 .flavour = RPC_AUTH_UNIX, 490 .accept = svcauth_unix_accept, 491 .release = svcauth_unix_release, 492 .domain_release = svcauth_unix_domain_release, 493 .set_client = svcauth_unix_set_client, 494 }; 495 496