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
rfs4_cmp_cred_set(cred_set_t * p,struct compound_state * cs)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
rfs4_dup_princ(rpc_gss_principal_t ppl)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
rfs4_set_cred_set(cred_set_t * p,struct compound_state * cs)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
rfs4_free_cred_set(cred_set_t * p)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
nfs_clid4_cmp(nfs_client_id4 * s1,nfs_client_id4 * s2)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
rfs4x_get_server_impl_id(EXCHANGE_ID4resok * resp)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
rfs4x_set_trunkinfo(EXCHANGE_ID4resok * rok)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
client_has_state_locked(rfs4_client_t * cp)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
rfs4x_op_exchange_id(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_exchange_id_free(nfs_resop4 * resop)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
rfs4x_op_create_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_op_destroy_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_find_session(SEQUENCE4args * sargs,struct compound_state * cs)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
check_slot_seqid(rfs4_slot_t * slot,sequenceid4 seqid)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
rfs4x_sequence_prep(COMPOUND4args * args,COMPOUND4res * resp,compound_state_t * cs)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
rfs4x_sequence_done(COMPOUND4res * resp,compound_state_t * cs)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
rfs4x_op_sequence(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_op_reclaim_complete(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_op_destroy_clientid(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_op_bind_conn_to_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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
rfs4x_op_secinfo_noname(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)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