1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/param.h> 30 #include <sys/errno.h> 31 #include <sys/vfs.h> 32 #include <sys/vnode.h> 33 #include <sys/cred.h> 34 #include <sys/cmn_err.h> 35 #include <sys/systm.h> 36 #include <sys/kmem.h> 37 #include <sys/pathname.h> 38 #include <sys/utsname.h> 39 #include <sys/debug.h> 40 41 #include <rpc/types.h> 42 #include <rpc/auth.h> 43 #include <rpc/clnt.h> 44 45 #include <nfs/nfs.h> 46 #include <nfs/export.h> 47 #include <nfs/nfs_clnt.h> 48 #include <rpcsvc/nfsauth_prot.h> 49 50 #define EQADDR(a1, a2) \ 51 (bcmp((char *)(a1)->buf, (char *)(a2)->buf, (a1)->len) == 0 && \ 52 (a1)->len == (a2)->len) 53 54 static struct knetconfig auth_knconf; 55 static servinfo_t svp; 56 static clinfo_t ci; 57 58 static struct kmem_cache *exi_cache_handle; 59 static void exi_cache_reclaim(void *); 60 static void exi_cache_trim(struct exportinfo *exi); 61 62 int nfsauth_cache_hit; 63 int nfsauth_cache_miss; 64 int nfsauth_cache_reclaim; 65 66 /* 67 * Number of seconds to wait for an NFSAUTH upcall. 68 */ 69 static int nfsauth_timeout = 20; 70 71 void 72 nfsauth_init(void) 73 { 74 vnode_t *kvp; 75 int error; 76 char addrbuf[SYS_NMLN+16]; 77 78 /* 79 * Setup netconfig. 80 * Assume a connectionless loopback transport. 81 */ 82 if ((error = lookupname("/dev/ticotsord", UIO_SYSSPACE, FOLLOW, 83 NULLVPP, &kvp)) != 0) { 84 cmn_err(CE_CONT, "nfsauth: lookupname: %d\n", error); 85 return; 86 } 87 88 auth_knconf.knc_rdev = kvp->v_rdev; 89 auth_knconf.knc_protofmly = NC_LOOPBACK; 90 auth_knconf.knc_semantics = NC_TPI_COTS_ORD; 91 VN_RELE(kvp); 92 93 (void) strcpy(addrbuf, utsname.nodename); 94 (void) strcat(addrbuf, ".nfsauth"); 95 96 svp.sv_knconf = &auth_knconf; 97 svp.sv_addr.buf = kmem_alloc(strlen(addrbuf)+1, KM_SLEEP); 98 (void) strcpy(svp.sv_addr.buf, addrbuf); 99 svp.sv_addr.len = (uint_t)strlen(addrbuf); 100 svp.sv_addr.maxlen = svp.sv_addr.len; 101 svp.sv_secdata = kmem_alloc(sizeof (struct sec_data), KM_SLEEP); 102 svp.sv_secdata->rpcflavor = AUTH_LOOPBACK; 103 svp.sv_secdata->data = NULL; 104 105 ci.cl_prog = NFSAUTH_PROG; 106 ci.cl_vers = NFSAUTH_VERS; 107 ci.cl_readsize = 0; 108 ci.cl_retrans = 1; 109 ci.cl_flags = 0x0; 110 111 /* 112 * Allocate nfsauth cache handle 113 */ 114 exi_cache_handle = kmem_cache_create("exi_cache_handle", 115 sizeof (struct auth_cache), 0, NULL, NULL, 116 exi_cache_reclaim, NULL, NULL, 0); 117 } 118 119 /* 120 * Finalization routine for nfsauth. It is important to call this routine 121 * before destroying the exported_lock. 122 */ 123 void 124 nfsauth_fini(void) 125 { 126 /* 127 * Deallocate nfsauth cache handle 128 */ 129 kmem_cache_destroy(exi_cache_handle); 130 } 131 132 static int 133 nfsauth_clget(CLIENT **newcl, struct chtab **chp) 134 { 135 return (clget(&ci, &svp, CRED(), newcl, chp)); 136 } 137 138 /* 139 * Convert the address in a netbuf to 140 * a hash index for the auth_cache table. 141 */ 142 static int 143 hash(struct netbuf *a) 144 { 145 int i, h = 0; 146 147 for (i = 0; i < a->len; i++) 148 h ^= a->buf[i]; 149 150 return (h & (AUTH_TABLESIZE - 1)); 151 } 152 153 /* 154 * Mask out the components of an 155 * address that do not identify 156 * a host. For socket addresses the 157 * masking gets rid of the port number. 158 */ 159 static void 160 addrmask(struct netbuf *addr, struct netbuf *mask) 161 { 162 int i; 163 164 for (i = 0; i < addr->len; i++) 165 addr->buf[i] &= mask->buf[i]; 166 } 167 168 /* 169 * nfsauth4_access is used for NFS V4 auth checking. Besides doing 170 * the common nfsauth_access(), it will check if the client can 171 * have a limited access to this vnode even if the security flavor 172 * used does not meet the policy. 173 */ 174 int 175 nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req) 176 { 177 int access; 178 179 access = nfsauth_access(exi, req); 180 181 /* 182 * There are cases that the server needs to allow the client 183 * to have a limited view. 184 * 185 * e.g. 186 * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw" 187 * /export/home is shared as "sec=sys,rw" 188 * 189 * When the client mounts /export with sec=sys, the client 190 * would get a limited view with RO access on /export to see 191 * "home" only because the client is allowed to access 192 * /export/home with auth_sys. 193 */ 194 if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { 195 /* 196 * Allow ro permission with LIMITED view if there is a 197 * sub-dir exported under vp. 198 */ 199 if (has_visible(exi, vp)) { 200 return (NFSAUTH_LIMITED); 201 } 202 } 203 204 return (access); 205 } 206 207 /* 208 * Get the access information from the cache or callup to the mountd 209 * to get and cache the access information in the kernel. 210 */ 211 int 212 nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor) 213 { 214 struct netbuf addr, *claddr; 215 struct auth_cache **head, *ap; 216 CLIENT *clnt; 217 struct chtab *ch; 218 struct auth_req request; 219 struct auth_res result; 220 enum clnt_stat rpcstat; 221 int access; 222 struct timeval timout; 223 static time_t exi_msg = 0; 224 time_t now; 225 226 /* 227 * Now check whether this client already 228 * has an entry for this flavor in the cache 229 * for this export. 230 * Get the caller's address, mask off the 231 * parts of the address that do not identify 232 * the host (port number, etc), and then hash 233 * it to find the chain of cache entries. 234 */ 235 236 claddr = svc_getrpccaller(req->rq_xprt); 237 addr = *claddr; 238 addr.buf = mem_alloc(addr.len); 239 bcopy(claddr->buf, addr.buf, claddr->len); 240 addrmask(&addr, svc_getaddrmask(req->rq_xprt)); 241 head = &exi->exi_cache[hash(&addr)]; 242 243 rw_enter(&exi->exi_cache_lock, RW_READER); 244 for (ap = *head; ap; ap = ap->auth_next) { 245 if (EQADDR(&addr, &ap->auth_addr) && flavor == ap->auth_flavor) 246 break; 247 } 248 if (ap) { /* cache hit */ 249 access = ap->auth_access; 250 ap->auth_time = gethrestime_sec(); 251 nfsauth_cache_hit++; 252 } 253 254 rw_exit(&exi->exi_cache_lock); 255 256 if (ap) { 257 kmem_free(addr.buf, addr.len); 258 return (access); 259 } 260 261 nfsauth_cache_miss++; 262 263 /* 264 * No entry in the cache for this client/flavor 265 * so we need to call the nfsauth service in the 266 * mount daemon. 267 */ 268 269 if (nfsauth_clget(&clnt, &ch)) { 270 kmem_free(addr.buf, addr.len); 271 return (NFSAUTH_DROP); 272 } 273 274 timout.tv_sec = nfsauth_timeout; 275 timout.tv_usec = 0; 276 277 request.req_client.n_len = addr.len; 278 request.req_client.n_bytes = addr.buf; 279 request.req_netid = svc_getnetid(req->rq_xprt); 280 request.req_path = exi->exi_export.ex_path; 281 request.req_flavor = flavor; 282 283 rpcstat = clnt_call(clnt, NFSAUTH_ACCESS, 284 (xdrproc_t)xdr_auth_req, (caddr_t)&request, 285 (xdrproc_t)xdr_auth_res, (caddr_t)&result, 286 timout); 287 288 switch (rpcstat) { 289 case RPC_SUCCESS: 290 access = result.auth_perm; 291 break; 292 case RPC_INTR: 293 break; 294 case RPC_TIMEDOUT: 295 /* 296 * Show messages no more than once per minute 297 */ 298 now = gethrestime_sec(); 299 if ((exi_msg + 60) < now) { 300 exi_msg = now; 301 cmn_err(CE_WARN, "nfsauth: mountd not responding"); 302 } 303 break; 304 default: 305 /* 306 * Show messages no more than once per minute 307 */ 308 now = gethrestime_sec(); 309 if ((exi_msg + 60) < now) { 310 char *errmsg; 311 312 exi_msg = now; 313 errmsg = clnt_sperror(clnt, "nfsauth upcall failed"); 314 cmn_err(CE_WARN, errmsg); 315 kmem_free(errmsg, MAXPATHLEN); 316 } 317 break; 318 } 319 320 clfree(clnt, ch); 321 if (rpcstat != RPC_SUCCESS) { 322 kmem_free(addr.buf, addr.len); 323 return (NFSAUTH_DROP); 324 } 325 326 /* 327 * Now cache the result on the cache chain 328 * for this export (if there's enough memory) 329 */ 330 ap = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP); 331 if (ap) { 332 ap->auth_addr = addr; 333 ap->auth_flavor = flavor; 334 ap->auth_access = access; 335 ap->auth_time = gethrestime_sec(); 336 rw_enter(&exi->exi_cache_lock, RW_WRITER); 337 ap->auth_next = *head; 338 *head = ap; 339 rw_exit(&exi->exi_cache_lock); 340 } else { 341 kmem_free(addr.buf, addr.len); 342 } 343 344 return (access); 345 } 346 347 /* 348 * Check if the requesting client has access to the filesystem with 349 * a given nfs flavor number which is an explicitly shared flavor. 350 */ 351 int 352 nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, 353 int flavor, int perm) 354 { 355 int access; 356 357 if (! (perm & M_4SEC_EXPORTED)) { 358 return (NFSAUTH_DENIED); 359 } 360 361 /* 362 * Optimize if there are no lists 363 */ 364 if ((perm & M_ROOT) == 0) { 365 perm &= ~M_4SEC_EXPORTED; 366 if (perm == M_RO) 367 return (NFSAUTH_RO); 368 if (perm == M_RW) 369 return (NFSAUTH_RW); 370 } 371 372 access = nfsauth_cache_get(exi, req, flavor); 373 374 return (access); 375 } 376 377 int 378 nfsauth_access(struct exportinfo *exi, struct svc_req *req) 379 { 380 int access, mapaccess; 381 struct secinfo *sp; 382 int i, flavor, perm; 383 int authnone_entry = -1; 384 385 /* 386 * Get the nfs flavor number from xprt. 387 */ 388 flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 389 390 /* 391 * First check the access restrictions on the filesystem. If 392 * there are no lists associated with this flavor then there's no 393 * need to make an expensive call to the nfsauth service or to 394 * cache anything. 395 */ 396 397 sp = exi->exi_export.ex_secinfo; 398 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 399 if (flavor != sp[i].s_secinfo.sc_nfsnum) { 400 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 401 authnone_entry = i; 402 continue; 403 } 404 break; 405 } 406 407 mapaccess = 0; 408 409 if (i >= exi->exi_export.ex_seccnt) { 410 /* 411 * Flavor not found, but use AUTH_NONE if it exists 412 */ 413 if (authnone_entry == -1) 414 return (NFSAUTH_DENIED); 415 flavor = AUTH_NONE; 416 mapaccess = NFSAUTH_MAPNONE; 417 i = authnone_entry; 418 } 419 420 /* 421 * If the flavor is in the ex_secinfo list, but not an explicitly 422 * shared flavor by the user, it is a result of the nfsv4 server 423 * namespace setup. We will grant an RO permission similar for 424 * a pseudo node except that this node is a shared one. 425 * 426 * e.g. flavor in (flavor) indicates that it is not explictly 427 * shared by the user: 428 * 429 * / (sys, krb5) 430 * | 431 * export #share -o sec=sys (krb5) 432 * | 433 * secure #share -o sec=krb5 434 * 435 * In this case, when a krb5 request coming in to access 436 * /export, RO permission is granted. 437 */ 438 if (!(sp[i].s_flags & M_4SEC_EXPORTED)) 439 return (mapaccess | NFSAUTH_RO); 440 441 /* 442 * Optimize if there are no lists 443 */ 444 perm = sp[i].s_flags; 445 if ((perm & M_ROOT) == 0) { 446 perm &= ~M_4SEC_EXPORTED; 447 if (perm == M_RO) 448 return (mapaccess | NFSAUTH_RO); 449 if (perm == M_RW) 450 return (mapaccess | NFSAUTH_RW); 451 } 452 453 access = nfsauth_cache_get(exi, req, flavor); 454 455 return (access | mapaccess); 456 } 457 458 /* 459 * Free the nfsauth cache for a given export 460 */ 461 void 462 nfsauth_cache_free(struct exportinfo *exi) 463 { 464 int i; 465 struct auth_cache *p, *next; 466 467 for (i = 0; i < AUTH_TABLESIZE; i++) { 468 for (p = exi->exi_cache[i]; p; p = next) { 469 kmem_free(p->auth_addr.buf, p->auth_addr.len); 470 next = p->auth_next; 471 kmem_cache_free(exi_cache_handle, (void *)p); 472 } 473 } 474 } 475 476 /* 477 * Called by the kernel memory allocator when 478 * memory is low. Free unused cache entries. 479 * If that's not enough, the VM system will 480 * call again for some more. 481 */ 482 /*ARGSUSED*/ 483 void 484 exi_cache_reclaim(void *cdrarg) 485 { 486 int i; 487 struct exportinfo *exi; 488 489 rw_enter(&exported_lock, RW_READER); 490 491 for (i = 0; i < EXPTABLESIZE; i++) { 492 for (exi = exptable[i]; exi; exi = exi->exi_hash) { 493 exi_cache_trim(exi); 494 } 495 } 496 nfsauth_cache_reclaim++; 497 498 rw_exit(&exported_lock); 499 } 500 501 /* 502 * Don't reclaim entries until they've been 503 * in the cache for at least exi_cache_time 504 * seconds. 505 */ 506 time_t exi_cache_time = 60 * 60; 507 508 void 509 exi_cache_trim(struct exportinfo *exi) 510 { 511 struct auth_cache *p; 512 struct auth_cache *prev, *next; 513 int i; 514 time_t stale_time; 515 516 stale_time = gethrestime_sec() - exi_cache_time; 517 518 rw_enter(&exi->exi_cache_lock, RW_WRITER); 519 520 for (i = 0; i < AUTH_TABLESIZE; i++) { 521 522 /* 523 * Free entries that have not been 524 * used for exi_cache_time seconds. 525 */ 526 prev = NULL; 527 for (p = exi->exi_cache[i]; p; p = next) { 528 next = p->auth_next; 529 if (p->auth_time > stale_time) { 530 prev = p; 531 continue; 532 } 533 534 kmem_free(p->auth_addr.buf, p->auth_addr.len); 535 kmem_cache_free(exi_cache_handle, (void *)p); 536 if (prev == NULL) 537 exi->exi_cache[i] = next; 538 else 539 prev->auth_next = next; 540 } 541 } 542 543 rw_exit(&exi->exi_cache_lock); 544 } 545