xref: /reactos/dll/3rdparty/libtirpc/src/auth_sspi.c (revision c2c66aff)
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 <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <rpc/types.h>
29 #include <rpc/xdr.h>
30 #include <rpc/auth.h>
31 #include <rpc/auth_sspi.h>
32 #include <rpc/clnt.h>
33 
34 static void authsspi_nextverf(AUTH *auth);
35 static bool_t authsspi_marshal(AUTH *auth, XDR *xdrs, u_int *seq);
36 static bool_t authsspi_refresh(AUTH *auth, void *);
37 static bool_t authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq);
38 static void	authsspi_destroy(AUTH *auth);
39 static void	authsspi_destroy_context(AUTH *auth);
40 static bool_t authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr);
41 static bool_t authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq);
42 
43 static struct auth_ops authsspi_ops = {
44 	authsspi_nextverf,
45 	authsspi_marshal,
46 	authsspi_validate,
47 	authsspi_refresh,
48 	authsspi_destroy,
49 	authsspi_wrap,
50 	authsspi_unwrap
51 };
52 
53 struct rpc_sspi_data {
54 	bool_t              established;	/* context established */
55     bool_t              inprogress;
56 	sspi_buffer_desc    gc_wire_verf;	/* save GSS_S_COMPLETE NULL RPC verfier
57                                          * to process at end of context negotiation*/
58 	CLIENT              *clnt;		    /* client handle */
59 	sspi_name_t         name;		    /* service name */
60 	struct rpc_sspi_sec *sec;		    /* security tuple */
61     CtxtHandle          ctx;            /* context id */
62 	struct rpc_sspi_cred gc;		    /* client credentials */
63 	u_int               win;		    /* sequence window */
64     TimeStamp           expiry;
65 };
66 
67 #define	AUTH_PRIVATE(auth)	((struct rpc_sspi_data *)auth->ah_private)
68 
69 static struct timeval AUTH_TIMEOUT = { 25, 0 };
70 void print_rpc_gss_sec(struct rpc_sspi_sec *ptr);
71 void print_negotiated_attrs(PCtxtHandle ctx);
72 
73 AUTH *
authsspi_create(CLIENT * clnt,sspi_name_t name,struct rpc_sspi_sec * sec)74 authsspi_create(CLIENT *clnt, sspi_name_t name, struct rpc_sspi_sec *sec)
75 {
76 	AUTH *auth, *save_auth;
77 	struct rpc_sspi_data *gd;
78 
79 	log_debug("in authgss_create()");
80 
81 	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
82 
83 	if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
84 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
85 		rpc_createerr.cf_error.re_errno = ENOMEM;
86 		return (NULL);
87 	}
88 	if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
89 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
90 		rpc_createerr.cf_error.re_errno = ENOMEM;
91 		free(auth);
92 		return (NULL);
93 	}
94 
95 #if 0
96 	if (name != SSPI_C_NO_NAME) {
97 		if (gss_duplicate_name(&min_stat, name, &gd->name)
98 						!= GSS_S_COMPLETE) {
99 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
100 			rpc_createerr.cf_error.re_errno = ENOMEM;
101 			free(auth);
102 			return (NULL);
103 		}
104 	}
105 	else
106 #else
107     gd->name = strdup(name);
108 #endif
109 
110 	gd->clnt = clnt;
111 	SecInvalidateHandle(&gd->ctx);
112 	gd->sec = sec;
113 
114 	gd->gc.gc_v = RPCSEC_SSPI_VERSION;
115 	gd->gc.gc_proc = RPCSEC_SSPI_INIT;
116 	gd->gc.gc_svc = gd->sec->svc;
117 
118 	auth->ah_ops = &authsspi_ops;
119 	auth->ah_private = (caddr_t)gd;
120 
121 	save_auth = clnt->cl_auth;
122 	clnt->cl_auth = auth;
123 
124 	if (!authsspi_refresh(auth, NULL))
125 		auth = NULL;
126 
127 	clnt->cl_auth = save_auth;
128 
129 	return (auth);
130 }
131 
132 AUTH *
authsspi_create_default(CLIENT * clnt,char * service,int svc)133 authsspi_create_default(CLIENT *clnt, char *service, int svc)
134 {
135 	AUTH *auth = NULL;
136 	uint32_t maj_stat = 0;
137 	sspi_buffer_desc sname;
138     sspi_name_t name = SSPI_C_NO_NAME;
139     unsigned char sec_pkg_name[] = "Kerberos";
140     struct rpc_sspi_sec *sec;
141 
142 	log_debug("in authgss_create_default() for %s", service);
143 
144 	sname.value = service;
145 	sname.length = (int)strlen(service);
146 #if 0
147 	maj_stat = gss_import_name(&min_stat, &sname,
148 		(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
149 		&name);
150 #else
151     maj_stat = sspi_import_name(&sname, &name);
152 #endif
153 	if (maj_stat != SEC_E_OK) {
154 		log_debug("authgss_create_default: sspi_import_name failed with %x", maj_stat);
155 		return (NULL);
156 	}
157     sec = calloc(1, sizeof(struct rpc_sspi_sec));
158     if (sec == NULL)
159         goto out_err;
160     sec->svc = svc;
161     // Let's acquire creds here for now
162     maj_stat = AcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_BOTH,
163         NULL, NULL, NULL, NULL, &sec->cred, &sec->expiry);
164     if (maj_stat != SEC_E_OK) {
165         log_debug("authgss_create_default: AcquireCredentialsHandleA failed with %x", maj_stat);
166         free(sec);
167         goto out;
168     }
169 
170 	auth = authsspi_create(clnt, name, sec);
171     if (auth == NULL)
172         goto out_free_sec;
173 
174 out:
175 	if (name != SSPI_C_NO_NAME) {
176 #if 0
177  		gss_release_name(&min_stat, &name);
178 #else
179         free(name);
180 #endif
181 	}
182 
183 	return (auth);
184 out_free_sec:
185     if (rpc_createerr.cf_error.re_errno == ENOMEM) {
186         FreeCredentialsHandle(&sec->cred);
187         free(sec);
188     }
189 out_err:
190     rpc_createerr.cf_stat = RPC_SYSTEMERROR;
191 	rpc_createerr.cf_error.re_errno = ENOMEM;
192     goto out;
193 }
194 
195 static void
authsspi_nextverf(AUTH * auth)196 authsspi_nextverf(AUTH *auth)
197 {
198 	log_debug("in authgss_nextverf()");
199 	/* no action necessary */
200 }
201 
202 static bool_t
authsspi_marshal(AUTH * auth,XDR * xdrs,u_int * seq)203 authsspi_marshal(AUTH *auth, XDR *xdrs, u_int *seq)
204 {
205 	XDR tmpxdrs;
206 	char tmp[MAX_AUTH_BYTES];
207 	struct rpc_sspi_data *gd;
208 	sspi_buffer_desc rpcbuf, checksum;
209 	uint32_t maj_stat;
210 	bool_t xdr_stat;
211 
212     log_debug("in authgss_marshal()");
213 
214 	gd = AUTH_PRIVATE(auth);
215 
216 	if (gd->established) {
217 		gd->gc.gc_seq++;
218         *seq = gd->gc.gc_seq;
219     }
220 
221 	xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE);
222 
223 	if (!xdr_rpc_sspi_cred(&tmpxdrs, &gd->gc)) {
224         log_debug("authsspi_marshal: xdr_rpc_sspi_cred failed");
225 		XDR_DESTROY(&tmpxdrs);
226 		return (FALSE);
227 	}
228 	auth->ah_cred.oa_flavor = RPCSEC_GSS;
229 	auth->ah_cred.oa_base = tmp;
230 	auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs);
231 
232 	XDR_DESTROY(&tmpxdrs);
233 
234 	if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) {
235         log_debug("authsspi_marshal: failed to xdr GSS CRED");
236 		return (FALSE);
237     }
238 	if (gd->gc.gc_proc == RPCSEC_SSPI_INIT ||
239 	    gd->gc.gc_proc == RPCSEC_SSPI_CONTINUE_INIT) {
240 		return (xdr_opaque_auth(xdrs, &_null_auth));
241 	}
242 	/* Checksum serialized RPC header, up to and including credential. */
243 	rpcbuf.length = XDR_GETPOS(xdrs) - 4;
244 	//XDR_SETPOS(xdrs, 0);
245 	//rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length);
246 	rpcbuf.value = xdrrec_getoutbase(xdrs) + 1;
247 
248 #if 0
249 	maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
250 			    &rpcbuf, &checksum);
251 #else
252     maj_stat = sspi_get_mic(&gd->ctx, 0, gd->gc.gc_seq, &rpcbuf, &checksum);
253 #endif
254 	if (maj_stat != SEC_E_OK) {
255 		log_debug("authsspi_marshal: sspi_get_mic failed with %x", maj_stat);
256 		if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
257 			gd->established = FALSE;
258 			authsspi_destroy_context(auth);
259 		}
260 		return (FALSE);
261 	}
262 	auth->ah_verf.oa_flavor = RPCSEC_GSS;
263 	auth->ah_verf.oa_base = checksum.value;
264 	auth->ah_verf.oa_length = checksum.length;
265 	xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf);
266 #if 0
267 	gss_release_buffer(&min_stat, &checksum);
268 #else
269     sspi_release_buffer(&checksum);
270 #endif
271 	return (xdr_stat);
272 }
273 
274 static bool_t
authsspi_validate(AUTH * auth,struct opaque_auth * verf,u_int seq)275 authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq)
276 {
277 	struct rpc_sspi_data *gd;
278 	u_int num, qop_state, cur_seq;
279 	sspi_buffer_desc signbuf, checksum;
280 	uint32_t maj_stat;
281 
282 	log_debug("in authgss_validate(for seq=%d)", seq);
283 
284 	gd = AUTH_PRIVATE(auth);
285 
286 	if (gd->established == FALSE) {
287 		/* would like to do this only on NULL rpc --
288 		 * gc->established is good enough.
289 		 * save the on the wire verifier to validate last
290 		 * INIT phase packet after decode if the major
291 		 * status is GSS_S_COMPLETE
292 		 */
293 		if ((gd->gc_wire_verf.value =
294 				mem_alloc(verf->oa_length)) == NULL) {
295 			return (FALSE);
296 		}
297 		memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length);
298 		gd->gc_wire_verf.length = verf->oa_length;
299 		return (TRUE);
300   	}
301 
302     if (gd->gc.gc_proc == RPCSEC_SSPI_DESTROY)
303         return TRUE;
304 
305 	if (gd->gc.gc_proc == RPCSEC_SSPI_INIT ||
306 	        gd->gc.gc_proc == RPCSEC_SSPI_CONTINUE_INIT) {
307 		num = htonl(gd->win);
308 	}
309 	else {
310         if (seq == -1) {
311             num = htonl(gd->gc.gc_seq);
312             cur_seq = gd->gc.gc_seq;
313         }
314 	    else {
315             num = htonl(seq);
316             cur_seq = seq;
317         }
318     }
319 
320 	signbuf.value = &num;
321 	signbuf.length = sizeof(num);
322 
323 	checksum.value = verf->oa_base;
324 	checksum.length = verf->oa_length;
325 #if 0
326 	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf,
327 				  &checksum, &qop_state);
328 #else
329     maj_stat = sspi_verify_mic(&gd->ctx, cur_seq, &signbuf, &checksum, &qop_state);
330 #endif
331 	if (maj_stat != SEC_E_OK) {
332 		log_debug("authsspi_validate: VerifySignature failed with %x", maj_stat);
333 		if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
334 			gd->established = FALSE;
335 			authsspi_destroy_context(auth);
336 		}
337 		return (FALSE);
338 	}
339 	return (TRUE);
340 }
341 
342 static bool_t
authsspi_refresh(AUTH * auth,void * tmp)343 authsspi_refresh(AUTH *auth, void *tmp)
344 {
345 	struct rpc_sspi_data *gd;
346 	struct rpc_sspi_init_res gr;
347     sspi_buffer_desc *recv_tokenp, send_token;
348 	uint32_t maj_stat, call_stat, ret_flags, i;
349     unsigned long flags =
350         ISC_REQ_MUTUAL_AUTH|ISC_REQ_INTEGRITY|ISC_REQ_ALLOCATE_MEMORY;
351     SecBufferDesc out_desc, in_desc;
352     SecBuffer wtkn[1], rtkn[1];
353 
354     log_debug("in authgss_refresh()");
355 
356 	gd = AUTH_PRIVATE(auth);
357 
358 	if ((gd->established && tmp == NULL) || gd->inprogress)
359 		return (TRUE);
360     else if (tmp) {
361         log_debug("trying to refresh credentials\n");
362         DeleteSecurityContext(&gd->ctx);
363         sspi_release_buffer(&gd->gc.gc_ctx);
364         SecInvalidateHandle(&gd->ctx);
365         mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length);
366         gd->gc_wire_verf.value = NULL;
367         gd->gc_wire_verf.length = 0;
368         gd->established = FALSE;
369         gd->gc.gc_proc = RPCSEC_SSPI_INIT;
370     }
371 
372 	/* GSS context establishment loop. */
373 	memset(&gr, 0, sizeof(gr));
374 	recv_tokenp = SSPI_C_NO_BUFFER;
375     send_token.length = 0;
376     send_token.value = NULL;
377 
378 	print_rpc_gss_sec(gd->sec);
379 
380     if (gd->sec->svc == RPCSEC_SSPI_SVC_PRIVACY)
381         flags |= ISC_REQ_CONFIDENTIALITY;
382 
383     for (i=0;;i++) {
384 		/* print the token we just received */
385 		if (recv_tokenp != SSPI_C_NO_BUFFER) {
386 			log_debug("The token we just received (length %d):",
387 				  recv_tokenp->length);
388 			log_hexdump(0, "", recv_tokenp->value, recv_tokenp->length, 0);
389 		}
390 #if 0
391 		maj_stat = gss_init_sec_context(&min_stat,
392 						gd->sec.cred,
393 						&gd->ctx,
394 						gd->name,
395 						gd->sec.mech,
396 						gd->sec.req_flags,
397 						0,		/* time req */
398 						NULL,		/* channel */
399 						recv_tokenp,
400 						NULL,		/* used mech */
401 						&send_token,
402 						&ret_flags,
403 						NULL);		/* time rec */
404 #else
405         gd->inprogress = TRUE;
406         out_desc.cBuffers = 1;
407         out_desc.pBuffers = wtkn;
408         out_desc.ulVersion = SECBUFFER_VERSION;
409         wtkn[0].BufferType = SECBUFFER_TOKEN;
410         wtkn[0].cbBuffer = send_token.length;
411         wtkn[0].pvBuffer = send_token.value;
412         log_debug("calling InitializeSecurityContextA for %s", gd->name);
413 
414         maj_stat = InitializeSecurityContextA(
415                         &gd->sec->cred,
416                         ((i==0)?NULL:&gd->ctx),
417                         gd->name,
418                         flags,
419                         0,
420                         SECURITY_NATIVE_DREP,
421                         ((i==0)?NULL:&in_desc),
422                         0,
423                         &gd->ctx,
424                         &out_desc,
425                         &ret_flags,
426                         &gd->expiry);
427 #endif
428 		if (recv_tokenp != SSPI_C_NO_BUFFER) {
429 #if 0
430 			gss_release_buffer(&min_stat, &gr.gr_token);
431 #else
432             sspi_release_buffer(&gr.gr_token);
433 #endif
434 			recv_tokenp = SSPI_C_NO_BUFFER;
435 		}
436 		if (maj_stat != SEC_E_OK && maj_stat != SEC_I_CONTINUE_NEEDED) {
437 			log_debug("InitializeSecurityContext failed with %x", maj_stat);
438 			break;
439 		}
440         send_token.length = wtkn[0].cbBuffer;
441         send_token.value = wtkn[0].pvBuffer;
442 		if (send_token.length != 0) {
443 			memset(&gr, 0, sizeof(gr));
444 
445 			/* print the token we are about to send */
446 			log_debug("The token being sent (length %d):",
447 				  send_token.length);
448 			log_hexdump(0, "", send_token.value, send_token.length, 0);
449 
450 			call_stat = clnt_call(gd->clnt, NULLPROC,
451 					      (xdrproc_t)xdr_rpc_sspi_init_args,
452 					      &send_token,
453 					      (xdrproc_t)xdr_rpc_sspi_init_res,
454 					      (caddr_t)&gr, AUTH_TIMEOUT);
455 #if 0
456 			gss_release_buffer(&min_stat, &send_token);
457 #else
458             // 11/29/2010 [aglo] can't call sspi_relase_buffer, causes heap
459             // corruption (later) to try and free the buffer directly.
460             FreeContextBuffer(send_token.value);
461 #endif
462 			if (call_stat != RPC_SUCCESS ||
463 			    (gr.gr_major != SEC_E_OK &&
464 			     gr.gr_major != SEC_I_CONTINUE_NEEDED))
465 				break;
466 
467 			if (gr.gr_ctx.length != 0) {
468 #if 0
469 				if (gd->gc.gc_ctx.value)
470 					gss_release_buffer(&min_stat,
471 							   &gd->gc.gc_ctx);
472 #else
473                 sspi_release_buffer(&gd->gc.gc_ctx);
474 #endif
475 				gd->gc.gc_ctx = gr.gr_ctx;
476 			}
477 			if (gr.gr_token.length != 0) {
478 				if (maj_stat != SEC_I_CONTINUE_NEEDED)
479 					break;
480 				recv_tokenp = &gr.gr_token;
481                 in_desc.cBuffers = 1;
482                 in_desc.pBuffers = rtkn;
483                 in_desc.ulVersion = SECBUFFER_VERSION;
484                 rtkn[0].BufferType = SECBUFFER_TOKEN;
485                 rtkn[0].cbBuffer = gr.gr_token.length;
486                 rtkn[0].pvBuffer = gr.gr_token.value;
487 			}
488 			gd->gc.gc_proc = RPCSEC_SSPI_CONTINUE_INIT;
489 		}
490 
491 		/* GSS_S_COMPLETE => check gss header verifier,
492 		 * usually checked in gss_validate
493 		 */
494 		if (maj_stat == SEC_E_OK) {
495 			sspi_buffer_desc bufin;
496 			u_int seq, qop_state = 0;
497 
498             print_negotiated_attrs(&gd->ctx);
499 
500 			seq = htonl(gr.gr_win);
501 			bufin.value = (unsigned char *)&seq;
502 			bufin.length = sizeof(seq);
503 #if 0
504 			maj_stat = gss_verify_mic(&min_stat, gd->ctx,
505 				&bufin, &bufout, &qop_state);
506 #else
507             maj_stat = sspi_verify_mic(&gd->ctx, 0, &bufin, &gd->gc_wire_verf, &qop_state);
508 #endif
509 			if (maj_stat != SEC_E_OK) {
510 				log_debug("authgss_refresh: sspi_verify_mic failed with %x", maj_stat);
511 				if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
512 					gd->established = FALSE;
513 					authsspi_destroy_context(auth);
514 				}
515 				break;
516 			}
517 			gd->established = TRUE;
518             gd->inprogress = FALSE;
519 			gd->gc.gc_proc = RPCSEC_SSPI_DATA;
520 			gd->gc.gc_seq = 0;
521 			gd->win = gr.gr_win;
522             log_debug("authgss_refresh: established GSS context");
523 			break;
524 		}
525 	}
526 	/* End context negotiation loop. */
527 	if (gd->gc.gc_proc != RPCSEC_SSPI_DATA) {
528 		if (gr.gr_token.length != 0)
529 #if 0
530 			gss_release_buffer(&min_stat, &gr.gr_token);
531 #else
532             sspi_release_buffer(&gr.gr_token);
533 #endif
534 		authsspi_destroy(auth);
535 		auth = NULL;
536 		rpc_createerr.cf_stat = RPC_AUTHERROR;
537 
538 		return (FALSE);
539 	}
540 	return (TRUE);
541 }
542 
543 bool_t
authsspi_service(AUTH * auth,int svc)544 authsspi_service(AUTH *auth, int svc)
545 {
546 	struct rpc_sspi_data	*gd;
547 
548 	log_debug("in authgss_service()");
549 
550 	if (!auth)
551         return(FALSE);
552 	gd = AUTH_PRIVATE(auth);
553 	if (!gd || !gd->established)
554 		return (FALSE);
555 	gd->sec->svc = svc;
556 	gd->gc.gc_svc = svc;
557 	return (TRUE);
558 }
559 
560 static void
authsspi_destroy_context(AUTH * auth)561 authsspi_destroy_context(AUTH *auth)
562 {
563 	struct rpc_sspi_data *gd;
564 
565 	log_debug("in authgss_destroy_context()");
566 
567 	gd = AUTH_PRIVATE(auth);
568     if (gd == NULL) return;
569 
570 	if (SecIsValidHandle(&gd->ctx)) {
571 		if (gd->established) {
572 			gd->gc.gc_proc = RPCSEC_SSPI_DESTROY;
573 			clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL,
574 				  (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
575             DeleteSecurityContext(&gd->ctx);
576 		}
577         sspi_release_buffer(&gd->gc.gc_ctx);
578         SecInvalidateHandle(&gd->ctx);
579 #if 0
580 		gss_release_buffer(&min_stat, &gd->gc.gc_ctx);
581 		/* XXX ANDROS check size of context  - should be 8 */
582 		memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx));
583 		gss_delete_sec_context(&min_stat, &gd->ctx, NULL);
584 #endif
585 	}
586 
587 	/* free saved wire verifier (if any) */
588 	mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length);
589 	gd->gc_wire_verf.value = NULL;
590 	gd->gc_wire_verf.length = 0;
591 
592 	gd->established = FALSE;
593 }
594 
595 static void
authsspi_destroy(AUTH * auth)596 authsspi_destroy(AUTH *auth)
597 {
598 	struct rpc_sspi_data *gd;
599 
600 	log_debug("in authgss_destroy()");
601 
602 	gd = AUTH_PRIVATE(auth);
603     if (gd == NULL) return;
604 
605 	authsspi_destroy_context(auth);
606 
607 #if 0
608     if (gd->name != SSPI_C_NO_NAME)
609 		gss_release_name(&min_stat, &gd->name);
610 #else
611     free(gd->name);
612 #endif
613     FreeCredentialsHandle(&gd->sec->cred);
614     free(gd->sec);
615 	free(gd);
616 	free(auth);
617 }
618 
619 bool_t
authsspi_wrap(AUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)620 authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
621 {
622 	struct rpc_sspi_data	*gd;
623 
624 	log_debug("in authgss_wrap()");
625 
626 	gd = AUTH_PRIVATE(auth);
627 
628 	if (!gd->established || gd->sec->svc == RPCSEC_SSPI_SVC_NONE) {
629 		return ((*xdr_func)(xdrs, xdr_ptr));
630 	}
631 	return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr,
632 				 &gd->ctx, gd->sec->qop,
633 				 gd->sec->svc, gd->gc.gc_seq));
634 }
635 
636 bool_t
authsspi_unwrap(AUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr,u_int seq)637 authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq)
638 {
639 	struct rpc_sspi_data	*gd;
640 
641 	log_debug("in authgss_unwrap()");
642 
643 	gd = AUTH_PRIVATE(auth);
644 
645 	if (!gd->established || gd->sec->svc == RPCSEC_SSPI_SVC_NONE) {
646 		return ((*xdr_func)(xdrs, xdr_ptr));
647 	}
648 	return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr,
649 				 &gd->ctx, gd->sec->qop,
650 				 gd->sec->svc, seq));
651 }
652 
653 #ifdef __REACTOS__
sspi_get_mic(void * dummy,u_int qop,u_int seq,sspi_buffer_desc * bufin,sspi_buffer_desc * bufout)654 uint32_t sspi_get_mic(void *dummy, u_int qop, u_int seq,
655                         sspi_buffer_desc *bufin, sspi_buffer_desc *bufout)
656 {
657     PCtxtHandle ctx = dummy;
658 #else
659 uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq,
660                         sspi_buffer_desc *bufin, sspi_buffer_desc *bufout)
661 {
662 #endif
663     uint32_t maj_stat;
664     SecPkgContext_Sizes ContextSizes;
665     SecBufferDesc desc;
666     SecBuffer sec_tkn[2];
667 
668     log_hexdump(0, "sspi_get_mic: calculating checksum of", bufin->value, bufin->length, 0);
669 
670     memset(&ContextSizes, 0, sizeof(ContextSizes));
671     maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_SIZES, &ContextSizes);
672     if (maj_stat != SEC_E_OK) return maj_stat;
673 
674     if (ContextSizes.cbMaxSignature == 0) return SEC_E_INTERNAL_ERROR;
675 
676     desc.cBuffers = 2;
677     desc.pBuffers = sec_tkn;
678     desc.ulVersion = SECBUFFER_VERSION;
679     sec_tkn[0].BufferType = SECBUFFER_DATA;
680     sec_tkn[0].cbBuffer = bufin->length;
681     sec_tkn[0].pvBuffer = bufin->value;
682     sec_tkn[1].BufferType = SECBUFFER_TOKEN;
683     sec_tkn[1].cbBuffer = ContextSizes.cbMaxSignature;
684     sec_tkn[1].pvBuffer = calloc(ContextSizes.cbMaxSignature, sizeof(char));
685     if (sec_tkn[1].pvBuffer == NULL) return SEC_E_INSUFFICIENT_MEMORY;
686 
687     maj_stat = MakeSignature(ctx, 0, &desc, seq);
688     if (maj_stat == SEC_E_OK) {
689         bufout->length = sec_tkn[1].cbBuffer;
690         bufout->value = sec_tkn[1].pvBuffer;
691         log_hexdump(0, "sspi_get_mic: verifier is", bufout->value, bufout->length, 0);
692     } else
693         free(sec_tkn[1].pvBuffer);
694 
695     return maj_stat;
696 }
697 
698 #ifndef __REACTOS__
699 uint32_t sspi_verify_mic(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin,
700                             sspi_buffer_desc *bufout, u_int *qop_state)
701 {
702 #else
703 uint32_t sspi_verify_mic(void *dummy, u_int seq, sspi_buffer_desc *bufin,
704                             sspi_buffer_desc *bufout, u_int *qop_state)
705 {
706     PCtxtHandle ctx = dummy;
707 #endif
708     SecBufferDesc desc;
709     SecBuffer sec_tkn[2];
710 
711     desc.cBuffers = 2;
712     desc.pBuffers = sec_tkn;
713     desc.ulVersion = SECBUFFER_VERSION;
714     sec_tkn[0].BufferType = SECBUFFER_DATA;
715     sec_tkn[0].cbBuffer = bufin->length;
716     sec_tkn[0].pvBuffer = bufin->value;
717     sec_tkn[1].BufferType = SECBUFFER_TOKEN;
718     sec_tkn[1].cbBuffer = bufout->length;
719     sec_tkn[1].pvBuffer = bufout->value;
720 
721     log_hexdump(0, "sspi_verify_mic: calculating checksum over", bufin->value, bufin->length, 0);
722     log_hexdump(0, "sspi_verify_mic: received checksum ", bufout->value, bufout->length, 0);
723 
724     return VerifySignature(ctx, &desc, seq, qop_state);
725 }
726 
727 void sspi_release_buffer(sspi_buffer_desc *buf)
728 {
729     if (buf->value)
730         free(buf->value);
731     buf->value = NULL;
732     buf->length = 0;
733 }
734 
735 uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out)
736 {
737     *name_out = calloc(name_in->length + 5, sizeof(char));
738     if (*name_out == NULL)
739         return SEC_E_INSUFFICIENT_MEMORY;
740 
741     strcpy(*name_out, "nfs/");
742     strncat(*name_out, name_in->value, name_in->length);
743 
744     log_debug("imported service name is: %s\n", *name_out);
745 
746     return SEC_E_OK;
747 }
748 
749 #ifndef __REACTOS__
750 uint32_t sspi_wrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin,
751                    sspi_buffer_desc *bufout, u_int *conf_state)
752 {
753 #else
754 uint32_t sspi_wrap(void *dummy, u_int seq, sspi_buffer_desc *bufin,
755                    sspi_buffer_desc *bufout, u_int *conf_state)
756 {
757     PCtxtHandle ctx = dummy;
758 #endif
759     uint32_t maj_stat;
760     SecBufferDesc BuffDesc;
761     SecBuffer SecBuff[3];
762     ULONG ulQop = 0;
763     SecPkgContext_Sizes ContextSizes;
764     PBYTE p;
765 
766     maj_stat = QueryContextAttributes(ctx, SECPKG_ATTR_SIZES,
767        &ContextSizes);
768     if (maj_stat != SEC_E_OK)
769         goto out;
770 
771     BuffDesc.ulVersion = 0;
772     BuffDesc.cBuffers = 3;
773     BuffDesc.pBuffers = SecBuff;
774 
775     SecBuff[0].cbBuffer = ContextSizes.cbSecurityTrailer;
776     SecBuff[0].BufferType = SECBUFFER_TOKEN;
777     SecBuff[0].pvBuffer = malloc(ContextSizes.cbSecurityTrailer);
778 
779     SecBuff[1].cbBuffer = bufin->length;
780     SecBuff[1].BufferType = SECBUFFER_DATA;
781     SecBuff[1].pvBuffer = bufin->value;
782     log_hexdump(0, "plaintext:", bufin->value, bufin->length, 0);
783 
784     SecBuff[2].cbBuffer = ContextSizes.cbBlockSize;
785     SecBuff[2].BufferType = SECBUFFER_PADDING;
786     SecBuff[2].pvBuffer = malloc(ContextSizes.cbBlockSize);
787 
788     maj_stat = EncryptMessage(ctx, ulQop, &BuffDesc, seq);
789     if (maj_stat != SEC_E_OK)
790         goto out_free;
791 
792     bufout->length = SecBuff[0].cbBuffer + SecBuff[1].cbBuffer + SecBuff[2].cbBuffer;
793     p = bufout->value = malloc(bufout->length);
794     memcpy(p, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer);
795     p += SecBuff[0].cbBuffer;
796     memcpy(p, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer);
797     p += SecBuff[1].cbBuffer;
798     memcpy(p, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer);
799 out_free:
800     free(SecBuff[0].pvBuffer);
801     free(SecBuff[2].pvBuffer);
802 
803     if (!maj_stat)
804         log_hexdump(0, "cipher:", bufout->value, bufout->length, 0);
805 out:
806     return maj_stat;
807 }
808 
809 #ifndef __REACTOS__
810 uint32_t sspi_unwrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin,
811                      sspi_buffer_desc *bufout, u_int *conf_state,
812                      u_int *qop_state)
813 {
814 #else
815 uint32_t sspi_unwrap(void *dummy, u_int seq, sspi_buffer_desc *bufin,
816                      sspi_buffer_desc *bufout, u_int *conf_state,
817                      u_int *qop_state)
818 {
819     PCtxtHandle ctx = dummy;
820 #endif
821     uint32_t maj_stat;
822     SecBufferDesc BuffDesc;
823     SecBuffer SecBuff[2];
824     ULONG ulQop = 0;
825 
826     BuffDesc.ulVersion    = 0;
827     BuffDesc.cBuffers     = 2;
828     BuffDesc.pBuffers     = SecBuff;
829 
830     SecBuff[0].cbBuffer   = bufin->length;
831     SecBuff[0].BufferType = SECBUFFER_STREAM;
832     SecBuff[0].pvBuffer   = bufin->value;
833 
834     SecBuff[1].cbBuffer   = 0;
835     SecBuff[1].BufferType = SECBUFFER_DATA;
836     SecBuff[1].pvBuffer   = NULL;
837 
838     log_hexdump(0, "cipher:", bufin->value, bufin->length, 0);
839 
840     maj_stat = DecryptMessage(ctx, &BuffDesc, seq, &ulQop);
841     if (maj_stat != SEC_E_OK) return maj_stat;
842 
843     bufout->length = SecBuff[1].cbBuffer;
844     bufout->value = malloc(bufout->length);
845     memcpy(bufout->value, SecBuff[1].pvBuffer, bufout->length);
846 
847     log_hexdump(0, "data:", bufout->value, bufout->length, 0);
848 
849     *conf_state = 1;
850     *qop_state = 0;
851 
852     return SEC_E_OK;
853 }
854 
855 /* useful as i add more mechanisms */
856 #define DEBUG
857 #ifdef DEBUG
858 #define fd_out stdout
859 void print_rpc_gss_sec(struct rpc_sspi_sec *ptr)
860 {
861     int i;
862     char *p;
863 
864 	fprintf(fd_out, "rpc_gss_sec:");
865 	if(ptr->mech == NULL)
866 		fprintf(fd_out, "NULL gss_OID mech");
867 	else {
868 		fprintf(fd_out, "     mechanism_OID: {");
869 		p = (char *)ptr->mech->elements;
870 		for (i=0; i < ptr->mech->length; i++)
871 			/* First byte of OIDs encoded to save a byte */
872 			if (i == 0) {
873 				int first, second;
874 				if (*p < 40) {
875 					first = 0;
876 					second = *p;
877 				}
878 				else if (40 <= *p && *p < 80) {
879 					first = 1;
880 					second = *p - 40;
881 				}
882 				else if (80 <= *p && *p < 127) {
883 					first = 2;
884 					second = *p - 80;
885 				}
886 				else {
887 					/* Invalid value! */
888 					first = -1;
889 					second = -1;
890 				}
891 				fprintf(fd_out, " %u %u", first, second);
892 				p++;
893 			}
894 			else {
895 				fprintf(fd_out, " %u", (unsigned char)*p++);
896 			}
897 		fprintf(fd_out, " }\n");
898 	}
899 	fprintf(fd_out, "     qop: %d\n", ptr->qop);
900 	fprintf(fd_out, "     service: %d\n", ptr->svc);
901 	fprintf(fd_out, "     cred: %p\n", ptr->cred);
902 }
903 
904 void print_negotiated_attrs(PCtxtHandle ctx)
905 {
906     SecPkgContext_Sizes ContextSizes;
907     unsigned long  flags;
908     uint32_t maj_stat;
909 
910     maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_FLAGS, &flags);
911     if (maj_stat != SEC_E_OK) return;
912 
913     log_debug("negotiated flags %x\n", flags);
914     if (flags & ISC_REQ_DELEGATE) log_debug("ISC_REQ_DELEGATE");
915     if (flags & ISC_REQ_MUTUAL_AUTH) log_debug("ISC_REQ_MUTUAL_AUTH");
916     if (flags & ISC_REQ_REPLAY_DETECT) log_debug("ISC_REQ_REPLAY_DETECT");
917     if (flags & ISC_REQ_SEQUENCE_DETECT) log_debug("ISC_REQ_SEQUENCE_DETECT");
918     if (flags & ISC_REQ_CONFIDENTIALITY) log_debug("ISC_REQ_CONFIDENTIALITY");
919     if (flags & ISC_REQ_USE_SESSION_KEY) log_debug("ISC_REQ_USE_SESSION_KEY");
920     if (flags & ISC_REQ_PROMPT_FOR_CREDS) log_debug("ISC_REQ_PROMPT_FOR_CREDS");
921     if (flags & ISC_REQ_USE_SUPPLIED_CREDS) log_debug("ISC_REQ_USE_SUPPLIED_CREDS");
922     if (flags & ISC_REQ_ALLOCATE_MEMORY) log_debug("ISC_REQ_ALLOCATE_MEMORY");
923     if (flags & ISC_REQ_USE_DCE_STYLE) log_debug("ISC_REQ_USE_DCE_STYLE");
924     if (flags & ISC_REQ_DATAGRAM) log_debug("ISC_REQ_DATAGRAM");
925     if (flags & ISC_REQ_CONNECTION) log_debug("ISC_REQ_CONNECTION");
926     if (flags & ISC_REQ_CALL_LEVEL) log_debug("ISC_REQ_CALL_LEVEL");
927     if (flags & ISC_REQ_FRAGMENT_SUPPLIED) log_debug("ISC_REQ_FRAGMENT_SUPPLIED");
928     if (flags & ISC_REQ_EXTENDED_ERROR) log_debug("ISC_REQ_EXTENDED_ERROR");
929     if (flags & ISC_REQ_STREAM) log_debug("ISC_REQ_STREAM");
930     if (flags & ISC_REQ_INTEGRITY) log_debug("ISC_REQ_INTEGRITY");
931     if (flags & ISC_REQ_IDENTIFY) log_debug("ISC_REQ_IDENTIFY");
932     if (flags & ISC_REQ_NULL_SESSION) log_debug("ISC_REQ_NULL_SESSION");
933     if (flags & ISC_REQ_MANUAL_CRED_VALIDATION) log_debug("ISC_REQ_MANUAL_CRED_VALIDATION");
934 
935     maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_SIZES, &ContextSizes);
936     if (maj_stat != SEC_E_OK) return;
937 
938     log_debug("signature size is %d\n", ContextSizes.cbMaxSignature);
939 
940 }
941 
942 void log_hexdump(bool_t on, const u_char *title, const u_char *buf,
943                     int len, int offset)
944 {
945 	int i, j, jm, c;
946 
947     if (!on) return;
948 
949 	fprintf(fd_out, "%04x: %s (len=%d)\n", GetCurrentThreadId(), title, len);
950 	for (i = 0; i < len; i += 0x10) {
951 		fprintf(fd_out, "  %04x: ", (u_int)(i + offset));
952 		jm = len - i;
953 		jm = jm > 16 ? 16 : jm;
954 
955 		for (j = 0; j < jm; j++) {
956 			if ((j % 2) == 1)
957 				fprintf(fd_out, "%02x ", (u_int) buf[i+j]);
958 			else
959 				fprintf(fd_out, "%02x", (u_int) buf[i+j]);
960 		}
961 		for (; j < 16; j++) {
962 			if ((j % 2) == 1) fprintf(fd_out, "   ");
963 			else fprintf(fd_out, "  ");
964 		}
965 		fprintf(fd_out, " ");
966 
967 		for (j = 0; j < jm; j++) {
968 			c = buf[i+j];
969 			c = isprint(c) ? c : '.';
970 			fprintf(fd_out, "%c", c);
971 		}
972 		fprintf(fd_out, "\n");
973 	}
974     fflush(fd_out);
975 }
976 
977 void log_debug(const char *fmt, ...)
978 {
979 	va_list ap;
980 
981 	va_start(ap, fmt);
982 	fprintf(fd_out, "%04x: rpcsec_gss: ", GetCurrentThreadId());
983 	vfprintf(fd_out, fmt, ap);
984 	fprintf(fd_out, "\n");
985     fflush(fd_out);
986 	va_end(ap);
987 }
988 #else
989 void print_rpc_gss_sec(struct rpc_sspi_sec *ptr) { return; }
990 void print_negotiated_flags(unsigned long  flags) {return; }
991 void log_hexdump(bool_t on, const u_char *title, const u_char *buf,
992                     int len, int offset) { return; }
993 void log_debug(const char *fmt, ...) { return; }
994 #endif
995