first stab at integrity and privacy

note: privacy will not work when we have more than 1 outstanding rpcs which generates out of order replies which sspi does not allow when privacy is enabled.

adding auth_wrap() and auth_unwrap() to per-message gss token protection required adding these methods to auth_sys and auth_non.

linux server doesnt support v2 kerberos tokens that have rotated data. sspi will always produce such tokens for aes. thus thus code was only tested for v1 kerberos tokens (ie des).
This commit is contained in:
Olga Kornievskaia 2011-01-27 13:52:08 -05:00
parent b6120b41fd
commit 4411d3d807
7 changed files with 149 additions and 28 deletions

View file

@ -156,6 +156,12 @@ authnone_destroy(AUTH *client)
{ {
} }
static bool_t
authnone_wrap(AUTH *auth, XDR *xdrs, xdrproc_t func, caddr_t args, u_int seq)
{
return ((*func)(xdrs, args));
}
static struct auth_ops * static struct auth_ops *
authnone_ops() authnone_ops()
{ {
@ -171,6 +177,8 @@ authnone_ops()
ops.ah_validate = authnone_validate; ops.ah_validate = authnone_validate;
ops.ah_refresh = authnone_refresh; ops.ah_refresh = authnone_refresh;
ops.ah_destroy = authnone_destroy; ops.ah_destroy = authnone_destroy;
ops.ah_wrap = authnone_wrap;
ops.ah_unwrap = authnone_wrap;
} }
mutex_unlock(&ops_lock); mutex_unlock(&ops_lock);
return (&ops); return (&ops);

View file

@ -324,7 +324,7 @@ authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq)
#else #else
maj_stat = sspi_verify_mic(&gd->ctx, cur_seq, &signbuf, &checksum, &qop_state); maj_stat = sspi_verify_mic(&gd->ctx, cur_seq, &signbuf, &checksum, &qop_state);
#endif #endif
if (maj_stat != SEC_E_OK || qop_state != gd->sec->qop) { if (maj_stat != SEC_E_OK) {
log_debug("authsspi_validate: VerifySignature failed with %x", maj_stat); log_debug("authsspi_validate: VerifySignature failed with %x", maj_stat);
if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) { if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
gd->established = FALSE; gd->established = FALSE;
@ -373,7 +373,10 @@ authsspi_refresh(AUTH *auth, void *tmp)
print_rpc_gss_sec(gd->sec); print_rpc_gss_sec(gd->sec);
for (i=0;;i++) { if (gd->sec->svc == RPCSEC_SSPI_SVC_PRIVACY)
flags |= ISC_REQ_CONFIDENTIALITY;
for (i=0;;i++) {
/* print the token we just received */ /* print the token we just received */
if (recv_tokenp != SSPI_C_NO_BUFFER) { if (recv_tokenp != SSPI_C_NO_BUFFER) {
log_debug("The token we just received (length %d):", log_debug("The token we just received (length %d):",
@ -498,7 +501,7 @@ authsspi_refresh(AUTH *auth, void *tmp)
#else #else
maj_stat = sspi_verify_mic(&gd->ctx, 0, &bufin, &gd->gc_wire_verf, &qop_state); maj_stat = sspi_verify_mic(&gd->ctx, 0, &bufin, &gd->gc_wire_verf, &qop_state);
#endif #endif
if (maj_stat != SEC_E_OK || qop_state != gd->sec->qop) { if (maj_stat != SEC_E_OK) {
log_debug("authgss_refresh: sspi_verify_mic failed with %x", maj_stat); log_debug("authgss_refresh: sspi_verify_mic failed with %x", maj_stat);
if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) { if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
gd->established = FALSE; gd->established = FALSE;
@ -623,7 +626,7 @@ authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
} }
bool_t bool_t
authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq)
{ {
struct rpc_sspi_data *gd; struct rpc_sspi_data *gd;
@ -636,7 +639,7 @@ authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
} }
return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr, return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr,
&gd->ctx, gd->sec->qop, &gd->ctx, gd->sec->qop,
gd->sec->svc, gd->gc.gc_seq)); gd->sec->svc, seq));
} }
uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq, uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq,
@ -720,6 +723,98 @@ uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out)
return SEC_E_OK; return SEC_E_OK;
} }
uint32_t sspi_wrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin,
sspi_buffer_desc *bufout, u_int *conf_state)
{
uint32_t maj_stat;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[3];
ULONG ulQop = 0;
SecPkgContext_Sizes ContextSizes;
PBYTE p;
maj_stat = QueryContextAttributes(ctx, SECPKG_ATTR_SIZES,
&ContextSizes);
if (maj_stat != SEC_E_OK)
goto out;
BuffDesc.ulVersion = 0;
BuffDesc.cBuffers = 3;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].cbBuffer = ContextSizes.cbSecurityTrailer;
SecBuff[0].BufferType = SECBUFFER_TOKEN;
SecBuff[0].pvBuffer = malloc(ContextSizes.cbSecurityTrailer);
SecBuff[1].cbBuffer = bufin->length;
SecBuff[1].BufferType = SECBUFFER_DATA;
SecBuff[1].pvBuffer = bufin->value;
log_hexdump(0, "plaintext:", bufin->value, bufin->length, 0);
SecBuff[2].cbBuffer = ContextSizes.cbBlockSize;
SecBuff[2].BufferType = SECBUFFER_PADDING;
SecBuff[2].pvBuffer = malloc(ContextSizes.cbBlockSize);
maj_stat = EncryptMessage(ctx, ulQop, &BuffDesc, 0);
if (maj_stat != SEC_E_OK)
goto out_free;
bufout->length = SecBuff[0].cbBuffer + SecBuff[1].cbBuffer + SecBuff[2].cbBuffer;
p = bufout->value = malloc(bufout->length);
memcpy(p, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer);
p += SecBuff[0].cbBuffer;
memcpy(p, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer);
p += SecBuff[1].cbBuffer;
memcpy(p, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer);
out_free:
free(SecBuff[0].pvBuffer);
free(SecBuff[2].pvBuffer);
if (!maj_stat)
log_hexdump(0, "cipher:", bufout->value, bufout->length, 0);
out:
return maj_stat;
}
uint32_t sspi_upwrap(PCtxtHandle ctx, sspi_buffer_desc *bufin,
sspi_buffer_desc *bufout, u_int *conf_state,
u_int *qop_state)
{
uint32_t maj_stat;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[2];
ULONG ulQop = 0;
BuffDesc.ulVersion = 0;
BuffDesc.cBuffers = 2;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].cbBuffer = bufin->length;
SecBuff[0].BufferType = SECBUFFER_STREAM;
SecBuff[0].pvBuffer = bufin->value;
SecBuff[1].cbBuffer = 0;
SecBuff[1].BufferType = SECBUFFER_DATA;
SecBuff[1].pvBuffer = NULL;
log_hexdump(0, "cipher:", bufin->value, bufin->length, 0);
maj_stat = DecryptMessage(ctx, &BuffDesc, 0, &ulQop);
if (maj_stat != SEC_E_OK) return maj_stat;
bufout->length = SecBuff[1].cbBuffer;
bufout->value = malloc(bufout->length);
memcpy(bufout->value, SecBuff[1].pvBuffer, bufout->length);
log_hexdump(0, "data:", bufout->value, bufout->length, 0);
*conf_state = 1;
*qop_state = 0;
return SEC_E_OK;
}
/* useful as i add more mechanisms */ /* useful as i add more mechanisms */
#define DEBUG #define DEBUG
#ifdef DEBUG #ifdef DEBUG

View file

@ -353,6 +353,12 @@ marshal_new_auth(auth)
XDR_DESTROY(xdrs); XDR_DESTROY(xdrs);
} }
static bool_t
authunix_wrap(AUTH *auth, XDR *xdrs, xdrproc_t func, caddr_t args, u_int seq)
{
return ((*func)(xdrs, args));
}
static struct auth_ops * static struct auth_ops *
authunix_ops() authunix_ops()
{ {
@ -368,6 +374,8 @@ authunix_ops()
ops.ah_validate = authunix_validate; ops.ah_validate = authunix_validate;
ops.ah_refresh = authunix_refresh; ops.ah_refresh = authunix_refresh;
ops.ah_destroy = authunix_destroy; ops.ah_destroy = authunix_destroy;
ops.ah_wrap = authunix_wrap;
ops.ah_unwrap = authunix_wrap;
} }
mutex_unlock(&ops_lock); mutex_unlock(&ops_lock);
return (&ops); return (&ops);

View file

@ -108,7 +108,7 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
/* Skip databody length. */ /* Skip databody length. */
start = XDR_GETPOS(xdrs); start = XDR_GETPOS(xdrs);
//XDR_SETPOS(xdrs, start + 4); XDR_SETPOS(xdrs, start + 4);
/* Marshal rpc_gss_data_t (sequence number + arguments). */ /* Marshal rpc_gss_data_t (sequence number + arguments). */
if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr)) if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
@ -117,15 +117,14 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
/* Set databuf to marshalled rpc_gss_data_t. */ /* Set databuf to marshalled rpc_gss_data_t. */
databuf.length = end - start - 4; databuf.length = end - start - 4;
//XDR_SETPOS(xdrs, start + 4); XDR_SETPOS(xdrs, start + 4);
//databuf.value = XDR_INLINE(xdrs, databuf.length); databuf.value = XDR_INLINE(xdrs, databuf.length);
databuf.value = xdrrec_getoutbase(xdrs) + 1;
xdr_stat = FALSE; xdr_stat = FALSE;
if (svc == RPCSEC_SSPI_SVC_INTEGRITY) { if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
/* Marshal databody_integ length. */ /* Marshal databody_integ length. */
//XDR_SETPOS(xdrs, start); XDR_SETPOS(xdrs, start);
if (!xdr_u_int(xdrs, (u_int *)&databuf.length)) if (!xdr_u_int(xdrs, (u_int *)&databuf.length))
return (FALSE); return (FALSE);
@ -141,9 +140,9 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
return (FALSE); return (FALSE);
} }
/* Marshal checksum. */ /* Marshal checksum. */
//XDR_SETPOS(xdrs, end); XDR_SETPOS(xdrs, end);
xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
(u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); (u_int *)&wrapbuf.length, (u_int)-1);
#if 0 #if 0
gss_release_buffer(&min_stat, &wrapbuf); gss_release_buffer(&min_stat, &wrapbuf);
#else #else
@ -155,6 +154,8 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
#if 0 #if 0
maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
&conf_state, &wrapbuf); &conf_state, &wrapbuf);
#else
maj_stat = sspi_wrap(ctx, 0, &databuf, &wrapbuf, &conf_state);
#endif #endif
if (maj_stat != SEC_E_OK) { if (maj_stat != SEC_E_OK) {
log_debug("xdr_rpc_sspi_wrap_data: sspi_wrap failed with %x", maj_stat); log_debug("xdr_rpc_sspi_wrap_data: sspi_wrap failed with %x", maj_stat);
@ -163,7 +164,7 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
/* Marshal databody_priv. */ /* Marshal databody_priv. */
XDR_SETPOS(xdrs, start); XDR_SETPOS(xdrs, start);
xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
(u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); (u_int *)&wrapbuf.length, (u_int)-1);
#if 0 #if 0
gss_release_buffer(&min_stat, &wrapbuf); gss_release_buffer(&min_stat, &wrapbuf);
#else #else
@ -196,7 +197,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
if (svc == RPCSEC_SSPI_SVC_INTEGRITY) { if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
/* Decode databody_integ. */ /* Decode databody_integ. */
if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length, if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length,
MAX_NETOBJ_SZ)) { (u_int)-1)) {
log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_integ failed"); log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_integ failed");
return (FALSE); return (FALSE);
} }
@ -224,7 +225,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
sspi_release_buffer(&wrapbuf); sspi_release_buffer(&wrapbuf);
#endif #endif
if (maj_stat != SEC_E_OK || qop_state != qop) { if (maj_stat != SEC_E_OK) {
#if 0 #if 0
gss_release_buffer(&min_stat, &databuf); gss_release_buffer(&min_stat, &databuf);
#else #else
@ -238,7 +239,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
else if (svc == RPCSEC_SSPI_SVC_PRIVACY) { else if (svc == RPCSEC_SSPI_SVC_PRIVACY) {
/* Decode databody_priv. */ /* Decode databody_priv. */
if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length, if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
MAX_NETOBJ_SZ)) { (u_int)-1)) {
log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_priv failed"); log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_priv failed");
return (FALSE); return (FALSE);
} }
@ -246,6 +247,8 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
#if 0 #if 0
maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
&conf_state, &qop_state); &conf_state, &qop_state);
#else
maj_stat = sspi_upwrap(ctx, &wrapbuf, &databuf, &conf_state, &qop_state);
#endif #endif
#if 0 #if 0
gss_release_buffer(&min_stat, &wrapbuf); gss_release_buffer(&min_stat, &wrapbuf);
@ -253,8 +256,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
sspi_release_buffer(&wrapbuf); sspi_release_buffer(&wrapbuf);
#endif #endif
/* Verify encryption and QOP. */ /* Verify encryption and QOP. */
if (maj_stat != SEC_E_OK || qop_state != qop || if (maj_stat != SEC_E_OK) {
conf_state != TRUE) {
#if 0 #if 0
gss_release_buffer(&min_stat, &databuf); gss_release_buffer(&min_stat, &databuf);
#else #else
@ -272,11 +274,12 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
#if 0 #if 0
gss_release_buffer(&min_stat, &databuf); gss_release_buffer(&min_stat, &databuf);
#else #else
sspi_release_buffer(&databuf); sspi_release_buffer(&databuf);
#endif #endif
/* Verify sequence number. */ /* Verify sequence number. */
if (xdr_stat == TRUE && seq_num != seq) { if (xdr_stat == TRUE && seq_num != seq) {
log_debug("wrong sequence number in databody"); log_debug("wrong sequence number in databody received %d expected %d",
seq_num, seq);
return (FALSE); return (FALSE);
} }

View file

@ -523,13 +523,14 @@ call_again:
if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
(! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
(! AUTH_MARSHALL(cl->cl_auth, xdrs, &seq)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs, &seq)) ||
(! (*xdr_args)(xdrs, args_ptr))) { (! AUTH_WRAP(cl->cl_auth, xdrs, xdr_args, args_ptr))) {
if (ct->ct_error.re_status == RPC_SUCCESS) if (ct->ct_error.re_status == RPC_SUCCESS)
ct->ct_error.re_status = RPC_CANTENCODEARGS; ct->ct_error.re_status = RPC_CANTENCODEARGS;
(void)xdrrec_endofrecord(xdrs, TRUE); (void)xdrrec_endofrecord(xdrs, TRUE);
release_fd_lock(ct->ct_fd, mask); release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status); return (ct->ct_error.re_status);
} }
if (! xdrrec_endofrecord(xdrs, shipnow)) { if (! xdrrec_endofrecord(xdrs, shipnow)) {
release_fd_lock(ct->ct_fd, mask); release_fd_lock(ct->ct_fd, mask);
ct->ct_error.re_status = RPC_CANTSEND; ct->ct_error.re_status = RPC_CANTSEND;
@ -552,7 +553,7 @@ call_again:
/* /*
* Keep receiving until we get a valid transaction id * Keep receiving until we get a valid transaction id
*/ */
while (TRUE) { while (TRUE) {
mutex_lock(&clnt_fd_lock); mutex_lock(&clnt_fd_lock);
while ((vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] && while ((vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] &&
@ -613,7 +614,8 @@ call_again:
&ct->reply_msg.acpted_rply.ar_verf, seq)) { &ct->reply_msg.acpted_rply.ar_verf, seq)) {
ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_status = RPC_AUTHERROR;
ct->ct_error.re_why = AUTH_INVALIDRESP; ct->ct_error.re_why = AUTH_INVALIDRESP;
} else if (! (*xdr_results)(xdrs, results_ptr)) { }
else if (! AUTH_UNWRAP(cl->cl_auth, xdrs, xdr_results, results_ptr, seq)) {
if (ct->ct_error.re_status == RPC_SUCCESS) if (ct->ct_error.re_status == RPC_SUCCESS)
ct->ct_error.re_status = RPC_CANTDECODERES; ct->ct_error.re_status = RPC_CANTDECODERES;
} }

View file

@ -198,7 +198,7 @@ typedef struct __auth {
/* encode data for wire */ /* encode data for wire */
int (*ah_wrap) (struct __auth *, XDR *, xdrproc_t, caddr_t); int (*ah_wrap) (struct __auth *, XDR *, xdrproc_t, caddr_t);
/* decode data for wire */ /* decode data for wire */
int (*ah_unwrap) (struct __auth *, XDR *, xdrproc_t, caddr_t); int (*ah_unwrap) (struct __auth *, XDR *, xdrproc_t, caddr_t, u_int);
} *ah_ops; } *ah_ops;
void *ah_private; void *ah_private;
@ -245,12 +245,12 @@ typedef struct __auth {
((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \
xfunc, xwhere)) xfunc, xwhere))
#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ #define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere, seq) \
((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
xfunc, xwhere)) xfunc, xwhere, seq))
#define auth_unwrap(auth, xdrs, xfunc, xwhere) \ #define auth_unwrap(auth, xdrs, xfunc, xwhere, seq) \
((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
xfunc, xwhere)) xfunc, xwhere, seq))
__BEGIN_DECLS __BEGIN_DECLS

View file

@ -105,6 +105,11 @@ uint32_t sspi_get_mic(void *ctx, u_int qop, u_int seq,
sspi_buffer_desc *bufin, sspi_buffer_desc *bufout); sspi_buffer_desc *bufin, sspi_buffer_desc *bufout);
uint32_t sspi_verify_mic(void *ctx, u_int seq, sspi_buffer_desc *bufin, uint32_t sspi_verify_mic(void *ctx, u_int seq, sspi_buffer_desc *bufin,
sspi_buffer_desc *bufout, u_int *qop_state); sspi_buffer_desc *bufout, u_int *qop_state);
uint32_t sspi_wrap(void *ctx, u_int seq, sspi_buffer_desc *bufin,
sspi_buffer_desc *bufout, u_int *conf_state);
uint32_t sspi_unwrap(void *ctx, sspi_buffer_desc *bufin,
sspi_buffer_desc *bufout, u_int *conf_state,
u_int *qop_state);
void sspi_release_buffer(sspi_buffer_desc *buf); void sspi_release_buffer(sspi_buffer_desc *buf);
uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out); uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out);