Ejemplo n.º 1
0
static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
	ADS_STATUS status;
	struct ads_service_principal p;

	status = ads_generate_service_principal(ads, &p);
	if (!ADS_ERR_OK(status)) {
		return status;
	}

	if (ads->auth.password == NULL ||
	    ads->auth.password[0] == '\0') {
		status = ads_sasl_gssapi_do_bind(ads, p.name);
		if (ADS_ERR_OK(status)) {
			ads_free_service_principal(&p);
			return status;
		}

		DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
			  "calling kinit\n", ads_errstr(status)));
	}

	status = ADS_ERROR_KRB5(ads_kinit_password(ads));

	if (ADS_ERR_OK(status)) {
		status = ads_sasl_gssapi_do_bind(ads, p.name);
	}

	ads_free_service_principal(&p);

	return status;
}
Ejemplo n.º 2
0
/* 
   perform a LDAP/SASL/SPNEGO/KRB5 bind
*/
static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
{
	DATA_BLOB blob = data_blob_null;
	struct berval cred, *scred = NULL;
	DATA_BLOB session_key = data_blob_null;
	int rc;

	if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
		return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
	}

	rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
				     &ads->auth.tgs_expire);

	if (rc) {
		return ADS_ERROR_KRB5(rc);
	}

	/* now send the auth packet and we should be done */
	cred.bv_val = (char *)blob.data;
	cred.bv_len = blob.length;

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);

	data_blob_free(&blob);
	data_blob_free(&session_key);
	if(scred)
		ber_bvfree(scred);

	return ADS_ERROR(rc);
}
Ejemplo n.º 3
0
static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
{
	ADS_STATUS status;
	krb5_context kctx;
	krb5_error_code kerr;
	krb5_ccache kccache = NULL;
	uint32_t maj, min;

	*cred = GSS_C_NO_CREDENTIAL;

	if (!ads->auth.ccache_name) {
		return ADS_SUCCESS;
	}

	kerr = krb5_init_context(&kctx);
	if (kerr) {
		return ADS_ERROR_KRB5(kerr);
	}

	kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
	if (kerr) {
		status = ADS_ERROR_KRB5(kerr);
		goto done;
	}

	maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
	if (maj != GSS_S_COMPLETE) {
		status = ADS_ERROR_GSS(maj, min);
		goto done;
	}

	status = ADS_SUCCESS;

done:
	if (!ADS_ERR_OK(status) && kccache != NULL) {
		krb5_cc_close(kctx, kccache);
	}
	krb5_free_context(kctx);
	return status;
}
Ejemplo n.º 4
0
ADS_STATUS kerberos_set_password(const char *kpasswd_server, 
				 const char *auth_principal, const char *auth_password,
				 const char *target_principal, const char *new_password,
				 int time_offset)
{
    int ret;

    if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL))) {
	DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if (!strcmp(auth_principal, target_principal))
	return ads_krb5_chg_password(kpasswd_server, target_principal,
				     auth_password, new_password, time_offset);
    else
    	return ads_krb5_set_password(kpasswd_server, target_principal,
				     new_password, time_offset);
}
Ejemplo n.º 5
0
/* 
   this performs a SASL/SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct ads_service_principal p = {0};
	struct berval *scred=NULL;
	int rc, i;
	ADS_STATUS status;
	DATA_BLOB blob = data_blob_null;
	char *given_principal = NULL;
	char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
	bool got_kerberos_mechanism = False;
#endif
	const char *mech = NULL;

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);

	if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
		status = ADS_ERROR(rc);
		goto done;
	}

	blob = data_blob(scred->bv_val, scred->bv_len);

	ber_bvfree(scred);

#if 0
	file_save("sasl_spnego.dat", blob.data, blob.length);
#endif

	/* the server sent us the first part of the SPNEGO exchange in the negprot 
	   reply */
	if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
			OIDs[0] == NULL) {
		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
		goto done;
	}
	TALLOC_FREE(given_principal);

	/* make sure the server understands kerberos */
	for (i=0;OIDs[i];i++) {
		DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
#ifdef HAVE_KRB5
		if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
		    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
			got_kerberos_mechanism = True;
		}
#endif
		talloc_free(OIDs[i]);
	}

	status = ads_generate_service_principal(ads, &p);
	if (!ADS_ERR_OK(status)) {
		goto done;
	}

#ifdef HAVE_KRB5
	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
	    got_kerberos_mechanism) 
	{
		mech = "KRB5";

		if (ads->auth.password == NULL ||
		    ads->auth.password[0] == '\0')
		{

			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
							     CRED_MUST_USE_KERBEROS,
							     p.service, p.hostname,
							     blob);
			if (ADS_ERR_OK(status)) {
				ads_free_service_principal(&p);
				goto done;
			}

			DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
				  "calling kinit\n", ads_errstr(status)));
		}

		status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 

		if (ADS_ERR_OK(status)) {
			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
							CRED_MUST_USE_KERBEROS,
							p.service, p.hostname,
							blob);
			if (!ADS_ERR_OK(status)) {
				DEBUG(0,("kinit succeeded but "
					"ads_sasl_spnego_gensec_bind(KRB5) failed "
					"for %s/%s with user[%s] realm[%s]: %s\n",
					p.service, p.hostname,
					ads->auth.user_name,
					ads->auth.realm,
					ads_errstr(status)));
			}
		}

		/* only fallback to NTLMSSP if allowed */
		if (ADS_ERR_OK(status) || 
		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
			goto done;
		}

		DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
			 "for %s/%s with user[%s] realm[%s]: %s, "
			 "fallback to NTLMSSP\n",
			 p.service, p.hostname,
			 ads->auth.user_name,
			 ads->auth.realm,
			 ads_errstr(status)));
	}
#endif

	/* lets do NTLMSSP ... this has the big advantage that we don't need
	   to sync clocks, and we don't rely on special versions of the krb5 
	   library for HMAC_MD4 encryption */
	mech = "NTLMSSP";
	status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
					     CRED_DONT_USE_KERBEROS,
					     p.service, p.hostname,
					     data_blob_null);
done:
	if (!ADS_ERR_OK(status)) {
		DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
			 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
			  p.service, p.hostname,
			  ads->auth.user_name,
			  ads->auth.realm,
			  ads_errstr(status)));
	}
	ads_free_service_principal(&p);
	TALLOC_FREE(frame);
	if (blob.data != NULL) {
		data_blob_free(&blob);
	}
	return status;
}
Ejemplo n.º 6
0
/* 
   this performs a SASL/SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
	struct berval *scred=NULL;
	int rc, i;
	ADS_STATUS status;
	DATA_BLOB blob;
	char *given_principal = NULL;
	char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
	bool got_kerberos_mechanism = False;
#endif

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);

	if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
		status = ADS_ERROR(rc);
		goto failed;
	}

	blob = data_blob(scred->bv_val, scred->bv_len);

	ber_bvfree(scred);

#if 0
	file_save("sasl_spnego.dat", blob.data, blob.length);
#endif

	/* the server sent us the first part of the SPNEGO exchange in the negprot 
	   reply */
	if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
		data_blob_free(&blob);
		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
		goto failed;
	}
	data_blob_free(&blob);

	/* make sure the server understands kerberos */
	for (i=0;OIDs[i];i++) {
		DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
#ifdef HAVE_KRB5
		if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
		    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
			got_kerberos_mechanism = True;
		}
#endif
		talloc_free(OIDs[i]);
	}
	DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));

#ifdef HAVE_KRB5
	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
	    got_kerberos_mechanism) 
	{
		struct ads_service_principal p;

		status = ads_generate_service_principal(ads, given_principal, &p);
		TALLOC_FREE(given_principal);
		if (!ADS_ERR_OK(status)) {
			return status;
		}

		status = ads_sasl_spnego_krb5_bind(ads, &p);
		if (ADS_ERR_OK(status)) {
			ads_free_service_principal(&p);
			return status;
		}

		DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
			  "calling kinit\n", ads_errstr(status)));

		status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 

		if (ADS_ERR_OK(status)) {
			status = ads_sasl_spnego_krb5_bind(ads, &p);
			if (!ADS_ERR_OK(status)) {
				DEBUG(0,("kinit succeeded but "
					"ads_sasl_spnego_krb5_bind failed: %s\n",
					ads_errstr(status)));
			}
		}

		ads_free_service_principal(&p);

		/* only fallback to NTLMSSP if allowed */
		if (ADS_ERR_OK(status) || 
		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
			return status;
		}
	} else
#endif
	{
		TALLOC_FREE(given_principal);
	}

	/* lets do NTLMSSP ... this has the big advantage that we don't need
	   to sync clocks, and we don't rely on special versions of the krb5 
	   library for HMAC_MD4 encryption */
	return ads_sasl_spnego_ntlmssp_bind(ads);

failed:
	return status;
}
Ejemplo n.º 7
0
static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
{
	ADS_STATUS status;
	krb5_context kctx;
	krb5_error_code kerr;
	krb5_ccache kccache = NULL;
	uint32_t maj, min;

	*cred = GSS_C_NO_CREDENTIAL;

	if (!ads->auth.ccache_name) {
		return ADS_SUCCESS;
	}

	kerr = krb5_init_context(&kctx);
	if (kerr) {
		return ADS_ERROR_KRB5(kerr);
	}

#ifdef HAVE_GSS_KRB5_IMPORT_CRED
	kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
	if (kerr) {
		status = ADS_ERROR_KRB5(kerr);
		goto done;
	}

	maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
	if (maj != GSS_S_COMPLETE) {
		status = ADS_ERROR_GSS(maj, min);
		goto done;
	}
#else
	/* We need to fallback to overriding the default creds.
	 * This operation is not thread safe as it changes the process
	 * environment variable, but we do not have any better option
	 * with older kerberos libraries */
	{
		const char *oldccname = NULL;

		oldccname = getenv("KRB5CCNAME");
		setenv("KRB5CCNAME", ads->auth.ccache_name, 1);

		maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
				       NULL, GSS_C_INITIATE, cred, NULL, NULL);

		if (oldccname) {
			setenv("KRB5CCNAME", oldccname, 1);
		} else {
			unsetenv("KRB5CCNAME");
		}

		if (maj != GSS_S_COMPLETE) {
			status = ADS_ERROR_GSS(maj, min);
			goto done;
		}
	}
#endif

	status = ADS_SUCCESS;

done:
	if (!ADS_ERR_OK(status) && kccache != NULL) {
		krb5_cc_close(kctx, kccache);
	}
	krb5_free_context(kctx);
	return status;
}
Ejemplo n.º 8
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, 
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	const char *realm = NULL;
	unsigned int realm_len = 0;
	krb5_creds creds, *credsp = NULL;
	krb5_ccache ccache = NULL;

	ZERO_STRUCT(creds);
	
	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	ret = krb5_cc_get_principal(context, ccache, &creds.client);
	if (ret) {
		krb5_cc_close(context, ccache);
                krb5_free_context(context);
		DEBUG(1,("Failed to get principal from ccache (%s)\n",
			 error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	realm = smb_krb5_principal_get_realm(context, creds.client);
	realm_len = strlen(realm);
	ret = krb5_build_principal(context,
				   &creds.server,
				   realm_len,
				   realm, "kadmin", "changepw", NULL);

	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
	        krb5_free_principal(context, creds.server);
	        krb5_free_context(context);
		DEBUG(1,("krb5_build_prinipal_ext (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
	        krb5_free_principal(context, creds.server);
	        krb5_free_context(context);
		DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	/* we might have to call krb5_free_creds(...) from now on ... */

	aret = do_krb5_kpasswd_request(context, kdc_host,
				       KRB5_KPASSWD_VERS_SETPW,
				       credsp, princ, newpw);

	krb5_free_creds(context, credsp);
	krb5_free_principal(context, creds.client);
        krb5_free_principal(context, creds.server);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}
Ejemplo n.º 9
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    const char *realm = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);
    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    aret = do_krb5_kpasswd_request(context, kdc_host,
				   KRB5_KPASSWD_VERS_CHANGEPW,
				   &creds, principal, newpw);

    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
Ejemplo n.º 10
0
static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
					  const char *kdc_host,
					  uint16 pversion,
					  krb5_creds *credsp,
					  const char *princ,
					  const char *newpw)
{
	krb5_auth_context auth_context = NULL;
	krb5_data ap_req, chpw_req, chpw_rep;
	int ret, sock;
	socklen_t addr_len;
	struct sockaddr_storage remote_addr, local_addr;
	struct sockaddr_storage addr;
	krb5_address local_kaddr, remote_kaddr;
	bool use_tcp = False;


	if (!interpret_string_addr(&addr, kdc_host, 0)) {
	}

	ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
				   NULL, credsp, &ap_req);
	if (ret) {
		DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	do {

		if (!use_tcp) {

			sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
			if (sock == -1) {
				int rc = errno;
				SAFE_FREE(ap_req.data);
				krb5_auth_con_free(context, auth_context);
				DEBUG(1,("failed to open kpasswd socket to %s "
					 "(%s)\n", kdc_host, strerror(errno)));
				return ADS_ERROR_SYSTEM(rc);
			}
		} else {
			NTSTATUS status;
			status = open_socket_out(&addr, DEFAULT_KPASSWD_PORT,
						 LONG_CONNECT_TIMEOUT, &sock);
			if (!NT_STATUS_IS_OK(status)) {
				SAFE_FREE(ap_req.data);
				krb5_auth_con_free(context, auth_context);
				DEBUG(1,("failed to open kpasswd socket to %s "
					 "(%s)\n", kdc_host,
					 nt_errstr(status)));
				return ADS_ERROR_NT(status);
			}
		}

		addr_len = sizeof(remote_addr);
		if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("getpeername() failed (%s)\n", error_message(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
		addr_len = sizeof(local_addr);
		if (getsockname(sock, (struct sockaddr *)&local_addr, &addr_len) != 0) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("getsockname() failed (%s)\n", error_message(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
		if (!setup_kaddr(&remote_kaddr, &remote_addr) ||
				!setup_kaddr(&local_kaddr, &local_addr)) {
			DEBUG(1,("do_krb5_kpasswd_request: "
				"Failed to setup addresses.\n"));
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			errno = EINVAL;
			return ADS_ERROR_SYSTEM(EINVAL);
		}

		ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
		if (ret) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}

		ret = build_kpasswd_request(pversion, context, auth_context, &ap_req,
					  princ, newpw, use_tcp, &chpw_req);
		if (ret) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}

		ret = write(sock, chpw_req.data, chpw_req.length); 

		if (ret != chpw_req.length) {
			close(sock);
			SAFE_FREE(chpw_req.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
	
		SAFE_FREE(chpw_req.data);
	
		chpw_rep.length = 1500;
		chpw_rep.data = (char *) SMB_MALLOC(chpw_rep.length);
		if (!chpw_rep.data) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
			errno = ENOMEM;
			return ADS_ERROR_SYSTEM(errno);
		}
	
		ret = read(sock, chpw_rep.data, chpw_rep.length);
		if (ret < 0) {
			close(sock);
			SAFE_FREE(chpw_rep.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
	
		close(sock);
		chpw_rep.length = ret;
	
		ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
		if (ret) {
			SAFE_FREE(chpw_rep.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", 
				 error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	
		ret = parse_setpw_reply(context, use_tcp, auth_context, &chpw_rep);
		SAFE_FREE(chpw_rep.data);
	
		if (ret) {
			
			if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
				DEBUG(5, ("Trying setpw with TCP!!!\n"));
				use_tcp = True;
				continue;
			}

			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("parse_setpw_reply failed (%s)\n", 
				 error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	
		SAFE_FREE(ap_req.data);
		krb5_auth_con_free(context, auth_context);
	} while ( ret );

	return ADS_SUCCESS;
}
Ejemplo n.º 11
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *principal,
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	krb5_principal princ = NULL;
	krb5_ccache ccache = NULL;
	int result_code;
	krb5_data result_code_string = { 0 };
	krb5_data result_string = { 0 };

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	if (principal) {
		ret = smb_krb5_parse_name(context, principal, &princ);
		if (ret) {
			krb5_free_context(context);
			DEBUG(1, ("Failed to parse %s (%s)\n", principal,
				  error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
		krb5_free_principal(context, princ);
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	ret = krb5_set_password_using_ccache(context,
					     ccache,
					     discard_const_p(char, newpw),
					     princ,
					     &result_code,
					     &result_code_string,
					     &result_string);
	if (ret) {
		DEBUG(1, ("krb5_set_password failed (%s)\n", error_message(ret)));
		aret = ADS_ERROR_KRB5(ret);
		goto done;
	}

	if (result_code != KRB5_KPASSWD_SUCCESS) {
		ret = kpasswd_err_to_krb5_err(result_code);
		DEBUG(1, ("krb5_set_password failed (%s)\n", error_message(ret)));
		aret = ADS_ERROR_KRB5(ret);
		goto done;
	}

	aret = ADS_SUCCESS;

done:
	kerberos_free_data_contents(context, &result_code_string);
	kerberos_free_data_contents(context, &result_string);
	krb5_free_principal(context, princ);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}
Ejemplo n.º 12
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    char *realm = NULL;
    int result_code;
    krb5_data result_code_string = { 0 };
    krb5_data result_string = { 0 };
    smb_krb5_addresses *addr = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);

    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    /* note that heimdal will fill in the local addresses if the addresses
     * in the creds_init_opt are all empty and then later fail with invalid
     * address, sending our local netbios krb5 address - just like windows
     * - avoids this - gd */
    ret = smb_krb5_gen_netbios_krb5_address(&addr, lp_netbios_name());
    if (ret) {
        krb5_free_principal(context, princ);
        krb5_free_context(context);
        return ADS_ERROR_KRB5(ret);
    }
    krb5_get_init_creds_opt_set_address_list(&opts, addr->addrs);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	free(realm);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    free(realm);
    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    ret = krb5_change_password(context,
			       &creds,
			       discard_const_p(char, newpw),
			       &result_code,
			       &result_code_string,
			       &result_string);
    if (ret) {
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    if (result_code != KRB5_KPASSWD_SUCCESS) {
	ret = kpasswd_err_to_krb5_err(result_code);
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    aret = ADS_SUCCESS;

done:
    kerberos_free_data_contents(context, &result_code_string);
    kerberos_free_data_contents(context, &result_string);
    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
Ejemplo n.º 13
0
/* this performs a SASL/gssapi bind
   we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
   is very dependent on correctly configured DNS whereas
   this routine is much less fragile
   see RFC2078 and RFC2222 for details
*/
static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
	uint32 minor_status;
	gss_name_t serv_name;
	gss_buffer_desc input_name;
	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
	gss_OID mech_type = GSS_C_NULL_OID;
	gss_buffer_desc output_token, input_token;
	uint32 ret_flags, conf_state;
	struct berval cred;
	struct berval *scred = NULL;
	int i=0;
	int gss_rc, rc;
	uint8 *p;
	uint32 max_msg_size = 0;
	char *sname = NULL;
	ADS_STATUS status;
	krb5_principal principal = NULL;
	krb5_context ctx = NULL;
	krb5_enctype enc_types[] = {
#ifdef ENCTYPE_ARCFOUR_HMAC
			ENCTYPE_ARCFOUR_HMAC,
#endif
			ENCTYPE_DES_CBC_MD5,
			ENCTYPE_NULL};
	gss_OID_desc nt_principal = 
	{10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};

	/* we need to fetch a service ticket as the ldap user in the
	   servers realm, regardless of our realm */
	asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);

	initialize_krb5_error_table();
	status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		return status;
	}
	status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		krb5_free_context(ctx);	
		return status;
	}
	status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
	if (!ADS_ERR_OK(status)) {
		SAFE_FREE(sname);
		krb5_free_context(ctx);	
		return status;
	}

	input_name.value = &principal;
	input_name.length = sizeof(principal);

	gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);

	/*
	 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
	 * to point to the *address* of the krb5_principal, and the gss libraries
	 * to a shallow copy of the krb5_principal pointer - so we need to keep
	 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
	 * Just one more way in which MIT engineers screwed me over.... JRA.
	 */

	SAFE_FREE(sname);

	if (gss_rc) {
		krb5_free_principal(ctx, principal);
		krb5_free_context(ctx);	
		return ADS_ERROR_GSS(gss_rc, minor_status);
	}

	input_token.value = NULL;
	input_token.length = 0;

	for (i=0; i < MAX_GSS_PASSES; i++) {
		gss_rc = gss_init_sec_context(&minor_status,
					  GSS_C_NO_CREDENTIAL,
					  &context_handle,
					  serv_name,
					  mech_type,
					  GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
					  0,
					  NULL,
					  &input_token,
					  NULL,
					  &output_token,
					  &ret_flags,
					  NULL);

		if (input_token.value) {
			gss_release_buffer(&minor_status, &input_token);
		}

		if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		cred.bv_val = (char *)output_token.value;
		cred.bv_len = output_token.length;

		rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL, 
				      &scred);
		if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ADS_ERROR(rc);
			goto failed;
		}

		if (output_token.value) {
			gss_release_buffer(&minor_status, &output_token);
		}

		if (scred) {
			input_token.value = scred->bv_val;
			input_token.length = scred->bv_len;
		} else {
			input_token.value = NULL;
			input_token.length = 0;
		}

		if (gss_rc == 0) break;
	}

	gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
			    (int *)&conf_state,NULL);
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	gss_release_buffer(&minor_status, &input_token);

	p = (uint8 *)output_token.value;

#if 0
	file_save("sasl_gssapi.dat", output_token.value, output_token.length);
#endif

	if (p) {
		max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
	}

	gss_release_buffer(&minor_status, &output_token);

	output_token.value = SMB_MALLOC(strlen(ads->config.bind_path) + 8);
	p = (uint8 *)output_token.value;

	*p++ = 1; /* no sign & seal selection */
	/* choose the same size as the server gave us */
	*p++ = max_msg_size>>16;
	*p++ = max_msg_size>>8;
	*p++ = max_msg_size;
	snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
	p += strlen((const char *)p);

	output_token.length = PTR_DIFF(p, output_token.value);

	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
			  &output_token, (int *)&conf_state,
			  &input_token);
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	free(output_token.value);

	cred.bv_val = (char *)input_token.value;
	cred.bv_len = input_token.length;

	rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL, 
			      &scred);
	status = ADS_ERROR(rc);

	gss_release_buffer(&minor_status, &input_token);

failed:

	gss_release_name(&minor_status, &serv_name);
	if (context_handle != GSS_C_NO_CONTEXT)
		gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
	krb5_free_principal(ctx, principal);
	krb5_free_context(ctx);	

	if(scred)
		ber_bvfree(scred);
	return status;
}
Ejemplo n.º 14
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, 
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	krb5_principal principal = NULL;
	char *princ_name = NULL;
	char *realm = NULL;
	krb5_creds creds, *credsp = NULL;
#if KRB5_PRINC_REALM_RETURNS_REALM
	krb5_realm orig_realm;
#else
	krb5_data orig_realm;
#endif
	krb5_ccache ccache = NULL;

	ZERO_STRUCT(creds);
	
	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	realm = strchr_m(princ, '@');
	if (!realm) {
		krb5_cc_close(context, ccache);
	        krb5_free_context(context);
		DEBUG(1,("Failed to get realm\n"));
		return ADS_ERROR_KRB5(-1);
	}
	realm++;

	asprintf(&princ_name, "kadmin/changepw@%s", realm);
	ret = smb_krb5_parse_name(context, princ_name, &creds.server);
	if (ret) {
		krb5_cc_close(context, ccache);
                krb5_free_context(context);
		DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	/* parse the principal we got as a function argument */
	ret = smb_krb5_parse_name(context, princ, &principal);
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.server);
                krb5_free_context(context);
		DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
		free(princ_name);
		return ADS_ERROR_KRB5(ret);
	}

	free(princ_name);

	/* The creds.server principal takes ownership of this memory.
		Remember to set back to original value before freeing. */
	orig_realm = *krb5_princ_realm(context, creds.server);
	krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal));
	
	ret = krb5_cc_get_principal(context, ccache, &creds.client);
	if (ret) {
		krb5_cc_close(context, ccache);
		krb5_princ_set_realm(context, creds.server, &orig_realm);
	        krb5_free_principal(context, creds.server);
	        krb5_free_principal(context, principal);
                krb5_free_context(context);
		DEBUG(1,("Failed to get principal from ccache (%s)\n", 
			 error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
		krb5_princ_set_realm(context, creds.server, &orig_realm);
	        krb5_free_principal(context, creds.server);
	        krb5_free_principal(context, principal);
	        krb5_free_context(context);
		DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	/* we might have to call krb5_free_creds(...) from now on ... */

	aret = do_krb5_kpasswd_request(context, kdc_host,
				       KRB5_KPASSWD_VERS_SETPW,
				       credsp, princ, newpw);

	krb5_free_creds(context, credsp);
	krb5_free_principal(context, creds.client);
	krb5_princ_set_realm(context, creds.server, &orig_realm);
        krb5_free_principal(context, creds.server);
	krb5_free_principal(context, principal);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}