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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26 * Copyright 2017 RackTop Systems. 27 */ 28 29 #include <rpc/types.h> 30 #include <rpc/auth.h> 31 #include <rpc/rpcsec_gss.h> 32 #include <sys/sdt.h> 33 #include <sys/disp.h> 34 #include <nfs/nfs.h> 35 #include <nfs/nfs4.h> 36 #include <nfs/lm.h> 37 #include <sys/systeminfo.h> 38 #include <sys/flock.h> 39 40 /* Helpers */ 41 42 /* Principal handling routines */ 43 /* returns 0 if no match; or 1 for a match */ 44 int 45 rfs4_cmp_cred_set(cred_set_t *p, struct compound_state *cs) 46 { 47 int rc = 0; 48 rpc_gss_principal_t recp; /* cached clnt princ */ 49 rpc_gss_principal_t ibrp; /* inbound req princ */ 50 51 52 if (p->cp_cr == NULL) 53 return (rc); /* nothing to compare with */ 54 55 if (p->cp_aflavor != cs->req->rq_cred.oa_flavor) 56 return (rc); 57 58 if (p->cp_secmod != cs->nfsflavor) 59 return (rc); 60 61 if (crcmp(p->cp_cr, cs->basecr)) 62 return (rc); 63 64 switch (p->cp_aflavor) { 65 case AUTH_DES: 66 rc = (strcmp(p->cp_princ, cs->principal) == 0); 67 break; 68 69 case RPCSEC_GSS: 70 recp = (rpc_gss_principal_t)p->cp_princ; 71 ibrp = (rpc_gss_principal_t)cs->principal; 72 73 if (recp->len != ibrp->len) 74 break; 75 rc = (bcmp(recp->name, ibrp->name, ibrp->len) == 0); 76 break; 77 78 case AUTH_SYS: 79 case AUTH_NONE: 80 default: 81 rc = 1; 82 break; 83 } 84 return (rc); 85 } 86 87 static rpc_gss_principal_t 88 rfs4_dup_princ(rpc_gss_principal_t ppl) 89 { 90 rpc_gss_principal_t pdup; 91 size_t len; 92 93 if (ppl == NULL) 94 return (NULL); 95 96 len = sizeof (int) + ppl->len; 97 pdup = (rpc_gss_principal_t)kmem_alloc(len, KM_SLEEP); 98 bcopy(ppl, pdup, len); 99 return (pdup); 100 } 101 102 void 103 rfs4_set_cred_set(cred_set_t *p, struct compound_state *cs) 104 { 105 ASSERT(p->cp_cr == NULL); 106 107 p->cp_cr = crdup(cs->basecr); 108 p->cp_aflavor = cs->req->rq_cred.oa_flavor; 109 p->cp_secmod = cs->nfsflavor; /* secmod != flavor for RPCSEC_GSS */ 110 111 /* 112 * Set principal as per security flavor 113 */ 114 switch (p->cp_aflavor) { 115 case AUTH_DES: 116 p->cp_princ = strdup(cs->principal); 117 break; 118 119 case RPCSEC_GSS: 120 p->cp_princ = 121 (caddr_t)rfs4_dup_princ((rpc_gss_principal_t)cs->principal); 122 break; 123 124 case AUTH_SYS: 125 case AUTH_NONE: 126 default: 127 break; 128 } 129 } 130 131 void 132 rfs4_free_cred_set(cred_set_t *p) 133 { 134 rpc_gss_principal_t ppl; 135 136 if (p->cp_cr == NULL) 137 return; 138 139 switch (p->cp_aflavor) { 140 case AUTH_DES: 141 kmem_free(p->cp_princ, strlen(p->cp_princ) + 1); 142 break; 143 144 case RPCSEC_GSS: 145 ppl = (rpc_gss_principal_t)p->cp_princ; 146 kmem_free(ppl, ppl->len + sizeof (int)); 147 break; 148 } 149 150 crfree(p->cp_cr); 151 p->cp_cr = NULL; 152 } 153 154 /* principal end */ 155 156 bool_t 157 nfs_clid4_cmp(nfs_client_id4 *s1, nfs_client_id4 *s2) 158 { 159 if (s1->verifier != s2->verifier) 160 return (FALSE); 161 if (s1->id_len != s2->id_len) 162 return (FALSE); 163 if (bcmp(s1->id_val, s2->id_val, s2->id_len)) 164 return (FALSE); 165 return (TRUE); 166 } 167 168 /* 169 * Rudimentary server implementation (XXX - for now) 170 */ 171 void 172 rfs4x_get_server_impl_id(EXCHANGE_ID4resok *resp) 173 { 174 char *sol_impl = "illumos NFSv4.1 Server Implementation"; 175 char *sol_idom = "nfsv41.ietf.org"; 176 void *p; 177 uint_t len = 0; 178 nfs_impl_id4 *nip; 179 180 resp->eir_server_impl_id.eir_server_impl_id_len = 1; 181 nip = kmem_zalloc(sizeof (nfs_impl_id4), KM_SLEEP); 182 resp->eir_server_impl_id.eir_server_impl_id_val = nip; 183 184 /* Domain */ 185 nip->nii_domain.utf8string_len = len = strlen(sol_idom); 186 p = kmem_zalloc(len * sizeof (char), KM_SLEEP); 187 nip->nii_domain.utf8string_val = p; 188 bcopy(sol_idom, p, len); 189 190 /* Implementation */ 191 nip->nii_name.utf8string_len = len = strlen(sol_impl); 192 p = kmem_zalloc(len * sizeof (char), KM_SLEEP); 193 nip->nii_name.utf8string_val = p; 194 bcopy(sol_impl, p, len); 195 196 /* Time is zero for now */ 197 } 198 199 static void 200 rfs4x_set_trunkinfo(EXCHANGE_ID4resok *rok) 201 { 202 const char *nodename = uts_nodename(); 203 size_t nd_len = strlen(nodename); 204 size_t hw_len = strlen(hw_serial); 205 size_t id_len = nd_len + 1 + hw_len; 206 char *s = kmem_alloc(id_len, KM_SLEEP); 207 server_owner4 *so = &rok->eir_server_owner; 208 struct eir_server_scope *ss = &rok->eir_server_scope; 209 210 (void) memcpy(s, nodename, nd_len); 211 s[nd_len] = ' '; 212 (void) memcpy(s + nd_len + 1, hw_serial, hw_len); 213 214 so->so_major_id.so_major_id_len = id_len; 215 so->so_major_id.so_major_id_val = s; 216 217 ss->eir_server_scope_len = id_len; 218 ss->eir_server_scope_val = kmem_alloc(id_len, KM_SLEEP); 219 (void) memcpy(ss->eir_server_scope_val, s, id_len); 220 221 rok->eir_server_owner.so_minor_id = 0; 222 } 223 224 static bool_t 225 client_has_state_locked(rfs4_client_t *cp) 226 { 227 if (list_head(&cp->rc_sessions) != NULL || 228 list_head(&cp->rc_openownerlist) != NULL) 229 return (TRUE); 230 else 231 return (FALSE); 232 } 233 234 /* OPERATIONS */ 235 236 /* 237 * EXCHANGE_ID 238 * RFC5661 sec. 18.35 239 */ 240 void 241 rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop, 242 struct svc_req *req, compound_state_t *cs) 243 { 244 EXCHANGE_ID4args *args = &argop->nfs_argop4_u.opexchange_id; 245 EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id; 246 EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4; 247 rfs4_client_t *cp, *conf; 248 bool_t update, create; 249 client_owner4 *cop; 250 nfs_client_id4 cid; /* cip */ 251 nfsstat4 status = NFS4_OK; 252 nfs4_srv_t *nsrv4; 253 254 DTRACE_NFSV4_2(op__exchange__id__start, 255 struct compound_state *, cs, 256 EXCHANGE_ID4args *, args); 257 258 /* 259 * EXCHANGE_ID's may be preceded by SEQUENCE 260 * 261 * Check that eia_flags only has "valid" spec bits 262 * and that no 'eir_flag' ONLY bits are specified. 263 */ 264 if (args->eia_flags & ~EXID4_FLAG_MASK) { 265 status = NFS4ERR_INVAL; 266 goto err; 267 } 268 269 update = (args->eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A); 270 cop = &args->eia_clientowner; 271 conf = NULL; 272 273 cid.verifier = cop->co_verifier; 274 cid.id_len = cop->co_ownerid.co_ownerid_len; 275 cid.id_val = cop->co_ownerid.co_ownerid_val; 276 cid.cl_addr = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 277 278 /* 279 * Refer to Section 18.35.4 280 */ 281 again: 282 create = TRUE; 283 cp = rfs4_findclient(&cid, &create, conf); 284 285 if (cp == NULL) { 286 status = NFS4ERR_RESOURCE; 287 if (conf) 288 rfs4_client_rele(conf); 289 goto err; 290 } 291 292 if (conf) { 293 rfs4_dbe_lock(cp->rc_dbe); 294 if (cp->rc_cp_confirmed == NULL) 295 cp->rc_cp_confirmed = conf; 296 else 297 rfs4_client_rele(conf); 298 rfs4_dbe_unlock(cp->rc_dbe); 299 conf = NULL; 300 } 301 302 if (create) { 303 /* Record just created */ 304 if (!update) { 305 /* case 1 - utok */ 306 rfs4_set_cred_set(&cp->rc_cr_set, cs); 307 308 rok->eir_clientid = cp->rc_clientid; 309 rok->eir_sequenceid = cp->rc_contrived.xi_sid; 310 goto out; 311 } else { 312 /* no record and trying to update */ 313 status = NFS4ERR_NOENT; 314 goto err_out; 315 } 316 } 317 318 /* Record exists */ 319 320 /* expired clients should be ignored and released */ 321 if (rfs4_lease_expired(cp)) { 322 rfs4_client_close(cp); 323 update = FALSE; 324 goto again; 325 } 326 327 if (cp->rc_need_confirm) { 328 /* UNCONFIRMED */ 329 if (!update) { 330 /* case 4 - utok */ 331 rfs4_client_close(cp); 332 333 ASSERT(!update); 334 goto again; 335 } else { 336 /* case 7 - utok */ 337 status = NFS4ERR_NOENT; 338 goto err_out; 339 } 340 } 341 342 /* record exists and confirmed */ 343 if (!update) { 344 if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { 345 /* case 3 */ 346 /* lease is checked above */ 347 rfs4_dbe_lock(cp->rc_dbe); 348 if (!client_has_state_locked(cp)) { 349 rfs4_dbe_unlock(cp->rc_dbe); 350 351 rfs4_client_close(cp); 352 ASSERT(!update); 353 goto again; 354 } 355 rfs4_dbe_unlock(cp->rc_dbe); 356 357 /* 358 * clid_in_use. old_client_ret has unexpired 359 * lease with state. 360 */ 361 status = NFS4ERR_CLID_INUSE; 362 goto err_out; 363 } else if (cp->rc_nfs_client.verifier != cid.verifier) { 364 /* case 5: Client Restart */ 365 /* 366 * Skip confirmed client record to allow confirmed 367 * and unconfirmed state at the same time. The number 368 * of states can collapse to one once the server 369 * receives an applicable CREATE_SESSION or EXCHANGE_ID. 370 */ 371 ASSERT(conf == NULL); 372 conf = cp; 373 ASSERT(!update); 374 goto again; 375 376 } else if (nfs_clid4_cmp(&cp->rc_nfs_client, &cid)) { 377 /* case 2 - utok */ 378 rok->eir_clientid = cp->rc_clientid; 379 rok->eir_sequenceid = cp->rc_contrived.xi_sid; 380 /* trickle down to "out" */ 381 382 } else { 383 /* something is really wacky in srv state */ 384 status = NFS4ERR_SERVERFAULT; 385 goto err_out; 386 } 387 388 } else { /* UPDATE */ 389 if (cp->rc_nfs_client.verifier != cid.verifier) { 390 /* 18.35.4 case 8 */ 391 status = NFS4ERR_NOT_SAME; 392 goto err_out; 393 } 394 if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { 395 /* 18.35.4 case 9 */ 396 status = NFS4ERR_PERM; 397 goto err_out; 398 } 399 400 /* case 6 - utok */ 401 rok->eir_clientid = cp->rc_clientid; 402 rok->eir_sequenceid = cp->rc_contrived.xi_sid; 403 /* trickle down to "out" */ 404 } 405 out: 406 rok->eir_flags = 0; 407 if (resp->eir_status == NFS4_OK && !cp->rc_need_confirm) 408 rok->eir_flags |= EXCHGID4_FLAG_CONFIRMED_R; 409 410 /* 411 * State Protection (See sec. 2.10.8.3) 412 */ 413 cp->rc_state_prot.sp_type = args->eia_state_protect.spa_how; 414 switch (cp->rc_state_prot.sp_type) { 415 case SP4_NONE: 416 break; 417 418 case SP4_MACH_CRED: 419 break; 420 421 case SP4_SSV: 422 /* 423 * SSV state protection is not implemented. 424 */ 425 status = NFS4ERR_ENCR_ALG_UNSUPP; 426 goto err_out; 427 default: 428 status = NFS4ERR_INVAL; 429 goto err_out; 430 431 } 432 433 /* 434 * Referrals supports 435 */ 436 if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_REFER) { 437 rok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 438 } 439 440 /* 441 * Migration/Replication not (yet) supported 442 */ 443 if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_MIGR) 444 rok->eir_flags &= ~EXCHGID4_FLAG_SUPP_MOVED_MIGR; 445 446 /* 447 * RFC8881 Section 13.1 Client ID and Session Considerations 448 * Non-metadata server, do not support pNFS (yet). 449 */ 450 rok->eir_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 451 452 /* force no state protection for now */ 453 rok->eir_state_protect.spr_how = SP4_NONE; 454 455 /* Implementation specific mojo */ 456 if (args->eia_client_impl_id.eia_client_impl_id_len != 0) { 457 /* EMPTY */; 458 } 459 460 nsrv4 = nfs4_get_srv(); 461 462 /* Record clientid in stable storage */ 463 rfs4_ss_clid(nsrv4, cp); 464 465 /* Server's implementation */ 466 rfs4x_get_server_impl_id(rok); 467 468 /* compute trunking capabilities */ 469 bzero(&rok->eir_server_scope, sizeof (rok->eir_server_scope)); 470 bzero(&rok->eir_server_owner, sizeof (server_owner4)); 471 472 /* Add trunk handling */ 473 rfs4x_set_trunkinfo(rok); 474 475 /* 476 * Check to see if client can perform reclaims 477 */ 478 rfs4_ss_chkclid(nsrv4, cp); 479 480 err_out: 481 rfs4_client_rele(cp); 482 err: 483 *cs->statusp = resp->eir_status = status; 484 485 DTRACE_NFSV4_2(op__exchange__id__done, 486 struct compound_state *, cs, 487 EXCHANGE_ID4res *, resp); 488 } 489 490 void 491 rfs4x_exchange_id_free(nfs_resop4 *resop) 492 { 493 EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id; 494 EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4; 495 struct server_owner4 *sop = &rok->eir_server_owner; 496 nfs_impl_id4 *nip; 497 int len = 0; 498 499 /* Server Owner: major */ 500 if ((len = sop->so_major_id.so_major_id_len) != 0) 501 kmem_free(sop->so_major_id.so_major_id_val, len); 502 503 if ((nip = rok->eir_server_impl_id.eir_server_impl_id_val) != NULL) { 504 /* Immplementation */ 505 len = nip->nii_name.utf8string_len; 506 kmem_free(nip->nii_name.utf8string_val, len * sizeof (char)); 507 508 /* Domain */ 509 len = nip->nii_domain.utf8string_len; 510 kmem_free(nip->nii_domain.utf8string_val, len * sizeof (char)); 511 512 /* Server Impl */ 513 kmem_free(nip, sizeof (nfs_impl_id4)); 514 } 515 } 516 517 void 518 rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop, 519 struct svc_req *req, compound_state_t *cs) 520 { 521 CREATE_SESSION4args *args = &argop->nfs_argop4_u.opcreate_session; 522 CREATE_SESSION4res *resp = &resop->nfs_resop4_u.opcreate_session; 523 CREATE_SESSION4resok *rok = &resp->CREATE_SESSION4res_u.csr_resok4; 524 CREATE_SESSION4resok *crp; 525 rfs4_client_t *cp; 526 rfs4_session_t *sp; 527 session41_create_t sca; 528 sequenceid4 stseq; 529 sequenceid4 agseq; 530 nfsstat4 status = NFS4_OK; 531 532 DTRACE_NFSV4_2(op__create__session__start, 533 struct compound_state *, cs, 534 CREATE_SESSION4args*, args); 535 536 /* 537 * A CREATE_SESSION request can be prefixed by OP_SEQUENCE. 538 * In this case, the newly created session has no relation 539 * to the sessid used for the OP_SEQUENCE. 540 */ 541 542 /* 543 * Find the clientid 544 */ 545 cp = rfs4_findclient_by_id(args->csa_clientid, TRUE); 546 if (cp == NULL) { 547 status = NFS4ERR_STALE_CLIENTID; 548 goto out; 549 } 550 551 /* 552 * Make sure the lease is still valid. 553 */ 554 if (rfs4_lease_expired(cp)) { 555 rfs4_client_close(cp); 556 status = NFS4ERR_STALE_CLIENTID; 557 goto out; 558 } 559 560 /* 561 * Sequenceid processing (handling replay's, etc) 562 */ 563 agseq = args->csa_sequence; 564 stseq = cp->rc_contrived.xi_sid; 565 if (stseq == agseq + 1) { 566 /* 567 * If the previous sequenceid, then must be a replay of a 568 * previous CREATE_SESSION; return the cached result. 569 */ 570 crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res; 571 status = cp->rc_contrived.cs_status; 572 rok->csr_sequence = agseq; 573 bcopy(crp->csr_sessionid, rok->csr_sessionid, 574 sizeof (sessionid4)); 575 rok->csr_flags = crp->csr_flags; 576 rok->csr_fore_chan_attrs = crp->csr_fore_chan_attrs; 577 rok->csr_back_chan_attrs = crp->csr_back_chan_attrs; 578 579 rfs4_update_lease(cp); 580 rfs4_client_rele(cp); 581 goto out; 582 } 583 584 if (stseq != agseq) { 585 /* 586 * No way to differentiate MISORD_NEWREQ vs. MISORD_REPLAY, 587 * so anything else, we simply treat as SEQ_MISORDERED. 588 */ 589 status = NFS4ERR_SEQ_MISORDERED; 590 rfs4_client_rele(cp); 591 goto out; 592 } 593 594 /* 595 * Clientid confirmation 596 */ 597 if (cp->rc_need_confirm) { 598 if (rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { 599 cp->rc_need_confirm = FALSE; 600 if (cp->rc_cp_confirmed != NULL) { 601 rfs4_client_close(cp->rc_cp_confirmed); 602 cp->rc_cp_confirmed = NULL; 603 } 604 } else { 605 status = NFS4ERR_CLID_INUSE; 606 rfs4_client_rele(cp); 607 goto out; 608 } 609 } 610 611 /* 612 * Session creation 613 */ 614 sca.cs_error = 0; 615 sca.cs_req = req; 616 sca.cs_client = cp; 617 sca.cs_aotw = *args; 618 sp = rfs4x_createsession(&sca); 619 620 if (sca.cs_error) { 621 status = sca.cs_error; 622 rfs4_client_rele(cp); 623 if (sp != NULL) 624 rfs4x_session_rele(sp); 625 goto out; 626 } 627 628 if (sp == NULL) { 629 status = NFS4ERR_SERVERFAULT; 630 rfs4_client_rele(cp); 631 goto out; 632 } 633 634 /* 635 * Need to store the result in the rfs4_client_t's contrived 636 * result slot and then respond from there. This way, when the 637 * csa_sequence == contrived.cc_sid, we can return the latest 638 * cached result. (see replay: above) 639 */ 640 crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res; 641 cp->rc_contrived.cs_status = NFS4_OK; 642 rok->csr_sequence = crp->csr_sequence = cp->rc_contrived.xi_sid; 643 bcopy(sp->sn_sessid, rok->csr_sessionid, sizeof (sessionid4)); 644 bcopy(sp->sn_sessid, crp->csr_sessionid, sizeof (sessionid4)); 645 rok->csr_flags = crp->csr_flags = sp->sn_csflags; 646 647 cp->rc_contrived.xi_sid++; 648 649 rok->csr_fore_chan_attrs = 650 crp->csr_fore_chan_attrs = sp->sn_fore->cn_attrs; 651 rok->csr_back_chan_attrs = crp->csr_back_chan_attrs = 652 sp->sn_fore->cn_back_attrs; 653 654 rfs4_update_lease(cp); 655 656 /* 657 * References from the session to the client are 658 * accounted for while session is being created. 659 */ 660 rfs4_client_rele(cp); 661 rfs4x_session_rele(sp); 662 out: 663 *cs->statusp = resp->csr_status = status; 664 665 DTRACE_NFSV4_2(op__create__session__done, 666 struct compound_state *, cs, 667 CREATE_SESSION4res *, resp); 668 } 669 670 /* ARGSUSED */ 671 void 672 rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop, 673 struct svc_req *req, compound_state_t *cs) 674 { 675 DESTROY_SESSION4args *args = &argop->nfs_argop4_u.opdestroy_session; 676 DESTROY_SESSION4res *resp = &resop->nfs_resop4_u.opdestroy_session; 677 rfs4_session_t *sp; 678 rfs4_client_t *cp; 679 nfsstat4 status = NFS4_OK; 680 int addref = 0; /* additional reference */ 681 682 DTRACE_NFSV4_2(op__destroy__session__start, 683 struct compound_state *, cs, 684 DESTROY_SESSION4args *, args); 685 686 /* section 18.37.3 rfc5661 */ 687 if (rfs4_has_session(cs)) { 688 /* compound with a sequence */ 689 if (bcmp(args->dsa_sessionid, cs->sp->sn_sessid, 690 sizeof (sessionid4)) == 0) { 691 /* 692 * Same session. 693 * must be the final operation in the COMPOUND request 694 */ 695 if ((cs->op_pos + 1) != cs->op_len) { 696 status = NFS4ERR_NOT_ONLY_OP; 697 goto out; 698 } 699 addref++; 700 } else { 701 /* Not the same session */ 702 DTRACE_PROBE(nfss41__i__destroy_encap_session); 703 704 } 705 } 706 707 sp = rfs4x_findsession_by_id(args->dsa_sessionid); 708 if (sp == NULL) { 709 status = NFS4ERR_BADSESSION; 710 goto out; 711 } 712 713 /* 714 * State Protection (See sec. 2.10.8.3) 715 * 716 * verify cred that was used to create the session matches and is in 717 * concordance w/the state protection type used. 718 */ 719 cp = sp->sn_clnt; 720 switch (cp->rc_state_prot.sp_type) { 721 case SP4_MACH_CRED: 722 if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { 723 status = NFS4ERR_PERM; 724 goto err_out; 725 } 726 break; 727 728 case SP4_SSV: 729 /* 730 * Todo -- Missing SSV validation here, if/when 731 * SSV state protection is implemented. 732 * Should not get this after check in EXCHANGE_ID 733 */ 734 status = NFS4ERR_PERM; 735 goto err_out; 736 737 case SP4_NONE: 738 break; 739 740 default: 741 break; 742 } 743 744 status = rfs4x_destroysession(sp, 2 + addref); 745 err_out: 746 rfs4x_session_rele(sp); 747 out: 748 *cs->statusp = resp->dsr_status = status; 749 750 DTRACE_NFSV4_2(op__destroy__session__done, 751 struct compound_state *, cs, 752 DESTROY_SESSION4res *, resp); 753 } 754 755 /* 756 * Find session and validate sequence args. 757 * If this function successfully completes the compound state 758 * will contain a session pointer. 759 */ 760 static nfsstat4 761 rfs4x_find_session(SEQUENCE4args *sargs, struct compound_state *cs) 762 { 763 rfs4_session_t *sp; 764 slotid4 slot; 765 766 ASSERT(sargs != NULL); 767 768 if ((sp = rfs4x_findsession_by_id(sargs->sa_sessionid)) == NULL) 769 return (NFS4ERR_BADSESSION); 770 771 slot = sargs->sa_slotid; 772 if (slot >= sp->sn_fore->cn_attrs.ca_maxrequests) { 773 rfs4x_session_rele(sp); 774 return (NFS4ERR_BADSLOT); 775 } 776 cs->sp = sp; 777 cs->cachethis = sargs->sa_cachethis; 778 779 return (NFS4_OK); 780 } 781 782 /* called under held lock */ 783 static nfsstat4 784 check_slot_seqid(rfs4_slot_t *slot, sequenceid4 seqid) 785 { 786 nfsstat4 status = NFS4ERR_SEQ_MISORDERED; 787 788 if (slot->se_flags & RFS4_SLOT_INUSE) { 789 /* 790 * There are three cases: 791 * 1. Duplicated requests for currently performing 792 * duplicated request. 793 * 2. New request for currently performing duplicated 794 * request. 795 * 3. Request with bad seqid for non finished performing 796 * request (due to a little window between 'prep' 797 * stage and actual renew se_seqid). 798 * In all cases tell a client to retry request later. 799 */ 800 if (slot->se_seqid == seqid || slot->se_seqid + 1 == seqid) { 801 status = NFS4ERR_DELAY; 802 } 803 } else { 804 if (seqid == slot->se_seqid + 1) 805 status = NFS4_OK; 806 else if (seqid == slot->se_seqid) 807 status = nfserr_replay_cache; 808 } 809 return (status); 810 } 811 812 static boolean_t is_solo_sequence(const COMPOUND4res *resp) 813 { 814 return (resp->array_len == 1 && resp->array[0].resop == OP_SEQUENCE); 815 } 816 817 /* 818 * Prep stage for SEQUENCE operation. 819 * 820 * Main purpose to call this: 821 * - check on cached replay 822 * - Set cs.sp and cs.slot 823 */ 824 int 825 rfs4x_sequence_prep(COMPOUND4args *args, COMPOUND4res *resp, 826 compound_state_t *cs, SVCXPRT *xprt) 827 { 828 SEQUENCE4args *sargs; 829 nfsstat4 status; 830 rfs4_slot_t *slot; 831 XDR *xdrs; 832 833 if (args->array_len == 0 || args->array[0].argop != OP_SEQUENCE) 834 return (NFS4_OK); 835 836 sargs = &args->array[0].nfs_argop4_u.opsequence; 837 838 status = rfs4x_find_session(sargs, cs); 839 if (status != NFS4_OK) 840 return (status); 841 842 ASSERT(cs->sp != NULL); 843 844 if (args->array_len > cs->sp->sn_fore->cn_attrs.ca_maxoperations) 845 return (NFS4ERR_TOO_MANY_OPS); 846 847 xdrs = &xprt->xp_xdrin; 848 if (xdr_getpos(xdrs) > cs->sp->sn_fore->cn_attrs.ca_maxrequestsize) 849 return (NFS4ERR_REQ_TOO_BIG); 850 851 /* have reference to session */ 852 slot = &cs->sp->sn_slots[sargs->sa_slotid]; 853 854 mutex_enter(&slot->se_lock); 855 status = check_slot_seqid(slot, sargs->sa_sequenceid); 856 if (status == nfserr_replay_cache) { 857 if (slot->se_flags & RFS4_SLOT_CACHED) { 858 slot->se_flags |= RFS4_SLOT_INUSE; 859 cs->slot = slot; 860 *resp = slot->se_buf; 861 } else if (args->array_len == 1) { 862 /* 863 * If original request was solo 'sequence' operation, 864 * it would be always cached. So this request differs 865 * from the previous. 866 */ 867 status = NFS4ERR_SEQ_FALSE_RETRY; 868 } else { 869 status = NFS4ERR_RETRY_UNCACHED_REP; 870 } 871 } else if (status == NFS4_OK) { 872 slot->se_flags |= RFS4_SLOT_INUSE; 873 cs->slot = slot; 874 } 875 mutex_exit(&slot->se_lock); 876 877 return (status); 878 } 879 880 /* 881 * Do cleanup things 882 * 1. cache reply 883 * 2. release slot 884 */ 885 void 886 rfs4x_sequence_done(COMPOUND4res *resp, compound_state_t *cs) 887 { 888 rfs4_slot_t *slot = cs->slot; 889 rfs4_session_t *sp = cs->sp; 890 int add = 0; 891 892 ASSERT(slot != NULL); 893 ASSERT(sp != NULL); 894 895 mutex_enter(&slot->se_lock); 896 slot->se_flags &= ~RFS4_SLOT_INUSE; 897 898 if (*cs->statusp != nfserr_replay_cache) { 899 if (slot->se_flags & RFS4_SLOT_CACHED) { 900 rfs4_compound_free(&slot->se_buf); 901 slot->se_flags &= ~RFS4_SLOT_CACHED; 902 add = -1; 903 } 904 905 if (cs->cachethis || is_solo_sequence(resp)) { 906 slot->se_flags |= RFS4_SLOT_CACHED; 907 slot->se_buf = *resp; /* cache a reply */ 908 add += 1; 909 } else { 910 rfs4_compound_free(resp); 911 } 912 } 913 mutex_exit(&slot->se_lock); 914 915 if (add != 0) 916 atomic_add_32(&sp->sn_rcached, add); 917 } 918 919 /* 920 * Process the SEQUENCE operation. The session pointer has already been 921 * cached in the compound state, so we just dereference 922 */ 923 /*ARGSUSED*/ 924 void 925 rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop, 926 struct svc_req *req, compound_state_t *cs) 927 { 928 SEQUENCE4args *args = &argop->nfs_argop4_u.opsequence; 929 SEQUENCE4res *resp = &resop->nfs_resop4_u.opsequence; 930 SEQUENCE4resok *rok = &resp->SEQUENCE4res_u.sr_resok4; 931 rfs4_session_t *sp = cs->sp; 932 rfs4_slot_t *slot = cs->slot; 933 nfsstat4 status = NFS4_OK; 934 uint32_t cbstat = 0; 935 int buflen; 936 937 DTRACE_NFSV4_2(op__sequence__start, 938 struct compound_state *, cs, 939 SEQUENCE4args *, args); 940 941 ASSERT(sp != NULL && slot != NULL); 942 943 if (cs->op_pos != 0) { 944 status = NFS4ERR_SEQUENCE_POS; 945 goto out; 946 } 947 948 if (rfs4_lease_expired(sp->sn_clnt)) { 949 status = NFS4ERR_BADSESSION; 950 goto out; 951 } 952 953 buflen = args->sa_cachethis ? 954 sp->sn_fore->cn_attrs.ca_maxresponsesize_cached : 955 sp->sn_fore->cn_attrs.ca_maxresponsesize; 956 957 if (buflen < NFS4_MIN_HDR_SEQSZ) { 958 status = args->sa_cachethis ? 959 NFS4ERR_REP_TOO_BIG_TO_CACHE : NFS4ERR_REP_TOO_BIG; 960 goto out; 961 } 962 963 rfs4_dbe_lock(sp->sn_dbe); 964 cs->client = sp->sn_clnt; 965 966 DTRACE_PROBE1(compound_clid, clientid4, cs->client->rc_clientid); 967 968 ASSERT(args->sa_sequenceid == slot->se_seqid + 1); 969 970 /* 971 * New request. 972 */ 973 mutex_enter(&slot->se_lock); 974 slot->se_seqid = args->sa_sequenceid; 975 mutex_exit(&slot->se_lock); 976 977 cs->slotno = args->sa_slotid; 978 979 /* Update access time */ 980 sp->sn_laccess = nfs_sys_uptime(); 981 982 /* Prepare result */ 983 bcopy(sp->sn_sessid, rok->sr_sessionid, sizeof (sessionid4)); 984 rok->sr_sequenceid = slot->se_seqid; 985 rok->sr_slotid = args->sa_slotid; 986 rok->sr_highest_slotid = 987 sp->sn_fore->cn_attrs.ca_maxrequests - 1; 988 rok->sr_target_highest_slotid = 989 sp->sn_fore->cn_attrs.ca_maxrequests - 1; 990 rok->sr_status_flags |= cbstat; 991 rfs4_dbe_unlock(sp->sn_dbe); 992 993 /* Update lease (out of session lock) */ 994 rfs4_update_lease(cs->client); 995 996 out: 997 *cs->statusp = resp->sr_status = status; 998 DTRACE_NFSV4_2(op__sequence__done, 999 struct compound_state *, cs, 1000 SEQUENCE4res *, resp); 1001 } 1002 1003 /* ARGSUSED */ 1004 void 1005 rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop, 1006 struct svc_req *req, compound_state_t *cs) 1007 { 1008 RECLAIM_COMPLETE4args *args = &argop->nfs_argop4_u.opreclaim_complete; 1009 RECLAIM_COMPLETE4res *resp = &resop->nfs_resop4_u.opreclaim_complete; 1010 rfs4_client_t *cp; 1011 nfsstat4 status = NFS4_OK; 1012 1013 DTRACE_NFSV4_2(op__reclaim__complete__start, 1014 struct compound_state *, cs, 1015 RECLAIM_COMPLETE4args *, args); 1016 1017 cp = cs->client; 1018 rfs4_dbe_lock(cp->rc_dbe); 1019 if (args->rca_one_fs) { 1020 /* do what? we don't track this */ 1021 goto out; 1022 } 1023 1024 if (cp->rc_reclaim_completed) { 1025 status = NFS4ERR_COMPLETE_ALREADY; 1026 goto out; 1027 } 1028 1029 if (cp->rc_can_reclaim) { 1030 ASSERT(rfs4_servinst(cp)->nreclaim > 0); 1031 atomic_add_32(&(rfs4_servinst(cp))->nreclaim, -1); 1032 } 1033 1034 cp->rc_reclaim_completed = 1; 1035 out: 1036 rfs4_dbe_unlock(cp->rc_dbe); 1037 1038 *cs->statusp = resp->rcr_status = status; 1039 DTRACE_NFSV4_2(op__reclaim__complete__done, 1040 struct compound_state *, cs, 1041 RECLAIM_COMPLETE4res *, resp); 1042 } 1043 1044 /* ARGSUSED */ 1045 void 1046 rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop, 1047 struct svc_req *req, compound_state_t *cs) 1048 { 1049 DESTROY_CLIENTID4args *args = &argop->nfs_argop4_u.opdestroy_clientid; 1050 DESTROY_CLIENTID4res *resp = &resop->nfs_resop4_u.opdestroy_clientid; 1051 rfs4_client_t *cp; 1052 nfsstat4 status = NFS4_OK; 1053 1054 DTRACE_NFSV4_2(op__destroy__clientid__start, 1055 struct compound_state *, cs, 1056 DESTROY_CLIENTID4args *, args); 1057 1058 cp = rfs4_findclient_by_id(args->dca_clientid, TRUE); 1059 if (cp == NULL) { 1060 status = NFS4ERR_STALE_CLIENTID; 1061 goto end; 1062 } 1063 1064 rfs4_dbe_lock(cp->rc_dbe); 1065 if (client_has_state_locked(cp)) 1066 status = NFS4ERR_CLIENTID_BUSY; 1067 else 1068 cp->rc_destroying = TRUE; 1069 rfs4_dbe_unlock(cp->rc_dbe); 1070 1071 if (status == NFS4_OK) 1072 rfs4_client_close(cp); 1073 else 1074 rfs4_client_rele(cp); 1075 end: 1076 *cs->statusp = resp->dcr_status = status; 1077 1078 DTRACE_NFSV4_2(op__destroy__clientid__done, 1079 struct compound_state *, cs, 1080 DESTROY_CLIENTID4res *, resp); 1081 } 1082 1083 /*ARGSUSED*/ 1084 void 1085 rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop, 1086 struct svc_req *req, compound_state_t *cs) 1087 { 1088 BIND_CONN_TO_SESSION4args *args = 1089 &argop->nfs_argop4_u.opbind_conn_to_session; 1090 BIND_CONN_TO_SESSION4res *resp = 1091 &resop->nfs_resop4_u.opbind_conn_to_session; 1092 BIND_CONN_TO_SESSION4resok *rok = 1093 &resp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4; 1094 rfs4_session_t *sp; 1095 nfsstat4 status = NFS4_OK; 1096 1097 DTRACE_NFSV4_2(op__bind__conn__to__session__start, 1098 struct compound_state *, cs, 1099 BIND_CONN_TO_SESSION4args *, args); 1100 1101 if (cs->op_pos != 0) { 1102 status = NFS4ERR_NOT_ONLY_OP; 1103 goto end; 1104 } 1105 1106 sp = rfs4x_findsession_by_id(args->bctsa_sessid); 1107 if (sp == NULL) { 1108 status = NFS4ERR_BADSESSION; 1109 goto end; 1110 } 1111 1112 rfs4_update_lease(sp->sn_clnt); /* no need lock protection */ 1113 1114 rfs4_dbe_lock(sp->sn_dbe); 1115 sp->sn_laccess = nfs_sys_uptime(); 1116 rfs4_dbe_unlock(sp->sn_dbe); 1117 1118 rok->bctsr_use_conn_in_rdma_mode = FALSE; 1119 1120 switch (args->bctsa_dir) { 1121 case CDFC4_FORE: 1122 case CDFC4_FORE_OR_BOTH: 1123 /* always map to Fore */ 1124 rok->bctsr_dir = CDFS4_FORE; 1125 break; 1126 1127 case CDFC4_BACK: 1128 case CDFC4_BACK_OR_BOTH: 1129 /* TODO: always map to Back */ 1130 rok->bctsr_dir = CDFS4_FORE; 1131 break; 1132 default: 1133 break; 1134 } 1135 1136 bcopy(sp->sn_sessid, rok->bctsr_sessid, sizeof (sessionid4)); 1137 rfs4x_session_rele(sp); 1138 end: 1139 *cs->statusp = resp->bctsr_status = status; 1140 1141 DTRACE_NFSV4_2(op__bind__conn__to__session__done, 1142 struct compound_state *, cs, 1143 BIND_CONN_TO_SESSION4res *, resp); 1144 } 1145 1146 /* ARGSUSED */ 1147 void 1148 rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop, 1149 struct svc_req *req, compound_state_t *cs) 1150 { 1151 SECINFO_NO_NAME4res *resp = &resop->nfs_resop4_u.opsecinfo_no_name; 1152 nfsstat4 status; 1153 bool_t dotdot; 1154 1155 DTRACE_NFSV4_1(op__secinfo__no__name__start, 1156 struct compound_state *, cs); 1157 1158 if (cs->vp == NULL) { 1159 status = NFS4ERR_NOFILEHANDLE; 1160 goto out; 1161 } 1162 1163 if (cs->vp->v_type != VDIR) { 1164 status = NFS4ERR_NOTDIR; 1165 goto out; 1166 } 1167 1168 dotdot = 1169 (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT); 1170 1171 status = do_rfs4_op_secinfo(cs, dotdot ? ".." : ".", resp); 1172 1173 /* Cleanup FH as described at 18.45.3 and 2.6.3.1.1.8 */ 1174 if (status == NFS4_OK) { 1175 VN_RELE(cs->vp); 1176 cs->vp = NULL; 1177 } 1178 out: 1179 *cs->statusp = resp->status = status; 1180 1181 DTRACE_NFSV4_2(op__secinfo__no__name__done, 1182 struct compound_state *, cs, 1183 SECINFO_NO_NAME4res *, resp); 1184 } 1185 1186 /* 1187 * Used to free a stateid that no longer has any associated locks. 1188 * If there are valid locks, error NFS4ERR_LOCKS_HELD is returned. 1189 * NB: Actual freeing of stateid will be taken care by reaper_thread(). 1190 */ 1191 void 1192 rfs4x_op_free_stateid(nfs_argop4 *argop, nfs_resop4 *resop, 1193 struct svc_req *req, compound_state_t *cs) 1194 { 1195 FREE_STATEID4args *args = &argop->nfs_argop4_u.opfree_stateid; 1196 FREE_STATEID4res *resp = &resop->nfs_resop4_u.opfree_stateid; 1197 nfsstat4 status = NFS4ERR_BAD_STATEID; 1198 stateid4 *sid; 1199 stateid_t *id; 1200 1201 DTRACE_NFSV4_2(op__free__stateid__start, 1202 struct compound_state *, cs, 1203 FREE_STATEID4args *, args); 1204 1205 /* Fetch the ARG stateid */ 1206 sid = &args->fsa_stateid; 1207 get_stateid4(cs, sid); 1208 1209 id = (stateid_t *)sid; 1210 switch (id->bits.type) { 1211 case OPENID: { 1212 rfs4_state_t *sp; 1213 1214 status = rfs4_get_state_nolock(sid, &sp, RFS4_DBS_VALID); 1215 if (status != NFS4_OK) 1216 goto final; 1217 1218 rfs4_update_lease(sp->rs_owner->ro_client); 1219 rfs4_state_rele_nounlock(sp); 1220 status = NFS4ERR_LOCKS_HELD; 1221 break; 1222 } 1223 1224 case LOCKID: { 1225 sysid_t sysid; 1226 rfs4_lo_state_t *lsp; 1227 rfs4_lockowner_t *lo; 1228 1229 status = rfs4_get_lo_state(sid, &lsp, FALSE); 1230 if (status != NFS4_OK) 1231 goto final; 1232 1233 lo = lsp->rls_locker; 1234 rfs4_update_lease(lo->rl_client); 1235 1236 rfs4_dbe_lock(lo->rl_client->rc_dbe); 1237 sysid = lo->rl_client->rc_sysidt; 1238 rfs4_dbe_unlock(lo->rl_client->rc_dbe); 1239 1240 /* 1241 * Check for ACTIVE LOCKS by this lockowner. 1242 */ 1243 if (sysid != LM_NOSYSID) { 1244 locklist_t *llist; 1245 1246 llist = flk_get_active_locks(sysid, lo->rl_pid); 1247 if (llist != NULL) { 1248 flk_free_locklist(llist); 1249 status = NFS4ERR_LOCKS_HELD; 1250 } 1251 } 1252 1253 1254 /* 1255 * If the state does not have any active LOCKS, 1256 * invalidate the LOCK stateid right away. 1257 */ 1258 if (status != NFS4ERR_LOCKS_HELD) { 1259 rfs4_dbe_lock(lsp->rls_dbe); 1260 rfs4_dbe_invalidate(lsp->rls_dbe); 1261 rfs4_dbe_unlock(lsp->rls_dbe); 1262 } 1263 1264 rfs4_lo_state_rele(lsp, FALSE); 1265 break; 1266 } 1267 1268 case DELEGID: { 1269 rfs4_deleg_state_t *dsp; 1270 1271 status = rfs4_get_deleg_state(sid, &dsp); 1272 if (status != NFS4_OK) 1273 goto final; 1274 1275 rfs4_update_lease(dsp->rds_client); 1276 rfs4_deleg_state_rele(dsp); 1277 status = NFS4ERR_LOCKS_HELD; 1278 break; 1279 } 1280 1281 default: 1282 status = NFS4ERR_BAD_STATEID; 1283 break; 1284 } 1285 1286 final: 1287 *cs->statusp = resp->fsr_status = status; 1288 1289 DTRACE_NFSV4_2(op__free__stateid__done, 1290 struct compound_state *, cs, 1291 FREE_STATEID4res *, resp); 1292 } 1293