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