1 /* NFSv4.1 client for Windows
2  * Copyright � 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose.  See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #include <wintirpc.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 //#include <rpc/types.h>
27 #include <rpc/xdr.h>
28 #include <rpc/auth.h>
29 #include <rpc/auth_sspi.h>
30 #include <rpc/rpc.h>
31 #include <security.h>
32 
33 bool_t
34 xdr_rpc_sspi_cred(XDR *xdrs, struct rpc_sspi_cred *p)
35 {
36 	bool_t xdr_stat;
37 
38 	xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
39 		        xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
40 		        xdr_u_int(xdrs, &p->gc_seq) &&
41 		        xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
42 		        xdr_bytes(xdrs, (char **)&p->gc_ctx.value,
43                 (u_int *)&p->gc_ctx.length, MAX_AUTH_BYTES));
44 
45 	log_debug("xdr_rpc_gss_cred: %s %s "
46                 "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)",
47                 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
48                 (xdr_stat == TRUE) ? "success" : "failure",
49                 p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
50                 p->gc_ctx.value, p->gc_ctx.length);
51 
52 	return (xdr_stat);
53 }
54 
55 bool_t
56 xdr_rpc_sspi_init_args(XDR *xdrs, sspi_buffer_desc *p)
57 {
58 	bool_t xdr_stat;
59 
60 	xdr_stat = xdr_bytes(xdrs, (char **)&p->value,
61                         (u_int *)&p->length, (u_int)(-1));
62 
63 	log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)",
64                 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
65                 (xdr_stat == TRUE) ? "success" : "failure",
66                 p->value, p->length);
67 
68 	return (xdr_stat);
69 }
70 
71 bool_t
72 xdr_rpc_sspi_init_res(XDR *xdrs, struct rpc_sspi_init_res *p)
73 {
74 	bool_t xdr_stat;
75 
76 	xdr_stat = (xdr_bytes(xdrs, (char **)&p->gr_ctx.value,
77                 (u_int *)&p->gr_ctx.length, MAX_NETOBJ_SZ) &&
78                 xdr_u_int(xdrs, &p->gr_major) &&
79                 xdr_u_int(xdrs, &p->gr_minor) &&
80                 xdr_u_int(xdrs, &p->gr_win) &&
81                 xdr_bytes(xdrs, (char **)&p->gr_token.value,
82                 (u_int *)&p->gr_token.length, (u_int)(-1)));
83 
84 	log_debug("xdr_rpc_gss_init_res %s %s "
85                 "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)",
86                 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
87                 (xdr_stat == TRUE) ? "success" : "failure",
88                 p->gr_ctx.value, p->gr_ctx.length,
89                 p->gr_major, p->gr_minor, p->gr_win,
90                 p->gr_token.value, p->gr_token.length);
91 
92 	return (xdr_stat);
93 }
94 
95 bool_t
96 xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
97 		      PCtxtHandle ctx, sspi_qop_t qop,
98 		      rpc_sspi_svc_t svc, u_int seq)
99 {
100 	sspi_buffer_desc databuf, wrapbuf;
101 	uint32_t maj_stat;
102 	int start, end, conf_state;
103 	bool_t xdr_stat;
104 
105     log_debug("in xdr_rpc_sspi_wrap_data()");
106 
107     /* Skip databody length. */
108 	start = XDR_GETPOS(xdrs);
109 	XDR_SETPOS(xdrs, start + 4);
110 
111 	/* Marshal rpc_gss_data_t (sequence number + arguments). */
112 	if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
113 		return (FALSE);
114 	end = XDR_GETPOS(xdrs);
115 
116 	/* Set databuf to marshalled rpc_gss_data_t. */
117 	databuf.length = end - start - 4;
118 	XDR_SETPOS(xdrs, start + 4);
119 	databuf.value = XDR_INLINE(xdrs, databuf.length);
120 
121 	xdr_stat = FALSE;
122 
123 	if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
124 		/* Marshal databody_integ length. */
125 		XDR_SETPOS(xdrs, start);
126 		if (!xdr_u_int(xdrs, (u_int *)&databuf.length))
127 			return (FALSE);
128 
129 		/* Checksum rpc_gss_data_t. */
130 #if 0
131 		maj_stat = gss_get_mic(&min_stat, ctx, qop,
132 				       &databuf, &wrapbuf);
133 #else
134         maj_stat = sspi_get_mic(ctx, 0, seq, &databuf, &wrapbuf);
135 #endif
136 		if (maj_stat != SEC_E_OK) {
137 			log_debug("xdr_rpc_sspi_wrap_data: sspi_get_mic failed with %x", maj_stat);
138 			return (FALSE);
139 		}
140 		/* Marshal checksum. */
141 		XDR_SETPOS(xdrs, end);
142 		xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
143                             (u_int *)&wrapbuf.length, (u_int)-1);
144 #if 0
145 		gss_release_buffer(&min_stat, &wrapbuf);
146 #else
147         sspi_release_buffer(&wrapbuf);
148 #endif
149 	}
150 	else if (svc == RPCSEC_SSPI_SVC_PRIVACY) {
151 		/* Encrypt rpc_gss_data_t. */
152 #if 0
153 		maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
154 				    &conf_state, &wrapbuf);
155 #else
156         maj_stat = sspi_wrap(ctx, 0, &databuf, &wrapbuf, &conf_state);
157 #endif
158 		if (maj_stat != SEC_E_OK) {
159 			log_debug("xdr_rpc_sspi_wrap_data: sspi_wrap failed with %x", maj_stat);
160 			return (FALSE);
161 		}
162 		/* Marshal databody_priv. */
163 		XDR_SETPOS(xdrs, start);
164 		xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
165                             (u_int *)&wrapbuf.length, (u_int)-1);
166 #if 0
167 		gss_release_buffer(&min_stat, &wrapbuf);
168 #else
169         sspi_release_buffer(&wrapbuf);
170 #endif
171 	}
172 	return (xdr_stat);
173 }
174 
175 bool_t
176 xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
177 			PCtxtHandle ctx, sspi_qop_t qop,
178 			rpc_sspi_svc_t svc, u_int seq)
179 {
180 	XDR tmpxdrs;
181 	sspi_buffer_desc databuf, wrapbuf;
182 	uint32_t maj_stat;
183 	u_int seq_num, qop_state;
184 	int conf_state;
185 	bool_t xdr_stat;
186 
187     log_debug("in xdr_rpc_sspi_unwrap_data()");
188 
189 	if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
190 		return (TRUE);
191 
192 	memset(&databuf, 0, sizeof(databuf));
193 	memset(&wrapbuf, 0, sizeof(wrapbuf));
194 
195 	if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
196 		/* Decode databody_integ. */
197 		if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length,
198                         (u_int)-1)) {
199 			log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_integ failed");
200 			return (FALSE);
201 		}
202 		/* Decode checksum. */
203 		if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
204                         MAX_NETOBJ_SZ)) {
205 #if 0
206 			gss_release_buffer(&min_stat, &databuf);
207 #else
208             sspi_release_buffer(&databuf);
209 #endif
210 			log_debug("xdr_rpc_sspi_unwrap_data: xdr decode checksum failed");
211 			return (FALSE);
212 		}
213 		/* Verify checksum and QOP. */
214 #if 0
215 		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
216 					  &wrapbuf, &qop_state);
217 #else
218         maj_stat = sspi_verify_mic(ctx, seq, &databuf, &wrapbuf, &qop_state);
219 #endif
220 #if 0
221 		gss_release_buffer(&min_stat, &wrapbuf);
222 #else
223         sspi_release_buffer(&wrapbuf);
224 #endif
225 
226 		if (maj_stat != SEC_E_OK) {
227 #if 0
228 			gss_release_buffer(&min_stat, &databuf);
229 #else
230             sspi_release_buffer(&databuf);
231 #endif
232 			log_debug("xdr_rpc_sspi_unwrap_data: sspi_verify_mic "
233                         "failed with %x", maj_stat);
234 			return (FALSE);
235 		}
236 	}
237 	else if (svc == RPCSEC_SSPI_SVC_PRIVACY) {
238 		/* Decode databody_priv. */
239 		if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
240                         (u_int)-1)) {
241 			log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_priv failed");
242 			return (FALSE);
243 		}
244 		/* Decrypt databody. */
245 #if 0
246 		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
247 				      &conf_state, &qop_state);
248 #else
249         maj_stat = sspi_unwrap(ctx, seq, &wrapbuf, &databuf, &conf_state, &qop_state);
250 #endif
251 #if 0
252 		gss_release_buffer(&min_stat, &wrapbuf);
253 #else
254         sspi_release_buffer(&wrapbuf);
255 #endif
256 		/* Verify encryption and QOP. */
257 		if (maj_stat != SEC_E_OK) {
258 #if 0
259 			gss_release_buffer(&min_stat, &databuf);
260 #else
261             sspi_release_buffer(&databuf);
262 #endif
263 			log_debug("xdr_rpc_sspi_unwrap_data: sspi_unwrap failed with %x", maj_stat);
264 			return (FALSE);
265 		}
266 	}
267 	/* Decode rpc_gss_data_t (sequence number + arguments). */
268 	xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
269 	xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
270                 (*xdr_func)(&tmpxdrs, xdr_ptr));
271 	XDR_DESTROY(&tmpxdrs);
272 #if 0
273 	gss_release_buffer(&min_stat, &databuf);
274 #else
275     sspi_release_buffer(&databuf);
276 #endif
277 	/* Verify sequence number. */
278 	if (xdr_stat == TRUE && seq_num != seq) {
279 		log_debug("wrong sequence number in databody received %d expected %d",
280             seq_num, seq);
281 		return (FALSE);
282 	}
283 
284 	return (xdr_stat);
285 }
286 
287 bool_t
288 xdr_rpc_sspi_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
289 		 PCtxtHandle ctx, sspi_qop_t qop,
290 		 rpc_sspi_svc_t svc, u_int seq)
291 {
292 	switch (xdrs->x_op) {
293 
294 	case XDR_ENCODE:
295 		return (xdr_rpc_sspi_wrap_data(xdrs, xdr_func, xdr_ptr,
296                     ctx, qop, svc, seq));
297 	case XDR_DECODE:
298 		return (xdr_rpc_sspi_unwrap_data(xdrs, xdr_func, xdr_ptr,
299                     ctx, qop, svc, seq));
300 	case XDR_FREE:
301 		return (TRUE);
302 	}
303 	return (FALSE);
304 }
305