Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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