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