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