1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
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.
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.
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
28 #include <rpc/types.h>
31 #include <rpc/auth_sspi.h>
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
);
43 static struct auth_ops authsspi_ops
= {
53 struct rpc_sspi_data
{
54 bool_t established
; /* context established */
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 */
67 #define AUTH_PRIVATE(auth) ((struct rpc_sspi_data *)auth->ah_private)
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
);
74 authsspi_create(CLIENT
*clnt
, sspi_name_t name
, struct rpc_sspi_sec
*sec
)
76 AUTH
*auth
, *save_auth
;
77 struct rpc_sspi_data
*gd
;
79 log_debug("in authgss_create()");
81 memset(&rpc_createerr
, 0, sizeof(rpc_createerr
));
83 if ((auth
= calloc(sizeof(*auth
), 1)) == NULL
) {
84 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
85 rpc_createerr
.cf_error
.re_errno
= ENOMEM
;
88 if ((gd
= calloc(sizeof(*gd
), 1)) == NULL
) {
89 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
90 rpc_createerr
.cf_error
.re_errno
= ENOMEM
;
96 if (name
!= SSPI_C_NO_NAME
) {
97 if (gss_duplicate_name(&min_stat
, name
, &gd
->name
)
99 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
100 rpc_createerr
.cf_error
.re_errno
= ENOMEM
;
107 gd
->name
= strdup(name
);
111 SecInvalidateHandle(&gd
->ctx
);
114 gd
->gc
.gc_v
= RPCSEC_SSPI_VERSION
;
115 gd
->gc
.gc_proc
= RPCSEC_SSPI_INIT
;
116 gd
->gc
.gc_svc
= gd
->sec
->svc
;
118 auth
->ah_ops
= &authsspi_ops
;
119 auth
->ah_private
= (caddr_t
)gd
;
121 save_auth
= clnt
->cl_auth
;
122 clnt
->cl_auth
= auth
;
124 if (!authsspi_refresh(auth
, NULL
))
127 clnt
->cl_auth
= save_auth
;
133 authsspi_create_default(CLIENT
*clnt
, char *service
, int svc
)
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
;
142 log_debug("in authgss_create_default() for %s", service
);
144 sname
.value
= service
;
145 sname
.length
= (int)strlen(service
);
147 maj_stat
= gss_import_name(&min_stat
, &sname
,
148 (gss_OID
)GSS_C_NT_HOSTBASED_SERVICE
,
151 maj_stat
= sspi_import_name(&sname
, &name
);
153 if (maj_stat
!= SEC_E_OK
) {
154 log_debug("authgss_create_default: sspi_import_name failed with %x", maj_stat
);
157 sec
= calloc(1, sizeof(struct rpc_sspi_sec
));
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
);
170 auth
= authsspi_create(clnt
, name
, sec
);
175 if (name
!= SSPI_C_NO_NAME
) {
177 gss_release_name(&min_stat
, &name
);
185 if (rpc_createerr
.cf_error
.re_errno
== ENOMEM
) {
186 FreeCredentialsHandle(&sec
->cred
);
190 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
191 rpc_createerr
.cf_error
.re_errno
= ENOMEM
;
196 authsspi_nextverf(AUTH
*auth
)
198 log_debug("in authgss_nextverf()");
199 /* no action necessary */
203 authsspi_marshal(AUTH
*auth
, XDR
*xdrs
, u_int
*seq
)
206 char tmp
[MAX_AUTH_BYTES
];
207 struct rpc_sspi_data
*gd
;
208 sspi_buffer_desc rpcbuf
, checksum
;
212 log_debug("in authgss_marshal()");
214 gd
= AUTH_PRIVATE(auth
);
216 if (gd
->established
) {
218 *seq
= gd
->gc
.gc_seq
;
221 xdrmem_create(&tmpxdrs
, tmp
, sizeof(tmp
), XDR_ENCODE
);
223 if (!xdr_rpc_sspi_cred(&tmpxdrs
, &gd
->gc
)) {
224 log_debug("authsspi_marshal: xdr_rpc_sspi_cred failed");
225 XDR_DESTROY(&tmpxdrs
);
228 auth
->ah_cred
.oa_flavor
= RPCSEC_GSS
;
229 auth
->ah_cred
.oa_base
= tmp
;
230 auth
->ah_cred
.oa_length
= XDR_GETPOS(&tmpxdrs
);
232 XDR_DESTROY(&tmpxdrs
);
234 if (!xdr_opaque_auth(xdrs
, &auth
->ah_cred
)) {
235 log_debug("authsspi_marshal: failed to xdr GSS CRED");
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
));
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;
249 maj_stat
= gss_get_mic(&min_stat
, gd
->ctx
, gd
->sec
.qop
,
252 maj_stat
= sspi_get_mic(&gd
->ctx
, 0, gd
->gc
.gc_seq
, &rpcbuf
, &checksum
);
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
);
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
);
267 gss_release_buffer(&min_stat
, &checksum
);
269 sspi_release_buffer(&checksum
);
275 authsspi_validate(AUTH
*auth
, struct opaque_auth
*verf
, u_int seq
)
277 struct rpc_sspi_data
*gd
;
278 u_int num
, qop_state
, cur_seq
;
279 sspi_buffer_desc signbuf
, checksum
;
282 log_debug("in authgss_validate(for seq=%d)", seq
);
284 gd
= AUTH_PRIVATE(auth
);
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
293 if ((gd
->gc_wire_verf
.value
=
294 mem_alloc(verf
->oa_length
)) == NULL
) {
297 memcpy(gd
->gc_wire_verf
.value
, verf
->oa_base
, verf
->oa_length
);
298 gd
->gc_wire_verf
.length
= verf
->oa_length
;
302 if (gd
->gc
.gc_proc
== RPCSEC_SSPI_DESTROY
)
305 if (gd
->gc
.gc_proc
== RPCSEC_SSPI_INIT
||
306 gd
->gc
.gc_proc
== RPCSEC_SSPI_CONTINUE_INIT
) {
307 num
= htonl(gd
->win
);
311 num
= htonl(gd
->gc
.gc_seq
);
312 cur_seq
= gd
->gc
.gc_seq
;
320 signbuf
.value
= &num
;
321 signbuf
.length
= sizeof(num
);
323 checksum
.value
= verf
->oa_base
;
324 checksum
.length
= verf
->oa_length
;
326 maj_stat
= gss_verify_mic(&min_stat
, gd
->ctx
, &signbuf
,
327 &checksum
, &qop_state
);
329 maj_stat
= sspi_verify_mic(&gd
->ctx
, cur_seq
, &signbuf
, &checksum
, &qop_state
);
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
);
343 authsspi_refresh(AUTH
*auth
, void *tmp
)
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];
354 log_debug("in authgss_refresh()");
356 gd
= AUTH_PRIVATE(auth
);
358 if ((gd
->established
&& tmp
== NULL
) || gd
->inprogress
)
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
;
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
;
378 print_rpc_gss_sec(gd
->sec
);
380 if (gd
->sec
->svc
== RPCSEC_SSPI_SVC_PRIVACY
)
381 flags
|= ISC_REQ_CONFIDENTIALITY
;
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);
391 maj_stat
= gss_init_sec_context(&min_stat
,
400 NULL
, /* used mech */
403 NULL
); /* time rec */
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
);
414 maj_stat
= InitializeSecurityContextA(
416 ((i
==0)?NULL
:&gd
->ctx
),
420 SECURITY_NATIVE_DREP
,
421 ((i
==0)?NULL
:&in_desc
),
428 if (recv_tokenp
!= SSPI_C_NO_BUFFER
) {
430 gss_release_buffer(&min_stat
, &gr
.gr_token
);
432 sspi_release_buffer(&gr
.gr_token
);
434 recv_tokenp
= SSPI_C_NO_BUFFER
;
436 if (maj_stat
!= SEC_E_OK
&& maj_stat
!= SEC_I_CONTINUE_NEEDED
) {
437 log_debug("InitializeSecurityContext failed with %x", maj_stat
);
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
));
445 /* print the token we are about to send */
446 log_debug("The token being sent (length %d):",
448 log_hexdump(0, "", send_token
.value
, send_token
.length
, 0);
450 call_stat
= clnt_call(gd
->clnt
, NULLPROC
,
451 (xdrproc_t
)xdr_rpc_sspi_init_args
,
453 (xdrproc_t
)xdr_rpc_sspi_init_res
,
454 (caddr_t
)&gr
, AUTH_TIMEOUT
);
456 gss_release_buffer(&min_stat
, &send_token
);
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
);
462 if (call_stat
!= RPC_SUCCESS
||
463 (gr
.gr_major
!= SEC_E_OK
&&
464 gr
.gr_major
!= SEC_I_CONTINUE_NEEDED
))
467 if (gr
.gr_ctx
.length
!= 0) {
469 if (gd
->gc
.gc_ctx
.value
)
470 gss_release_buffer(&min_stat
,
473 sspi_release_buffer(&gd
->gc
.gc_ctx
);
475 gd
->gc
.gc_ctx
= gr
.gr_ctx
;
477 if (gr
.gr_token
.length
!= 0) {
478 if (maj_stat
!= SEC_I_CONTINUE_NEEDED
)
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
;
488 gd
->gc
.gc_proc
= RPCSEC_SSPI_CONTINUE_INIT
;
491 /* GSS_S_COMPLETE => check gss header verifier,
492 * usually checked in gss_validate
494 if (maj_stat
== SEC_E_OK
) {
495 sspi_buffer_desc bufin
;
496 u_int seq
, qop_state
= 0;
498 print_negotiated_attrs(&gd
->ctx
);
500 seq
= htonl(gr
.gr_win
);
501 bufin
.value
= (unsigned char *)&seq
;
502 bufin
.length
= sizeof(seq
);
504 maj_stat
= gss_verify_mic(&min_stat
, gd
->ctx
,
505 &bufin
, &bufout
, &qop_state
);
507 maj_stat
= sspi_verify_mic(&gd
->ctx
, 0, &bufin
, &gd
->gc_wire_verf
, &qop_state
);
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
);
517 gd
->established
= TRUE
;
518 gd
->inprogress
= FALSE
;
519 gd
->gc
.gc_proc
= RPCSEC_SSPI_DATA
;
522 log_debug("authgss_refresh: established GSS context");
526 /* End context negotiation loop. */
527 if (gd
->gc
.gc_proc
!= RPCSEC_SSPI_DATA
) {
528 if (gr
.gr_token
.length
!= 0)
530 gss_release_buffer(&min_stat
, &gr
.gr_token
);
532 sspi_release_buffer(&gr
.gr_token
);
534 authsspi_destroy(auth
);
536 rpc_createerr
.cf_stat
= RPC_AUTHERROR
;
544 authsspi_service(AUTH
*auth
, int svc
)
546 struct rpc_sspi_data
*gd
;
548 log_debug("in authgss_service()");
552 gd
= AUTH_PRIVATE(auth
);
553 if (!gd
|| !gd
->established
)
561 authsspi_destroy_context(AUTH
*auth
)
563 struct rpc_sspi_data
*gd
;
565 log_debug("in authgss_destroy_context()");
567 gd
= AUTH_PRIVATE(auth
);
568 if (gd
== NULL
) return;
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
);
577 sspi_release_buffer(&gd
->gc
.gc_ctx
);
578 SecInvalidateHandle(&gd
->ctx
);
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
);
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;
592 gd
->established
= FALSE
;
596 authsspi_destroy(AUTH
*auth
)
598 struct rpc_sspi_data
*gd
;
600 log_debug("in authgss_destroy()");
602 gd
= AUTH_PRIVATE(auth
);
603 if (gd
== NULL
) return;
605 authsspi_destroy_context(auth
);
608 if (gd
->name
!= SSPI_C_NO_NAME
)
609 gss_release_name(&min_stat
, &gd
->name
);
613 FreeCredentialsHandle(&gd
->sec
->cred
);
620 authsspi_wrap(AUTH
*auth
, XDR
*xdrs
, xdrproc_t xdr_func
, caddr_t xdr_ptr
)
622 struct rpc_sspi_data
*gd
;
624 log_debug("in authgss_wrap()");
626 gd
= AUTH_PRIVATE(auth
);
628 if (!gd
->established
|| gd
->sec
->svc
== RPCSEC_SSPI_SVC_NONE
) {
629 return ((*xdr_func
)(xdrs
, xdr_ptr
));
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
));
637 authsspi_unwrap(AUTH
*auth
, XDR
*xdrs
, xdrproc_t xdr_func
, caddr_t xdr_ptr
, u_int seq
)
639 struct rpc_sspi_data
*gd
;
641 log_debug("in authgss_unwrap()");
643 gd
= AUTH_PRIVATE(auth
);
645 if (!gd
->established
|| gd
->sec
->svc
== RPCSEC_SSPI_SVC_NONE
) {
646 return ((*xdr_func
)(xdrs
, xdr_ptr
));
648 return (xdr_rpc_sspi_data(xdrs
, xdr_func
, xdr_ptr
,
649 &gd
->ctx
, gd
->sec
->qop
,
654 uint32_t sspi_get_mic(void *dummy
, u_int qop
, u_int seq
,
655 sspi_buffer_desc
*bufin
, sspi_buffer_desc
*bufout
)
657 PCtxtHandle ctx
= dummy
;
659 uint32_t sspi_get_mic(PCtxtHandle ctx
, u_int qop
, u_int seq
,
660 sspi_buffer_desc
*bufin
, sspi_buffer_desc
*bufout
)
664 SecPkgContext_Sizes ContextSizes
;
666 SecBuffer sec_tkn
[2];
668 log_hexdump(0, "sspi_get_mic: calculating checksum of", bufin
->value
, bufin
->length
, 0);
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
;
674 if (ContextSizes
.cbMaxSignature
== 0) return SEC_E_INTERNAL_ERROR
;
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
;
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);
693 free(sec_tkn
[1].pvBuffer
);
699 uint32_t sspi_verify_mic(PCtxtHandle ctx
, u_int seq
, sspi_buffer_desc
*bufin
,
700 sspi_buffer_desc
*bufout
, u_int
*qop_state
)
703 uint32_t sspi_verify_mic(void *dummy
, u_int seq
, sspi_buffer_desc
*bufin
,
704 sspi_buffer_desc
*bufout
, u_int
*qop_state
)
706 PCtxtHandle ctx
= dummy
;
709 SecBuffer sec_tkn
[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
;
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);
724 return VerifySignature(ctx
, &desc
, seq
, qop_state
);
727 void sspi_release_buffer(sspi_buffer_desc
*buf
)
735 uint32_t sspi_import_name(sspi_buffer_desc
*name_in
, sspi_name_t
*name_out
)
737 *name_out
= calloc(name_in
->length
+ 5, sizeof(char));
738 if (*name_out
== NULL
)
739 return SEC_E_INSUFFICIENT_MEMORY
;
741 strcpy(*name_out
, "nfs/");
742 strncat(*name_out
, name_in
->value
, name_in
->length
);
744 log_debug("imported service name is: %s\n", *name_out
);
750 uint32_t sspi_wrap(PCtxtHandle ctx
, u_int seq
, sspi_buffer_desc
*bufin
,
751 sspi_buffer_desc
*bufout
, u_int
*conf_state
)
754 uint32_t sspi_wrap(void *dummy
, u_int seq
, sspi_buffer_desc
*bufin
,
755 sspi_buffer_desc
*bufout
, u_int
*conf_state
)
757 PCtxtHandle ctx
= dummy
;
760 SecBufferDesc BuffDesc
;
761 SecBuffer SecBuff
[3];
763 SecPkgContext_Sizes ContextSizes
;
766 maj_stat
= QueryContextAttributes(ctx
, SECPKG_ATTR_SIZES
,
768 if (maj_stat
!= SEC_E_OK
)
771 BuffDesc
.ulVersion
= 0;
772 BuffDesc
.cBuffers
= 3;
773 BuffDesc
.pBuffers
= SecBuff
;
775 SecBuff
[0].cbBuffer
= ContextSizes
.cbSecurityTrailer
;
776 SecBuff
[0].BufferType
= SECBUFFER_TOKEN
;
777 SecBuff
[0].pvBuffer
= malloc(ContextSizes
.cbSecurityTrailer
);
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);
784 SecBuff
[2].cbBuffer
= ContextSizes
.cbBlockSize
;
785 SecBuff
[2].BufferType
= SECBUFFER_PADDING
;
786 SecBuff
[2].pvBuffer
= malloc(ContextSizes
.cbBlockSize
);
788 maj_stat
= EncryptMessage(ctx
, ulQop
, &BuffDesc
, seq
);
789 if (maj_stat
!= SEC_E_OK
)
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
);
800 free(SecBuff
[0].pvBuffer
);
801 free(SecBuff
[2].pvBuffer
);
804 log_hexdump(0, "cipher:", bufout
->value
, bufout
->length
, 0);
810 uint32_t sspi_unwrap(PCtxtHandle ctx
, u_int seq
, sspi_buffer_desc
*bufin
,
811 sspi_buffer_desc
*bufout
, u_int
*conf_state
,
815 uint32_t sspi_unwrap(void *dummy
, u_int seq
, sspi_buffer_desc
*bufin
,
816 sspi_buffer_desc
*bufout
, u_int
*conf_state
,
819 PCtxtHandle ctx
= dummy
;
822 SecBufferDesc BuffDesc
;
823 SecBuffer SecBuff
[2];
826 BuffDesc
.ulVersion
= 0;
827 BuffDesc
.cBuffers
= 2;
828 BuffDesc
.pBuffers
= SecBuff
;
830 SecBuff
[0].cbBuffer
= bufin
->length
;
831 SecBuff
[0].BufferType
= SECBUFFER_STREAM
;
832 SecBuff
[0].pvBuffer
= bufin
->value
;
834 SecBuff
[1].cbBuffer
= 0;
835 SecBuff
[1].BufferType
= SECBUFFER_DATA
;
836 SecBuff
[1].pvBuffer
= NULL
;
838 log_hexdump(0, "cipher:", bufin
->value
, bufin
->length
, 0);
840 maj_stat
= DecryptMessage(ctx
, &BuffDesc
, seq
, &ulQop
);
841 if (maj_stat
!= SEC_E_OK
) return maj_stat
;
843 bufout
->length
= SecBuff
[1].cbBuffer
;
844 bufout
->value
= malloc(bufout
->length
);
845 memcpy(bufout
->value
, SecBuff
[1].pvBuffer
, bufout
->length
);
847 log_hexdump(0, "data:", bufout
->value
, bufout
->length
, 0);
855 /* useful as i add more mechanisms */
858 #define fd_out stdout
859 void print_rpc_gss_sec(struct rpc_sspi_sec
*ptr
)
864 fprintf(fd_out
, "rpc_gss_sec:");
865 if(ptr
->mech
== NULL
)
866 fprintf(fd_out
, "NULL gss_OID mech");
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 */
878 else if (40 <= *p
&& *p
< 80) {
882 else if (80 <= *p
&& *p
< 127) {
891 fprintf(fd_out
, " %u %u", first
, second
);
895 fprintf(fd_out
, " %u", (unsigned char)*p
++);
897 fprintf(fd_out
, " }\n");
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
);
904 void print_negotiated_attrs(PCtxtHandle ctx
)
906 SecPkgContext_Sizes ContextSizes
;
910 maj_stat
= QueryContextAttributesA(ctx
, SECPKG_ATTR_FLAGS
, &flags
);
911 if (maj_stat
!= SEC_E_OK
) return;
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");
935 maj_stat
= QueryContextAttributesA(ctx
, SECPKG_ATTR_SIZES
, &ContextSizes
);
936 if (maj_stat
!= SEC_E_OK
) return;
938 log_debug("signature size is %d\n", ContextSizes
.cbMaxSignature
);
942 void log_hexdump(bool_t on
, const u_char
*title
, const u_char
*buf
,
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
));
953 jm
= jm
> 16 ? 16 : jm
;
955 for (j
= 0; j
< jm
; j
++) {
957 fprintf(fd_out
, "%02x ", (u_int
) buf
[i
+j
]);
959 fprintf(fd_out
, "%02x", (u_int
) buf
[i
+j
]);
961 for (; j
< 16; j
++) {
962 if ((j
% 2) == 1) fprintf(fd_out
, " ");
963 else fprintf(fd_out
, " ");
965 fprintf(fd_out
, " ");
967 for (j
= 0; j
< jm
; j
++) {
969 c
= isprint(c
) ? c
: '.';
970 fprintf(fd_out
, "%c", c
);
972 fprintf(fd_out
, "\n");
977 void log_debug(const char *fmt
, ...)
982 fprintf(fd_out
, "%04x: rpcsec_gss: ", GetCurrentThreadId());
983 vfprintf(fd_out
, fmt
, ap
);
984 fprintf(fd_out
, "\n");
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; }