1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2017 RackTop Systems.
14 */
15
16 #include <sys/systm.h>
17 #include <sys/sdt.h>
18 #include <rpc/types.h>
19 #include <rpc/auth.h>
20 #include <rpc/auth_unix.h>
21 #include <rpc/auth_des.h>
22 #include <rpc/svc.h>
23 #include <rpc/xdr.h>
24 #include <nfs/nfs4.h>
25 #include <nfs/nfs_dispatch.h>
26 #include <sys/cmn_err.h>
27 #include <sys/modctl.h>
28
29 static void
rfs4_err_resp(COMPOUND4args * args,COMPOUND4res * resp,nfsstat4 err)30 rfs4_err_resp(COMPOUND4args *args, COMPOUND4res *resp, nfsstat4 err)
31 {
32 size_t sz;
33
34 resp->array_len = 1;
35 sz = resp->array_len * sizeof (nfs_resop4);
36 resp->array = kmem_zalloc(sz, KM_SLEEP);
37
38 resp->array[0].resop = args->array[0].argop;
39 resp->status = resp->array[0].nfs_resop4_u.opillegal.status = err;
40 }
41
42 /*
43 * The function checks if given compound operation is allowed
44 * to be the very fist operation in compound array.
45 */
46 static bool_t
valid_first_compound_op(nfs_opnum4 op)47 valid_first_compound_op(nfs_opnum4 op)
48 {
49 if (op == OP_BIND_CONN_TO_SESSION ||
50 op == OP_SEQUENCE ||
51 op == OP_EXCHANGE_ID ||
52 op == OP_CREATE_SESSION ||
53 op == OP_DESTROY_SESSION ||
54 op == OP_DESTROY_CLIENTID ||
55 op == OP_ILLEGAL)
56 return (TRUE);
57
58 return (FALSE);
59 }
60
61 /*
62 * The function verifies arguments passed to mds_op_compound.
63 * If agrguments are valid, NFS4_OK is returned, otherwise
64 * function returns correspoinding NFS4 error code.
65 */
66 static nfsstat4
verify_compound_args(COMPOUND4args * args)67 verify_compound_args(COMPOUND4args *args)
68 {
69 if (args->array_len == 0)
70 return (NFS4_OK);
71
72 if (!valid_first_compound_op(args->array[0].argop))
73 return (NFS4ERR_OP_NOT_IN_SESSION);
74
75 if (args->array_len > 1 && args->array[0].argop != OP_SEQUENCE) {
76 /*
77 * Compound is outside the session. There must be
78 * only one operation in request.
79 */
80 return (NFS4ERR_NOT_ONLY_OP);
81 }
82
83 return (NFS4_OK);
84 }
85
86 static void
rfs4x_dispatch_done(compound_state_t * cs)87 rfs4x_dispatch_done(compound_state_t *cs)
88 {
89 if (cs->slot)
90 rfs4x_sequence_done(cs->cmpresp, cs);
91 else {
92 rfs4_compound_free(cs->cmpresp);
93 }
94 cs->cs_flags |= RFS4_DISPATCH_DONE;
95 }
96
97 static bool_t
xdr_compound_wrapper(XDR * xdrs,compound_state_t * cs)98 xdr_compound_wrapper(XDR *xdrs, compound_state_t *cs)
99 {
100 COMPOUND4res *resp = cs->cmpresp;
101 bool_t res = FALSE;
102 bool_t isreal = (xdrs->x_handy != 0); /* real data encoding ? */
103
104 if (!(cs->cs_flags & RFS4_DISPATCH_DONE)) {
105 res = xdr_COMPOUND4res_srv(xdrs, resp);
106 if (isreal)
107 rfs4x_dispatch_done(cs);
108 }
109
110 return (res);
111 }
112
113 int
rfs4x_dispatch(struct svc_req * req,SVCXPRT * xprt,char * ap)114 rfs4x_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap)
115 {
116 struct compound_state cs;
117 COMPOUND4res res_buf;
118 COMPOUND4res *rbp;
119 COMPOUND4args *cap;
120 int rpcerr = 0;
121 nfsstat4 error;
122
123 bzero(&res_buf, sizeof (COMPOUND4res));
124 rbp = &res_buf;
125 cap = (COMPOUND4args *)ap;
126 rfs4_init_compound_state(&cs);
127
128 cs.statusp = &error;
129 cs.cmpresp = rbp;
130
131 error = verify_compound_args(cap);
132 if (error != NFS4_OK) {
133 rfs4_err_resp(cap, rbp, error);
134 goto out_send;
135 }
136
137 error = rfs4x_sequence_prep(cap, rbp, &cs);
138 if (error != NFS4_OK) {
139 if (error != nfserr_replay_cache)
140 rfs4_err_resp(cap, rbp, error);
141 goto out_send;
142 }
143
144 /* Regular processing */
145 curthread->t_flag |= T_DONTPEND;
146 rfs4_compound(cap, rbp, &cs, req, &rpcerr);
147 curthread->t_flag &= ~T_DONTPEND;
148
149 /*
150 * On RPC error, short sendreply
151 */
152 if (rpcerr) {
153 goto out_free;
154 }
155
156 if (curthread->t_flag & T_WOULDBLOCK) {
157 curthread->t_flag &= ~T_WOULDBLOCK;
158 error = 1;
159 goto out_free;
160 }
161
162 out_send:
163 if (!svc_sendreply(xprt, xdr_compound_wrapper, (char *)&cs)) {
164 DTRACE_PROBE2(sendfail, SVCXPRT *, xprt,
165 compound_state_t *, &cs);
166 svcerr_systemerr(xprt);
167 rpcerr = 1;
168 }
169
170 out_free:
171 if (!(cs.cs_flags & RFS4_DISPATCH_DONE)) {
172 rfs4x_dispatch_done(&cs);
173 }
174
175 rfs4_fini_compound_state(&cs);
176 return ((error != NFS4_OK || rpcerr) ? 1 : 0);
177 }
178