/* $NetBSD: gssapi.c,v 1.5 2021/08/19 12:13:37 christos Exp $ */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2020 The OpenLDAP Foundation. * All rights reserved. * * Author: Stefan Metzmacher * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include __RCSID("$NetBSD: gssapi.c,v 1.5 2021/08/19 12:13:37 christos Exp $"); #include "portable.h" #include #include #include #include #include #include #include #include #ifdef HAVE_LIMITS_H #include #endif #include "ldap-int.h" #ifdef HAVE_GSSAPI #ifdef HAVE_GSSAPI_GSSAPI_H #include #else #include #endif static char * gsserrstr( char *buf, ber_len_t buf_len, gss_OID mech, int gss_rc, OM_uint32 minor_status ) { OM_uint32 min2; gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER; OM_uint32 msg_ctx = 0; if (buf == NULL) { return NULL; } if (buf_len == 0) { return NULL; } #ifdef HAVE_GSS_OID_TO_STR gss_oid_to_str(&min2, mech, &mech_msg); #endif gss_display_status(&min2, gss_rc, GSS_C_GSS_CODE, mech, &msg_ctx, &gss_msg); gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, mech, &msg_ctx, &minor_msg); snprintf(buf, buf_len, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]", gss_rc, (int)gss_msg.length, (const char *)(gss_msg.value?gss_msg.value:""), (int)mech_msg.length, (const char *)(mech_msg.value?mech_msg.value:""), minor_status, (int)minor_msg.length, (const char *)(minor_msg.value?minor_msg.value:"")); gss_release_buffer(&min2, &mech_msg); gss_release_buffer(&min2, &gss_msg); gss_release_buffer(&min2, &minor_msg); buf[buf_len-1] = '\0'; return buf; } static void sb_sasl_gssapi_init( struct sb_sasl_generic_data *p, ber_len_t *min_send, ber_len_t *max_send, ber_len_t *max_recv ) { gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; int gss_rc; OM_uint32 minor_status; gss_OID ctx_mech = GSS_C_NO_OID; OM_uint32 ctx_flags = 0; int conf_req_flag = 0; OM_uint32 max_input_size; gss_inquire_context(&minor_status, gss_ctx, NULL, NULL, NULL, &ctx_mech, &ctx_flags, NULL, NULL); if (ctx_flags & (GSS_C_CONF_FLAG)) { conf_req_flag = 1; } #if defined(HAVE_CYRUS_SASL) #define SEND_PREALLOC_SIZE SASL_MIN_BUFF_SIZE #else #define SEND_PREALLOC_SIZE 4096 #endif #define SEND_MAX_WIRE_SIZE 0x00A00000 #define RECV_MAX_WIRE_SIZE 0x0FFFFFFF #define FALLBACK_SEND_MAX_SIZE 0x009FFFB8 /* from MIT 1.5.x */ gss_rc = gss_wrap_size_limit(&minor_status, gss_ctx, conf_req_flag, GSS_C_QOP_DEFAULT, SEND_MAX_WIRE_SIZE, &max_input_size); if ( gss_rc != GSS_S_COMPLETE ) { char msg[256]; ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: failed to wrap size limit: %s\n", __func__, gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: fallback to default wrap size limit\n", __func__); /* * some libgssglue/libgssapi versions * have a broken gss_wrap_size_limit() * implementation */ max_input_size = FALLBACK_SEND_MAX_SIZE; } *min_send = SEND_PREALLOC_SIZE; *max_send = max_input_size; *max_recv = RECV_MAX_WIRE_SIZE; } static ber_int_t sb_sasl_gssapi_encode( struct sb_sasl_generic_data *p, unsigned char *buf, ber_len_t len, Sockbuf_Buf *dst ) { gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; int gss_rc; OM_uint32 minor_status; gss_buffer_desc unwrapped, wrapped; gss_OID ctx_mech = GSS_C_NO_OID; OM_uint32 ctx_flags = 0; int conf_req_flag = 0; int conf_state; unsigned char *b; ber_len_t pkt_len; unwrapped.value = buf; unwrapped.length = len; gss_inquire_context(&minor_status, gss_ctx, NULL, NULL, NULL, &ctx_mech, &ctx_flags, NULL, NULL); if (ctx_flags & (GSS_C_CONF_FLAG)) { conf_req_flag = 1; } gss_rc = gss_wrap(&minor_status, gss_ctx, conf_req_flag, GSS_C_QOP_DEFAULT, &unwrapped, &conf_state, &wrapped); if ( gss_rc != GSS_S_COMPLETE ) { char msg[256]; ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: failed to encode packet: %s\n", __func__, gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); return -1; } if ( conf_req_flag && conf_state == 0 ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: GSS_C_CONF_FLAG was ignored by our gss_wrap()\n", __func__); return -1; } pkt_len = 4 + wrapped.length; /* Grow the packet buffer if neccessary */ if ( dst->buf_size < pkt_len && ber_pvt_sb_grow_buffer( dst, pkt_len ) < 0 ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: failed to grow the buffer to %lu bytes\n", __func__, pkt_len ); return -1; } dst->buf_end = pkt_len; b = (unsigned char *)dst->buf_base; b[0] = (unsigned char)(wrapped.length >> 24); b[1] = (unsigned char)(wrapped.length >> 16); b[2] = (unsigned char)(wrapped.length >> 8); b[3] = (unsigned char)(wrapped.length >> 0); /* copy the wrapped blob to the right location */ memcpy(b + 4, wrapped.value, wrapped.length); gss_release_buffer(&minor_status, &wrapped); return 0; } static ber_int_t sb_sasl_gssapi_decode( struct sb_sasl_generic_data *p, const Sockbuf_Buf *src, Sockbuf_Buf *dst ) { gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; int gss_rc; OM_uint32 minor_status; gss_buffer_desc unwrapped, wrapped; gss_OID ctx_mech = GSS_C_NO_OID; OM_uint32 ctx_flags = 0; int conf_req_flag = 0; int conf_state; unsigned char *b; wrapped.value = src->buf_base + 4; wrapped.length = src->buf_end - 4; gss_inquire_context(&minor_status, gss_ctx, NULL, NULL, NULL, &ctx_mech, &ctx_flags, NULL, NULL); if (ctx_flags & (GSS_C_CONF_FLAG)) { conf_req_flag = 1; } gss_rc = gss_unwrap(&minor_status, gss_ctx, &wrapped, &unwrapped, &conf_state, GSS_C_QOP_DEFAULT); if ( gss_rc != GSS_S_COMPLETE ) { char msg[256]; ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: failed to decode packet: %s\n", __func__, gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); return -1; } if ( conf_req_flag && conf_state == 0 ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: GSS_C_CONF_FLAG was ignored by our peer\n", __func__); return -1; } /* Grow the packet buffer if neccessary */ if ( dst->buf_size < unwrapped.length && ber_pvt_sb_grow_buffer( dst, unwrapped.length ) < 0 ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "%s: failed to grow the buffer to %zu bytes\n", __func__, unwrapped.length ); return -1; } dst->buf_end = unwrapped.length; b = (unsigned char *)dst->buf_base; /* copy the wrapped blob to the right location */ memcpy(b, unwrapped.value, unwrapped.length); gss_release_buffer(&minor_status, &unwrapped); return 0; } static void sb_sasl_gssapi_reset_buf( struct sb_sasl_generic_data *p, Sockbuf_Buf *buf ) { ber_pvt_sb_buf_destroy( buf ); } static void sb_sasl_gssapi_fini( struct sb_sasl_generic_data *p ) { } static const struct sb_sasl_generic_ops sb_sasl_gssapi_ops = { sb_sasl_gssapi_init, sb_sasl_gssapi_encode, sb_sasl_gssapi_decode, sb_sasl_gssapi_reset_buf, sb_sasl_gssapi_fini }; static int sb_sasl_gssapi_install( Sockbuf *sb, gss_ctx_id_t gss_ctx ) { struct sb_sasl_generic_install install_arg; install_arg.ops = &sb_sasl_gssapi_ops; install_arg.ops_private = gss_ctx; return ldap_pvt_sasl_generic_install( sb, &install_arg ); } static void sb_sasl_gssapi_remove( Sockbuf *sb ) { ldap_pvt_sasl_generic_remove( sb ); } static int map_gsserr2ldap( LDAP *ld, gss_OID mech, int gss_rc, OM_uint32 minor_status ) { char msg[256]; Debug1( LDAP_DEBUG_ANY, "%s\n", gsserrstr( msg, sizeof(msg), mech, gss_rc, minor_status )); if (gss_rc == GSS_S_COMPLETE) { ld->ld_errno = LDAP_SUCCESS; } else if (GSS_CALLING_ERROR(gss_rc)) { ld->ld_errno = LDAP_LOCAL_ERROR; } else if (GSS_ROUTINE_ERROR(gss_rc)) { ld->ld_errno = LDAP_INAPPROPRIATE_AUTH; } else if (gss_rc == GSS_S_CONTINUE_NEEDED) { ld->ld_errno = LDAP_SASL_BIND_IN_PROGRESS; } else if (GSS_SUPPLEMENTARY_INFO(gss_rc)) { ld->ld_errno = LDAP_AUTH_UNKNOWN; } else if (GSS_ERROR(gss_rc)) { ld->ld_errno = LDAP_AUTH_UNKNOWN; } else { ld->ld_errno = LDAP_OTHER; } return ld->ld_errno; } static int ldap_gssapi_get_rootdse_infos ( LDAP *ld, char **pmechlist, char **pldapServiceName, char **pdnsHostName ) { /* we need to query the server for supported mechs anyway */ LDAPMessage *res, *e; char *attrs[] = { "supportedSASLMechanisms", "ldapServiceName", "dnsHostName", NULL }; char **values, *mechlist; char *ldapServiceName = NULL; char *dnsHostName = NULL; int rc; Debug0( LDAP_DEBUG_TRACE, "ldap_gssapi_get_rootdse_infos\n"); rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &res ); if ( rc != LDAP_SUCCESS ) { return ld->ld_errno; } e = ldap_first_entry( ld, res ); if ( e == NULL ) { ldap_msgfree( res ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_NO_SUCH_OBJECT; } return ld->ld_errno; } values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); if ( values == NULL ) { ldap_msgfree( res ); ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; return ld->ld_errno; } mechlist = ldap_charray2str( values, " " ); if ( mechlist == NULL ) { LDAP_VFREE( values ); ldap_msgfree( res ); ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } LDAP_VFREE( values ); values = ldap_get_values( ld, e, "ldapServiceName" ); if ( values == NULL ) { goto get_dns_host_name; } ldapServiceName = ldap_charray2str( values, " " ); if ( ldapServiceName == NULL ) { LDAP_FREE( mechlist ); LDAP_VFREE( values ); ldap_msgfree( res ); ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } LDAP_VFREE( values ); get_dns_host_name: values = ldap_get_values( ld, e, "dnsHostName" ); if ( values == NULL ) { goto done; } dnsHostName = ldap_charray2str( values, " " ); if ( dnsHostName == NULL ) { LDAP_FREE( mechlist ); LDAP_FREE( ldapServiceName ); LDAP_VFREE( values ); ldap_msgfree( res ); ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } LDAP_VFREE( values ); done: ldap_msgfree( res ); *pmechlist = mechlist; *pldapServiceName = ldapServiceName; *pdnsHostName = dnsHostName; return LDAP_SUCCESS; } static int check_for_gss_spnego_support( LDAP *ld, const char *mechs_str ) { int rc; char **mechs_list = NULL; mechs_list = ldap_str2charray( mechs_str, " " ); if ( mechs_list == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } rc = ldap_charray_inlist( mechs_list, "GSS-SPNEGO" ); ldap_charray_free( mechs_list ); if ( rc != 1) { ld->ld_errno = LDAP_STRONG_AUTH_NOT_SUPPORTED; return ld->ld_errno; } return LDAP_SUCCESS; } static int guess_service_principal( LDAP *ld, const char *ldapServiceName, const char *dnsHostName, gss_name_t *principal ) { gss_buffer_desc input_name; /* GSS_KRB5_NT_PRINCIPAL_NAME */ gss_OID_desc nt_principal = {10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"}; const char *host = ld->ld_defconn->lconn_server->lud_host; OM_uint32 minor_status; int gss_rc; int ret; size_t svc_principal_size; char *svc_principal = NULL; const char *principal_fmt = NULL; const char *str = NULL; const char *givenstr = NULL; const char *ignore = "not_defined_in_RFC4178@please_ignore"; int allow_remote = 0; if (ldapServiceName) { givenstr = strchr(ldapServiceName, ':'); if (givenstr && givenstr[1]) { givenstr++; if (strcmp(givenstr, ignore) == 0) { givenstr = NULL; } } else { givenstr = NULL; } } if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) { allow_remote = 1; } if (allow_remote && givenstr) { principal_fmt = "%s"; svc_principal_size = strlen(givenstr) + 1; str = givenstr; } else if (allow_remote && dnsHostName) { principal_fmt = "ldap/%s"; svc_principal_size = STRLENOF("ldap/") + strlen(dnsHostName) + 1; str = dnsHostName; } else { principal_fmt = "ldap/%s"; svc_principal_size = STRLENOF("ldap/") + strlen(host) + 1; str = host; } svc_principal = (char*) ldap_memalloc(svc_principal_size * sizeof(char)); if ( svc_principal == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } ret = snprintf( svc_principal, svc_principal_size, principal_fmt, str ); if (ret < 0 || (size_t)ret >= svc_principal_size) { ld->ld_errno = LDAP_LOCAL_ERROR; return ld->ld_errno; } Debug2( LDAP_DEBUG_TRACE, "principal for host[%s]: '%s'\n", host, svc_principal ); input_name.value = svc_principal; input_name.length = (size_t)ret; gss_rc = gss_import_name( &minor_status, &input_name, &nt_principal, principal ); ldap_memfree( svc_principal ); if ( gss_rc != GSS_S_COMPLETE ) { return map_gsserr2ldap( ld, GSS_C_NO_OID, gss_rc, minor_status ); } return LDAP_SUCCESS; } void ldap_int_gssapi_close( LDAP *ld, LDAPConn *lc ) { if ( lc && lc->lconn_gss_ctx ) { OM_uint32 minor_status; OM_uint32 ctx_flags = 0; gss_ctx_id_t old_gss_ctx = GSS_C_NO_CONTEXT; old_gss_ctx = (gss_ctx_id_t)lc->lconn_gss_ctx; gss_inquire_context(&minor_status, old_gss_ctx, NULL, NULL, NULL, NULL, &ctx_flags, NULL, NULL); if (!( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT )) { gss_delete_sec_context( &minor_status, &old_gss_ctx, GSS_C_NO_BUFFER ); } lc->lconn_gss_ctx = GSS_C_NO_CONTEXT; if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) { /* remove wrapping layer */ sb_sasl_gssapi_remove( lc->lconn_sb ); } } } static void ldap_int_gssapi_setup( LDAP *ld, LDAPConn *lc, gss_ctx_id_t gss_ctx) { OM_uint32 minor_status; OM_uint32 ctx_flags = 0; ldap_int_gssapi_close( ld, lc ); gss_inquire_context(&minor_status, gss_ctx, NULL, NULL, NULL, NULL, &ctx_flags, NULL, NULL); lc->lconn_gss_ctx = gss_ctx; if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) { /* setup wrapping layer */ sb_sasl_gssapi_install( lc->lconn_sb, gss_ctx ); } } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_t ldap_int_gssapi_mutex; #endif static int ldap_int_gss_spnego_bind_s( LDAP *ld ) { int rc; int gss_rc; OM_uint32 minor_status; char *mechlist = NULL; char *ldapServiceName = NULL; char *dnsHostName = NULL; gss_OID_set supported_mechs = GSS_C_NO_OID_SET; int spnego_support = 0; #define __SPNEGO_OID_LENGTH 6 #define __SPNEGO_OID "\053\006\001\005\005\002" gss_OID_desc spnego_oid = {__SPNEGO_OID_LENGTH, __SPNEGO_OID}; gss_OID req_mech = GSS_C_NO_OID; gss_OID ret_mech = GSS_C_NO_OID; gss_ctx_id_t gss_ctx = GSS_C_NO_CONTEXT; gss_name_t principal = GSS_C_NO_NAME; OM_uint32 req_flags; OM_uint32 ret_flags; gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; struct berval cred, *scred = NULL; LDAP_MUTEX_LOCK( &ldap_int_gssapi_mutex ); /* get information from RootDSE entry */ rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist, &ldapServiceName, &dnsHostName); if ( rc != LDAP_SUCCESS ) { return rc; } /* check that the server supports GSS-SPNEGO */ rc = check_for_gss_spnego_support( ld, mechlist ); if ( rc != LDAP_SUCCESS ) { goto rc_error; } /* prepare new gss_ctx_id_t */ rc = guess_service_principal( ld, ldapServiceName, dnsHostName, &principal ); if ( rc != LDAP_SUCCESS ) { goto rc_error; } /* see if our gssapi library supports spnego */ gss_rc = gss_indicate_mechs( &minor_status, &supported_mechs ); if ( gss_rc != GSS_S_COMPLETE ) { goto gss_error; } gss_rc = gss_test_oid_set_member( &minor_status, &spnego_oid, supported_mechs, &spnego_support); gss_release_oid_set( &minor_status, &supported_mechs); if ( gss_rc != GSS_S_COMPLETE ) { goto gss_error; } if ( spnego_support != 0 ) { req_mech = &spnego_oid; } req_flags = ld->ld_options.ldo_gssapi_flags; req_flags |= GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; /* * loop around gss_init_sec_context() and ldap_sasl_bind_s() */ input_token.value = NULL; input_token.length = 0; gss_rc = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &gss_ctx, principal, req_mech, req_flags, 0, NULL, &input_token, &ret_mech, &output_token, &ret_flags, NULL); if ( gss_rc == GSS_S_COMPLETE ) { rc = LDAP_INAPPROPRIATE_AUTH; goto rc_error; } if ( gss_rc != GSS_S_CONTINUE_NEEDED ) { goto gss_error; } while (1) { cred.bv_val = (char *)output_token.value; cred.bv_len = output_token.length; rc = ldap_sasl_bind_s( ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred ); gss_release_buffer( &minor_status, &output_token ); if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { goto rc_error; } if ( scred ) { input_token.value = scred->bv_val; input_token.length = scred->bv_len; } else { input_token.value = NULL; input_token.length = 0; } gss_rc = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &gss_ctx, principal, req_mech, req_flags, 0, NULL, &input_token, &ret_mech, &output_token, &ret_flags, NULL); if ( scred ) { ber_bvfree( scred ); } if ( gss_rc == GSS_S_COMPLETE ) { gss_release_buffer( &minor_status, &output_token ); break; } if ( gss_rc != GSS_S_CONTINUE_NEEDED ) { goto gss_error; } } ldap_int_gssapi_setup( ld, ld->ld_defconn, gss_ctx); gss_ctx = GSS_C_NO_CONTEXT; rc = LDAP_SUCCESS; goto rc_error; gss_error: rc = map_gsserr2ldap( ld, (ret_mech != GSS_C_NO_OID ? ret_mech : req_mech ), gss_rc, minor_status ); rc_error: LDAP_MUTEX_UNLOCK( &ldap_int_gssapi_mutex ); LDAP_FREE( mechlist ); LDAP_FREE( ldapServiceName ); LDAP_FREE( dnsHostName ); gss_release_buffer( &minor_status, &output_token ); if ( gss_ctx != GSS_C_NO_CONTEXT ) { gss_delete_sec_context( &minor_status, &gss_ctx, GSS_C_NO_BUFFER ); } if ( principal != GSS_C_NO_NAME ) { gss_release_name( &minor_status, &principal ); } return rc; } int ldap_int_gssapi_config( struct ldapoptions *lo, int option, const char *arg ) { int ok = 0; switch( option ) { case LDAP_OPT_SIGN: if (!arg) { } else if (strcasecmp(arg, "on") == 0) { ok = 1; } else if (strcasecmp(arg, "yes") == 0) { ok = 1; } else if (strcasecmp(arg, "true") == 0) { ok = 1; } if (ok) { lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG; } return 0; case LDAP_OPT_ENCRYPT: if (!arg) { } else if (strcasecmp(arg, "on") == 0) { ok = 1; } else if (strcasecmp(arg, "yes") == 0) { ok = 1; } else if (strcasecmp(arg, "true") == 0) { ok = 1; } if (ok) { lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; } return 0; case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: if (!arg) { } else if (strcasecmp(arg, "on") == 0) { ok = 1; } else if (strcasecmp(arg, "yes") == 0) { ok = 1; } else if (strcasecmp(arg, "true") == 0) { ok = 1; } if (ok) { lo->ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL; } return 0; } return -1; } int ldap_int_gssapi_get_option( LDAP *ld, int option, void *arg ) { if ( ld == NULL ) return -1; switch ( option ) { case LDAP_OPT_SSPI_FLAGS: * (unsigned *) arg = (unsigned) ld->ld_options.ldo_gssapi_flags; break; case LDAP_OPT_SIGN: if ( ld->ld_options.ldo_gssapi_flags & GSS_C_INTEG_FLAG ) { * (int *) arg = (int)-1; } else { * (int *) arg = (int)0; } break; case LDAP_OPT_ENCRYPT: if ( ld->ld_options.ldo_gssapi_flags & GSS_C_CONF_FLAG ) { * (int *) arg = (int)-1; } else { * (int *) arg = (int)0; } break; case LDAP_OPT_SASL_METHOD: * (char **) arg = LDAP_STRDUP("GSS-SPNEGO"); break; case LDAP_OPT_SECURITY_CONTEXT: if ( ld->ld_defconn && ld->ld_defconn->lconn_gss_ctx ) { * (gss_ctx_id_t *) arg = (gss_ctx_id_t)ld->ld_defconn->lconn_gss_ctx; } else { * (gss_ctx_id_t *) arg = GSS_C_NO_CONTEXT; } break; case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT: if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT ) { * (int *) arg = (int)-1; } else { * (int *) arg = (int)0; } break; case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) { * (int *) arg = (int)-1; } else { * (int *) arg = (int)0; } break; default: return -1; } return 0; } int ldap_int_gssapi_set_option( LDAP *ld, int option, void *arg ) { if ( ld == NULL ) return -1; switch ( option ) { case LDAP_OPT_SSPI_FLAGS: if ( arg != LDAP_OPT_OFF ) { ld->ld_options.ldo_gssapi_flags = * (unsigned *)arg; } break; case LDAP_OPT_SIGN: if ( arg != LDAP_OPT_OFF ) { ld->ld_options.ldo_gssapi_flags |= GSS_C_INTEG_FLAG; } break; case LDAP_OPT_ENCRYPT: if ( arg != LDAP_OPT_OFF ) { ld->ld_options.ldo_gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; } break; case LDAP_OPT_SASL_METHOD: if ( arg != LDAP_OPT_OFF ) { const char *m = (const char *)arg; if ( strcmp( "GSS-SPNEGO", m ) != 0 ) { /* we currently only support GSS-SPNEGO */ return -1; } } break; case LDAP_OPT_SECURITY_CONTEXT: if ( arg != LDAP_OPT_OFF && ld->ld_defconn) { ldap_int_gssapi_setup( ld, ld->ld_defconn, (gss_ctx_id_t) arg); } break; case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT: if ( arg != LDAP_OPT_OFF ) { ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT; } break; case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: if ( arg != LDAP_OPT_OFF ) { ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL; } break; default: return -1; } return 0; } #else /* HAVE_GSSAPI */ #define ldap_int_gss_spnego_bind_s(ld) LDAP_NOT_SUPPORTED #endif /* HAVE_GSSAPI */ int ldap_gssapi_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *creds ) { return LDAP_NOT_SUPPORTED; } int ldap_gssapi_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *creds ) { if ( dn != NULL ) { return LDAP_NOT_SUPPORTED; } if ( creds != NULL ) { return LDAP_NOT_SUPPORTED; } return ldap_int_gss_spnego_bind_s(ld); }