// Copyright 2013-2015 Apcera Inc. All rights reserved. package gssapi // This file provides GSSContext methods /* #include OM_uint32 wrap_gss_init_sec_context(void *fp, OM_uint32 * minor_status, const gss_cred_id_t initiator_cred_handle, gss_ctx_id_t * context_handle, const gss_name_t target_name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec) { return ((OM_uint32(*) ( OM_uint32 *, const gss_cred_id_t, gss_ctx_id_t *, const gss_name_t, const gss_OID, OM_uint32, OM_uint32, const gss_channel_bindings_t, const gss_buffer_t, gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *) ) fp)( minor_status, initiator_cred_handle, context_handle, target_name, mech_type, req_flags, time_req, input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec); } OM_uint32 wrap_gss_accept_sec_context(void *fp, OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec, gss_cred_id_t * delegated_cred_handle) { return ((OM_uint32(*) ( OM_uint32 *, gss_ctx_id_t *, const gss_cred_id_t, const gss_buffer_t, const gss_channel_bindings_t, gss_name_t *, gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *, gss_cred_id_t *) ) fp)( minor_status, context_handle, acceptor_cred_handle, input_token_buffer, input_chan_bindings, src_name, mech_type, output_token, ret_flags, time_rec, delegated_cred_handle); } OM_uint32 wrap_gss_delete_sec_context(void *fp, OM_uint32 * minor_status, gss_ctx_id_t * context_handle, gss_buffer_t output_token) { return ((OM_uint32(*) ( OM_uint32 *, gss_ctx_id_t *, gss_buffer_t) ) fp)( minor_status, context_handle, output_token); } OM_uint32 wrap_gss_inquire_context(void *fp, OM_uint32 * minor_status, const gss_ctx_id_t context_handle, gss_name_t * src_name, gss_name_t * targ_name, OM_uint32 * lifetime_rec, gss_OID * mech_type, OM_uint32 * ctx_flags, int * locally_initiated, int * open) { return ((OM_uint32(*) ( OM_uint32 *, const gss_ctx_id_t, gss_name_t *, gss_name_t *, OM_uint32 *, gss_OID *, OM_uint32 *, int *, int *) ) fp)( minor_status, context_handle, src_name, targ_name, lifetime_rec, mech_type, ctx_flags, locally_initiated, open); } */ import "C" import ( "runtime" "time" ) func (lib *Lib) NewCtxId() *CtxId { return &CtxId{ Lib: lib, } } // InitSecContext initiates a security context. Usually invoked by the client. // A Context (CtxId) describes the state at one end of an authentication // protocol. May return ErrContinueNeeded if the client is to make another // iteration of exchanging token with the service func (lib *Lib) InitSecContext(initiatorCredHandle *CredId, ctxIn *CtxId, targetName *Name, mechType *OID, reqFlags uint32, timeReq time.Duration, inputChanBindings ChannelBindings, inputToken *Buffer) ( ctxOut *CtxId, actualMechType *OID, outputToken *Buffer, retFlags uint32, timeRec time.Duration, err error) { runtime.LockOSThread() defer runtime.UnlockOSThread() // prepare the input params C_initiator := C.gss_cred_id_t(nil) if initiatorCredHandle != nil { C_initiator = initiatorCredHandle.C_gss_cred_id_t } C_mechType := C.gss_OID(nil) if mechType != nil { C_mechType = mechType.C_gss_OID } C_inputToken := C.gss_buffer_t(nil) if inputToken != nil { C_inputToken = inputToken.C_gss_buffer_t } // prepare the outputs. if ctxIn != nil { ctxCopy := *ctxIn ctxOut = &ctxCopy } else { ctxOut = lib.NewCtxId() } min := C.OM_uint32(0) actualMechType = lib.NewOID() outputToken, err = lib.MakeBuffer(allocGSSAPI) if err != nil { return nil, nil, nil, 0, 0, err } flags := C.OM_uint32(0) timerec := C.OM_uint32(0) maj := C.wrap_gss_init_sec_context(lib.Fp_gss_init_sec_context, &min, C_initiator, &ctxOut.C_gss_ctx_id_t, // used as both in and out param targetName.C_gss_name_t, C_mechType, C.OM_uint32(reqFlags), C.OM_uint32(timeReq.Seconds()), C.gss_channel_bindings_t(inputChanBindings), C_inputToken, &actualMechType.C_gss_OID, outputToken.C_gss_buffer_t, &flags, &timerec) err = lib.stashLastStatus(maj, min) if err != nil { return nil, nil, nil, 0, 0, err } if MajorStatus(maj).ContinueNeeded() { err = ErrContinueNeeded } return ctxOut, actualMechType, outputToken, uint32(flags), time.Duration(timerec) * time.Second, err } // AcceptSecContext accepts an initialized security context. Usually called by // the server. May return ErrContinueNeeded if the client is to make another // iteration of exchanging token with the service func (lib *Lib) AcceptSecContext( ctxIn *CtxId, acceptorCredHandle *CredId, inputToken *Buffer, inputChanBindings ChannelBindings) ( ctxOut *CtxId, srcName *Name, actualMechType *OID, outputToken *Buffer, retFlags uint32, timeRec time.Duration, delegatedCredHandle *CredId, err error) { runtime.LockOSThread() defer runtime.UnlockOSThread() // prepare the inputs C_acceptorCredHandle := C.gss_cred_id_t(nil) if acceptorCredHandle != nil { C_acceptorCredHandle = acceptorCredHandle.C_gss_cred_id_t } C_inputToken := C.gss_buffer_t(nil) if inputToken != nil { C_inputToken = inputToken.C_gss_buffer_t } // prepare the outputs if ctxIn != nil { ctxCopy := *ctxIn ctxOut = &ctxCopy } else { ctxOut = lib.GSS_C_NO_CONTEXT } min := C.OM_uint32(0) srcName = lib.NewName() actualMechType = lib.NewOID() outputToken, err = lib.MakeBuffer(allocGSSAPI) if err != nil { return nil, nil, nil, nil, 0, 0, nil, err } flags := C.OM_uint32(0) timerec := C.OM_uint32(0) delegatedCredHandle = lib.NewCredId() maj := C.wrap_gss_accept_sec_context(lib.Fp_gss_accept_sec_context, &min, &ctxOut.C_gss_ctx_id_t, // used as both in and out param C_acceptorCredHandle, C_inputToken, C.gss_channel_bindings_t(inputChanBindings), &srcName.C_gss_name_t, &actualMechType.C_gss_OID, outputToken.C_gss_buffer_t, &flags, &timerec, &delegatedCredHandle.C_gss_cred_id_t) err = lib.stashLastStatus(maj, min) if err != nil { lib.Err("AcceptSecContext: ", err) return nil, nil, nil, nil, 0, 0, nil, err } if MajorStatus(maj).ContinueNeeded() { err = ErrContinueNeeded } return ctxOut, srcName, actualMechType, outputToken, uint32(flags), time.Duration(timerec) * time.Second, delegatedCredHandle, err } // DeleteSecContext frees a security context. // NB: I decided not to implement the outputToken parameter since its use is no // longer recommended, and it would have to be Released by the caller func (ctx *CtxId) DeleteSecContext() error { if ctx == nil || ctx.C_gss_ctx_id_t == nil { return nil } runtime.LockOSThread() defer runtime.UnlockOSThread() min := C.OM_uint32(0) maj := C.wrap_gss_delete_sec_context(ctx.Fp_gss_delete_sec_context, &min, &ctx.C_gss_ctx_id_t, nil) return ctx.stashLastStatus(maj, min) } // Release is an alias for DeleteSecContext. func (ctx *CtxId) Release() error { return ctx.DeleteSecContext() } // InquireContext returns fields about a security context. func (ctx *CtxId) InquireContext() ( srcName *Name, targetName *Name, lifetimeRec time.Duration, mechType *OID, ctxFlags uint64, locallyInitiated bool, open bool, err error) { min := C.OM_uint32(0) srcName = ctx.NewName() targetName = ctx.NewName() rec := C.OM_uint32(0) mechType = ctx.NewOID() flags := C.OM_uint32(0) li := C.int(0) opn := C.int(0) maj := C.wrap_gss_inquire_context(ctx.Fp_gss_inquire_context, &min, ctx.C_gss_ctx_id_t, &srcName.C_gss_name_t, &targetName.C_gss_name_t, &rec, &mechType.C_gss_OID, &flags, &li, &opn) err = ctx.stashLastStatus(maj, min) if err != nil { ctx.Err("InquireContext: ", err) return nil, nil, 0, nil, 0, false, false, err } lifetimeRec = time.Duration(rec) * time.Second ctxFlags = uint64(flags) if li != 0 { locallyInitiated = true } if opn != 0 { open = true } return srcName, targetName, lifetimeRec, mechType, ctxFlags, locallyInitiated, open, nil }