SPECS/openldap/openldap-2.4.40-gssapi-1.patch
f4d17450
 --- openldap-2.4.40/include/ldap.h	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/include/ldap.h	2015-01-21 15:59:24.000000000 -0800
 @@ -196,6 +196,7 @@ LDAP_BEGIN_DECL
  /* OpenLDAP GSSAPI options */
  #define LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT      0x6200
  #define LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL   0x6201
 +#define LDAP_OPT_X_GSSAPI_CREDENTIAL_HANDLE        0x6202
  
  /*
   * OpenLDAP per connection tcp-keepalive settings
 @@ -1238,6 +1239,15 @@ ldap_parse_sasl_bind_result LDAP_P((
  	struct berval	**servercredp,
  	int				freeit ));
  
 +/*
 + * in gssapi.c:
 + */
 +LDAP_F( int )
 +ldap_gssapi_bind_s LDAP_P((
 +	LDAP  *ld,
 +	LDAP_CONST char *dn,
 +	LDAP_CONST char *creds));
 +
  #if LDAP_DEPRECATED
  /*
   * in bind.c:
 diff -rupN openldap-2.4.40/libraries/libldap/gssapi.c openldap-2.4.40-1/libraries/libldap/gssapi.c
 --- openldap-2.4.40/libraries/libldap/gssapi.c	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/libraries/libldap/gssapi.c	2015-01-21 17:32:47.000000000 -0800
 @@ -199,6 +199,7 @@ sb_sasl_gssapi_encode(
  	if ( conf_req_flag && conf_state == 0 ) {
  		ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
  				"sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our gss_wrap()\n" );
 +		gss_release_buffer(&minor_status, &wrapped);
  		return -1;
  	}
  
 @@ -211,6 +212,7 @@ sb_sasl_gssapi_encode(
  		ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
  				"sb_sasl_gssapi_encode: failed to grow the buffer to %lu bytes\n",
  				pkt_len );
 +		gss_release_buffer(&minor_status, &wrapped);
  		return -1;
  	}
  
 @@ -240,12 +242,13 @@ sb_sasl_gssapi_decode(
  	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_buffer_desc unwrapped = {0}, 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_int_t result = 0;
  
  	wrapped.value	= src->buf_base + 4;
  	wrapped.length	= src->buf_end - 4;
 @@ -272,13 +275,15 @@ sb_sasl_gssapi_decode(
  		ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
  				"sb_sasl_gssapi_decode: failed to decode packet: %s\n",
  				gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) );
 -		return -1;
 +		result = -1;
 +		goto cleanup;
  	}
  
  	if ( conf_req_flag && conf_state == 0 ) {
  		ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
  				"sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our peer\n" );
 -		return -1;
 +		result = -1;
 +		goto cleanup;
  	}
  
  	/* Grow the packet buffer if neccessary */
 @@ -288,7 +293,8 @@ sb_sasl_gssapi_decode(
  		ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
  				"sb_sasl_gssapi_decode: failed to grow the buffer to %lu bytes\n",
  				unwrapped.length );
 -		return -1;
 +		result = -1;
 +		goto cleanup;
  	}
  
  	dst->buf_end = unwrapped.length;
 @@ -298,9 +304,11 @@ sb_sasl_gssapi_decode(
  	/* copy the wrapped blob to the right location */
  	memcpy(b, unwrapped.value, unwrapped.length);
  
 +cleanup:
 +
  	gss_release_buffer(&minor_status, &unwrapped);
  
 -	return 0;
 +	return result;
  }
  
  static void
 @@ -512,15 +520,28 @@ guess_service_principal(
  	int gss_rc;
  	int ret;
  	size_t svc_principal_size;
 +	size_t dns_domain_name_size;
  	char *svc_principal = NULL;
  	const char *principal_fmt = NULL;
 -	const char *str = NULL;
  	const char *givenstr = NULL;
 +	char *dns_domain_name = NULL;
 +	char *name = NULL;
  	const char *ignore = "not_defined_in_RFC4178@please_ignore";
  	int allow_remote = 0;
  
  	if (ldapServiceName) {
  		givenstr = strchr(ldapServiceName, ':');
 +
 +		dns_domain_name_size = (size_t)((givenstr - ldapServiceName) + 1);
 +		dns_domain_name = (char*) ldap_memalloc(dns_domain_name_size * sizeof(char));
 +		if (!dns_domain_name) {
 +			ld->ld_errno = LDAP_NO_MEMORY;
 +			return ld->ld_errno;
 +		}
 +
 +		strncpy(dns_domain_name, ldapServiceName, (dns_domain_name_size - 1));
 +		dns_domain_name[dns_domain_name_size - 1] = '\0';
 +
  		if (givenstr && givenstr[1]) {
  			givenstr++;
  			if (strcmp(givenstr, ignore) == 0) {
 @@ -535,20 +556,42 @@ guess_service_principal(
  		allow_remote = 1;
  	}
  
 +	/* Try to figure out correct service principal form given
 +	   available information */
  	if (allow_remote && givenstr) {
  		principal_fmt = "%s";
  		svc_principal_size = strlen(givenstr) + 1;
 -		str = givenstr;
 +		name = strdup(givenstr);
 +		if (!name) {
 +			ld->ld_errno = LDAP_NO_MEMORY;
 +			return ld->ld_errno;
 +		}
  
 -	} else if (allow_remote && dnsHostName) {
 +	} else if (dnsHostName) {
  		principal_fmt = "ldap/%s";
 -		svc_principal_size = STRLENOF("ldap/") + strlen(dnsHostName) + 1;
 -		str = dnsHostName;
 +        svc_principal_size = strlen(dnsHostName) + strlen(dns_domain_name) +
 +                                     strlen(principal_fmt);
 +                                     
 +        /* svc_principal_size is actually a bit more than really needed, but
 +           let's use it to avoid calculating yet another size */
 +        name = (char*) ldap_memalloc(svc_principal_size * sizeof(char));
 +        if (!name) {
 +            ld->ld_errno = LDAP_NO_MEMORY;
 +            return ld->ld_errno;
 +        }               
 +
 +        snprintf(name, svc_principal_size, "%s/%s",
 +             dnsHostName, dns_domain_name);
  
  	} else {
  		principal_fmt = "ldap/%s";
 -		svc_principal_size = STRLENOF("ldap/") + strlen(host) + 1;
 -		str = host;
 +        svc_principal_size = strlen(dns_domain_name) + strlen(principal_fmt);
 +        name = strdup(dns_domain_name);
 +        if (!name) {
 +            ld->ld_errno = LDAP_NO_MEMORY;
 +            return ld->ld_errno;
 +        }
 +
  	}
  
  	svc_principal = (char*) ldap_memalloc(svc_principal_size * sizeof(char));
 @@ -557,8 +600,8 @@ guess_service_principal(
  		return ld->ld_errno;
  	}
  
 -	ret = snprintf( svc_principal, svc_principal_size, principal_fmt, str );
 -	if (ret < 0 || (size_t)ret >= svc_principal_size) {
 +	ret = snprintf( svc_principal, svc_principal_size, principal_fmt, name );
 +	if (ret < 0 || (size_t)(ret+1) >= svc_principal_size) {
  		ld->ld_errno = LDAP_LOCAL_ERROR;
  		return ld->ld_errno;
  	}
 @@ -571,6 +614,8 @@ guess_service_principal(
  
  	gss_rc = gss_import_name( &minor_status, &input_name, &nt_principal, principal );
  	ldap_memfree( svc_principal );
 +	ldap_memfree(dns_domain_name);
 +	ldap_memfree(name);
  	if ( gss_rc != GSS_S_COMPLETE ) {
  		return map_gsserr2ldap( ld, GSS_C_NO_OID, gss_rc, minor_status );
  	}
 @@ -658,6 +703,7 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
  	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_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
  	gss_name_t principal = GSS_C_NO_NAME;
  	OM_uint32 req_flags;
  	OM_uint32 ret_flags;
 @@ -670,7 +716,7 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
  	rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist,
  					     &ldapServiceName, &dnsHostName);
  	if ( rc != LDAP_SUCCESS ) {
 -		return rc;
 +		goto rc_error;
  	}
  
  	/* check that the server supports GSS-SPNEGO */
 @@ -708,8 +754,16 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
  	 */
  	input_token.value = NULL;
  	input_token.length = 0;
 +
 +	/*
 +	 * Set credentials handle if it's been set (e.g. for gss-ntlm authentication)
 +	 */
 +	if (ld->ld_options.gssapi_cred_handle) {
 +		gss_cred = (gss_cred_id_t)ld->ld_options.gssapi_cred_handle;
 +	}
 +
  	gss_rc = gss_init_sec_context(&minor_status,
 -				      GSS_C_NO_CREDENTIAL,
 +				      gss_cred,
  				      &gss_ctx,
  				      principal,
  				      req_mech,
 @@ -746,7 +800,7 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
  		}
  
  		gss_rc = gss_init_sec_context(&minor_status,
 -					      GSS_C_NO_CREDENTIAL,
 +					      gss_cred,
  					      &gss_ctx,
  					      principal,
  					      req_mech,
 @@ -896,6 +950,14 @@ ldap_int_gssapi_get_option( LDAP *ld, in
  		}
  		break;
  
 +	case LDAP_OPT_X_GSSAPI_CREDENTIAL_HANDLE:
 +		if ( ld->ld_options.gssapi_cred_handle ) {
 +			* (void**)arg = ld->ld_options.gssapi_cred_handle;
 +		} else {
 +			* (void**)arg = GSS_C_NO_CREDENTIAL;
 +		}
 +		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;
 @@ -961,6 +1023,12 @@ ldap_int_gssapi_set_option( LDAP *ld, in
  		}
  		break;
  
 +	case LDAP_OPT_X_GSSAPI_CREDENTIAL_HANDLE:
 +		if ( arg != LDAP_OPT_OFF) {
 +			ld->ld_options.gssapi_cred_handle = 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;
 diff -rupN openldap-2.4.40/libraries/libldap/ldap-int.h openldap-2.4.40-1/libraries/libldap/ldap-int.h
 --- openldap-2.4.40/libraries/libldap/ldap-int.h	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/libraries/libldap/ldap-int.h	2015-01-21 16:03:49.000000000 -0800
 @@ -283,6 +283,7 @@ struct ldapoptions {
  #define LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT	0x0001
  #define LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL	0x0002
  	unsigned ldo_gssapi_options;
 +        void *gssapi_cred_handle;
  #define LDAP_LDO_GSSAPI_NULLARG ,0,0
  #else
  #define LDAP_LDO_GSSAPI_NULLARG
 diff -rupN openldap-2.4.40/libraries/libldap/os-ip.c openldap-2.4.40-1/libraries/libldap/os-ip.c
 --- openldap-2.4.40/libraries/libldap/os-ip.c	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/libraries/libldap/os-ip.c	2015-01-21 16:07:47.000000000 -0800
 @@ -550,6 +550,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *
  	char serv[7];
  	int err;
  	struct addrinfo hints, *res, *sai;
 +        int retry;
  #else
  	int i;
  	int use_hp = 0;
 @@ -605,7 +606,22 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *
  	/* most getaddrinfo(3) use non-threadsafe resolver libraries */
  	LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex);
  
 +	/* The hostname may be an IP address, depending on what is stored in
 +	 * the configuration file. To avoid issuing any unnecessary network
 +	 * traffic, try looking it up as a numerical host first.
 +	 */
 +	hints.ai_flags |= AI_NUMERICHOST;
  	err = getaddrinfo( host, serv, &hints, &res );
 +	retry = (err == EAI_NONAME);
 +#ifdef EAI_NODATA
 +	if (err == EAI_NODATA) {
 +		retry = 1;
 +	}
 +#endif
 +	if (retry) {
 +		hints.ai_flags &= ~AI_NUMERICHOST;
 +		err = getaddrinfo( host, serv, &hints, &res );
 +	}
  
  	LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex);
  
 diff -rupN openldap-2.4.40/libraries/libldap/request.c openldap-2.4.40-1/libraries/libldap/request.c
 --- openldap-2.4.40/libraries/libldap/request.c	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/libraries/libldap/request.c	2015-01-21 16:19:26.000000000 -0800
 @@ -779,6 +779,7 @@ ldap_free_connection( LDAP *ld, LDAPConn
  
  		if ( lc->lconn_ber != NULL ) {
  			ber_free( lc->lconn_ber, 1 );
 +			lc->lconn_ber = NULL;
  		}
  
  		ldap_int_sasl_close( ld, lc );
 diff -rupN openldap-2.4.40/libraries/libldap/result.c openldap-2.4.40-1/libraries/libldap/result.c
 --- openldap-2.4.40/libraries/libldap/result.c	2014-09-18 18:48:49.000000000 -0700
 +++ openldap-2.4.40-1/libraries/libldap/result.c	2015-01-21 16:16:46.000000000 -0800
 @@ -692,6 +692,8 @@ nextresp2:
  		char		*lr_res_error = NULL;
  
  		tmpber = *ber; 	/* struct copy */
 +		lr->lr_res_matched = NULL;
 +		lr_res_error = NULL;
  		if ( ber_scanf( &tmpber, "{eAA", &lderr,
  				&lr->lr_res_matched, &lr_res_error )
  				!= LBER_ERROR )
 @@ -789,6 +791,12 @@ nextresp2:
  				lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
  			}
  		}
 +		else
 +		{
 +			/* Free lr_res_matched in case it was allocated before
 +			 * ber_scanf found an error */
 +			LDAP_FREE(lr->lr_res_matched);
 +		}
  
  		/* in any case, don't leave any lr_res_error 'round */
  		if ( lr_res_error ) {
 @@ -881,6 +889,9 @@ nextresp2:
  
  				if ( lr != &dummy_lr ) {
  					ldap_return_request( ld, lr, 1 );
 +				} else {
 +					LDAP_FREE(lr->lr_res_error);
 +					lr->lr_res_error = NULL;
  				}
  				lr = NULL;
  			}
 @@ -962,7 +973,8 @@ nextresp2:
  
  			/* need to return -1, because otherwise
  			 * a valid result is expected */
 -			ld->ld_errno = lderr;
 +			ber_free(ber, 1);
 +			ld->ld_errno = LDAP_CONNECT_ERROR;
  			return -1;
  		}
  	}