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 = #
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