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 .owner = THIS_MODULE, 246 .hash_size = IP_HASHMAX, 247 .hash_table = ip_table, 248 .name = "auth.unix.ip", 249 .cache_put = ip_map_put, 250 .cache_request = ip_map_request, 251 .cache_parse = ip_map_parse, 252 .cache_show = ip_map_show, 253 }; 254 255 static DefineSimpleCacheLookup(ip_map, 0) 256 257 258 int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) 259 { 260 struct unix_domain *udom; 261 struct ip_map ip, *ipmp; 262 263 if (dom->flavour != RPC_AUTH_UNIX) 264 return -EINVAL; 265 udom = container_of(dom, struct unix_domain, h); 266 strcpy(ip.m_class, "nfsd"); 267 ip.m_addr = addr; 268 ip.m_client = udom; 269 ip.m_add_change = udom->addr_changes+1; 270 ip.h.flags = 0; 271 ip.h.expiry_time = NEVER; 272 273 ipmp = ip_map_lookup(&ip, 1); 274 275 if (ipmp) { 276 ip_map_put(&ipmp->h, &ip_map_cache); 277 return 0; 278 } else 279 return -ENOMEM; 280 } 281 282 int auth_unix_forget_old(struct auth_domain *dom) 283 { 284 struct unix_domain *udom; 285 286 if (dom->flavour != RPC_AUTH_UNIX) 287 return -EINVAL; 288 udom = container_of(dom, struct unix_domain, h); 289 udom->addr_changes++; 290 return 0; 291 } 292 293 struct auth_domain *auth_unix_lookup(struct in_addr addr) 294 { 295 struct ip_map key, *ipm; 296 struct auth_domain *rv; 297 298 strcpy(key.m_class, "nfsd"); 299 key.m_addr = addr; 300 301 ipm = ip_map_lookup(&key, 0); 302 303 if (!ipm) 304 return NULL; 305 if (cache_check(&ip_map_cache, &ipm->h, NULL)) 306 return NULL; 307 308 if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { 309 if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0) 310 auth_domain_put(&ipm->m_client->h); 311 rv = NULL; 312 } else { 313 rv = &ipm->m_client->h; 314 cache_get(&rv->h); 315 } 316 ip_map_put(&ipm->h, &ip_map_cache); 317 return rv; 318 } 319 320 void svcauth_unix_purge(void) 321 { 322 cache_purge(&ip_map_cache); 323 cache_purge(&auth_domain_cache); 324 } 325 326 static int 327 svcauth_unix_set_client(struct svc_rqst *rqstp) 328 { 329 struct ip_map key, *ipm; 330 331 rqstp->rq_client = NULL; 332 if (rqstp->rq_proc == 0) 333 return SVC_OK; 334 335 strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class); 336 key.m_addr = rqstp->rq_addr.sin_addr; 337 338 ipm = ip_map_lookup(&key, 0); 339 340 if (ipm == NULL) 341 return SVC_DENIED; 342 343 switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { 344 default: 345 BUG(); 346 case -EAGAIN: 347 return SVC_DROP; 348 case -ENOENT: 349 return SVC_DENIED; 350 case 0: 351 rqstp->rq_client = &ipm->m_client->h; 352 cache_get(&rqstp->rq_client->h); 353 ip_map_put(&ipm->h, &ip_map_cache); 354 break; 355 } 356 return SVC_OK; 357 } 358 359 static int 360 svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp) 361 { 362 struct kvec *argv = &rqstp->rq_arg.head[0]; 363 struct kvec *resv = &rqstp->rq_res.head[0]; 364 struct svc_cred *cred = &rqstp->rq_cred; 365 366 cred->cr_group_info = NULL; 367 rqstp->rq_client = NULL; 368 369 if (argv->iov_len < 3*4) 370 return SVC_GARBAGE; 371 372 if (svc_getu32(argv) != 0) { 373 dprintk("svc: bad null cred\n"); 374 *authp = rpc_autherr_badcred; 375 return SVC_DENIED; 376 } 377 if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { 378 dprintk("svc: bad null verf\n"); 379 *authp = rpc_autherr_badverf; 380 return SVC_DENIED; 381 } 382 383 /* Signal that mapping to nobody uid/gid is required */ 384 cred->cr_uid = (uid_t) -1; 385 cred->cr_gid = (gid_t) -1; 386 cred->cr_group_info = groups_alloc(0); 387 if (cred->cr_group_info == NULL) 388 return SVC_DROP; /* kmalloc failure - client must retry */ 389 390 /* Put NULL verifier */ 391 svc_putu32(resv, RPC_AUTH_NULL); 392 svc_putu32(resv, 0); 393 394 return SVC_OK; 395 } 396 397 static int 398 svcauth_null_release(struct svc_rqst *rqstp) 399 { 400 if (rqstp->rq_client) 401 auth_domain_put(rqstp->rq_client); 402 rqstp->rq_client = NULL; 403 if (rqstp->rq_cred.cr_group_info) 404 put_group_info(rqstp->rq_cred.cr_group_info); 405 rqstp->rq_cred.cr_group_info = NULL; 406 407 return 0; /* don't drop */ 408 } 409 410 411 struct auth_ops svcauth_null = { 412 .name = "null", 413 .owner = THIS_MODULE, 414 .flavour = RPC_AUTH_NULL, 415 .accept = svcauth_null_accept, 416 .release = svcauth_null_release, 417 .set_client = svcauth_unix_set_client, 418 }; 419 420 421 static int 422 svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp) 423 { 424 struct kvec *argv = &rqstp->rq_arg.head[0]; 425 struct kvec *resv = &rqstp->rq_res.head[0]; 426 struct svc_cred *cred = &rqstp->rq_cred; 427 u32 slen, i; 428 int len = argv->iov_len; 429 430 cred->cr_group_info = NULL; 431 rqstp->rq_client = NULL; 432 433 if ((len -= 3*4) < 0) 434 return SVC_GARBAGE; 435 436 svc_getu32(argv); /* length */ 437 svc_getu32(argv); /* time stamp */ 438 slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */ 439 if (slen > 64 || (len -= (slen + 3)*4) < 0) 440 goto badcred; 441 argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */ 442 argv->iov_len -= slen*4; 443 444 cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */ 445 cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */ 446 slen = ntohl(svc_getu32(argv)); /* gids length */ 447 if (slen > 16 || (len -= (slen + 2)*4) < 0) 448 goto badcred; 449 cred->cr_group_info = groups_alloc(slen); 450 if (cred->cr_group_info == NULL) 451 return SVC_DROP; 452 for (i = 0; i < slen; i++) 453 GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv)); 454 455 if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) { 456 *authp = rpc_autherr_badverf; 457 return SVC_DENIED; 458 } 459 460 /* Put NULL verifier */ 461 svc_putu32(resv, RPC_AUTH_NULL); 462 svc_putu32(resv, 0); 463 464 return SVC_OK; 465 466 badcred: 467 *authp = rpc_autherr_badcred; 468 return SVC_DENIED; 469 } 470 471 static int 472 svcauth_unix_release(struct svc_rqst *rqstp) 473 { 474 /* Verifier (such as it is) is already in place. 475 */ 476 if (rqstp->rq_client) 477 auth_domain_put(rqstp->rq_client); 478 rqstp->rq_client = NULL; 479 if (rqstp->rq_cred.cr_group_info) 480 put_group_info(rqstp->rq_cred.cr_group_info); 481 rqstp->rq_cred.cr_group_info = NULL; 482 483 return 0; 484 } 485 486 487 struct auth_ops svcauth_unix = { 488 .name = "unix", 489 .owner = THIS_MODULE, 490 .flavour = RPC_AUTH_UNIX, 491 .accept = svcauth_unix_accept, 492 .release = svcauth_unix_release, 493 .domain_release = svcauth_unix_domain_release, 494 .set_client = svcauth_unix_set_client, 495 }; 496 497