Exemple #1
0
/**
 * Obtain the client principal for this credentials context.
 * @param cred credentials context
 * @retval The username set on this context.
 * @note Return value will never be NULL except by programmer error.
 */
_PUBLIC_ const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
{
	if (cred->machine_account_pending) {
		cli_credentials_set_machine_account(cred,
					cred->machine_account_pending_lp_ctx);
	}

	if (cred->principal_obtained == CRED_CALLBACK && 
	    !cred->callback_running) {
	    	cred->callback_running = true;
		cred->principal = cred->principal_cb(cred);
	    	cred->callback_running = false;
		if (cred->principal_obtained == CRED_CALLBACK) {
			cred->principal_obtained = CRED_CALLBACK_RESULT;
			cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
		}
	}

	if (cred->principal_obtained < cred->username_obtained
	    || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
		if (cred->domain_obtained > cred->realm_obtained) {
			*obtained = MIN(cred->domain_obtained, cred->username_obtained);
			return talloc_asprintf(mem_ctx, "%s@%s", 
					       cli_credentials_get_username(cred),
					       cli_credentials_get_domain(cred));
		} else {
			*obtained = MIN(cred->domain_obtained, cred->username_obtained);
			return talloc_asprintf(mem_ctx, "%s@%s", 
					       cli_credentials_get_username(cred),
					       cli_credentials_get_realm(cred));
		}
	}
	*obtained = cred->principal_obtained;
	return talloc_strdup(mem_ctx, cred->principal);
}
/**
 * Fill in credentials for a particular principal, from the secrets database.
 *
 * @param cred Credentials structure to fill in
 * @retval NTSTATUS error detailing any failure
 */
_PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
					      struct loadparm_context *lp_ctx,
					      const char *serviceprincipal)
{
	NTSTATUS status;
	char *filter;
	char *error_string = NULL;
	/* Bleh, nasty recursion issues: We are setting a machine
	 * account here, so we don't want the 'pending' flag around
	 * any more */
	cred->machine_account_pending = false;
	filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH,
				 cli_credentials_get_realm(cred),
				 cli_credentials_get_domain(cred),
				 serviceprincipal);
	status = cli_credentials_set_secrets_lct(cred, lp_ctx, NULL,
					     SECRETS_PRINCIPALS_DN, filter,
					     0, NULL, &error_string);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not find %s principal in secrets database: %s: %s\n",
			  serviceprincipal, nt_errstr(status),
			  error_string ? error_string : "<no error>"));
	}
	return status;
}
/**
 * Fill in credentials for the machine trust account, from the secrets database.
 * 
 * @param cred Credentials structure to fill in
 * @retval NTSTATUS error detailing any failure
 */
NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred)
{
	char *filter;
	/* Bleh, nasty recursion issues: We are setting a machine
	 * account here, so we don't want the 'pending' flag around
	 * any more */
	cred->machine_account_pending = False;
	filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
				       cli_credentials_get_realm(cred),
				       cli_credentials_get_domain(cred));
	return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
					   filter);
}
Exemple #4
0
static bool test_parse_string(struct torture_context *tctx)
{
	struct cli_credentials *creds = cli_credentials_init_anon(tctx);

	/* anonymous */
	cli_credentials_parse_string(creds, "%", CRED_SPECIFIED);

	torture_assert_str_equal(tctx, cli_credentials_get_domain(creds),
				 "", "domain");

	torture_assert_str_equal(tctx, cli_credentials_get_username(creds),
				 "", "username");

	torture_assert(tctx, cli_credentials_get_password(creds) == NULL,
				 "password");

	/* username + password */
	cli_credentials_parse_string(creds, "somebody%secret", 
				     CRED_SPECIFIED);

	torture_assert_str_equal(tctx, cli_credentials_get_domain(creds),
				 "", "domain");

	torture_assert_str_equal(tctx, cli_credentials_get_username(creds),
				 "somebody", "username");

	torture_assert_str_equal(tctx, cli_credentials_get_password(creds),
				 "secret", "password");

	/* principal */
	cli_credentials_parse_string(creds, "prin@styx", 
				     CRED_SPECIFIED);

	torture_assert_str_equal(tctx, cli_credentials_get_realm(creds),
				 "STYX", "realm");

	torture_assert_str_equal(tctx, 
				 cli_credentials_get_principal(creds, tctx),
				 "prin@styx", "principal");

	return true;
}
Exemple #5
0
/**
 * Fill in credentials for the machine trust account, from the secrets database.
 * 
 * @param cred Credentials structure to fill in
 * @retval NTSTATUS error detailing any failure
 */
NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred,
			            struct tevent_context *event_ctx,
				    struct loadparm_context *lp_ctx)
{
	NTSTATUS status;
	char *filter;
	/* Bleh, nasty recursion issues: We are setting a machine
	 * account here, so we don't want the 'pending' flag around
	 * any more */
	cred->machine_account_pending = false;
	filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
				       cli_credentials_get_realm(cred),
				       cli_credentials_get_domain(cred));
	status = cli_credentials_set_secrets(cred, event_ctx, lp_ctx, NULL, 
					   SECRETS_PRINCIPALS_DN,
					   filter);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s", nt_errstr(status)));
	}
	return status;
}
Exemple #6
0
static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
{
	struct gensec_gssapi_state *gensec_gssapi_state;
	struct cli_credentials *creds = gensec_get_credentials(gensec_security);
	NTSTATUS nt_status;
	gss_buffer_desc name_token;
	gss_OID name_type;
	OM_uint32 maj_stat, min_stat;
	const char *hostname = gensec_get_target_hostname(gensec_security);

	if (!hostname) {
		DEBUG(3, ("No hostname for target computer passed in, cannot use kerberos for this connection\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (is_ipaddress(hostname)) {
		DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (strcmp(hostname, "localhost") == 0) {
		DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	nt_status = gensec_gssapi_start(gensec_security);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);

	if (cli_credentials_get_impersonate_principal(creds)) {
		gensec_gssapi_state->gss_want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
	}

	gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
	if (gensec_gssapi_state->target_principal) {
		name_type = GSS_C_NULL_OID;
	} else {
		gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
					    gensec_get_target_service(gensec_security), 
					    hostname, cli_credentials_get_realm(creds));

		name_type = GSS_C_NT_USER_NAME;
	}
	name_token.value  = discard_const_p(uint8_t, gensec_gssapi_state->target_principal);
	name_token.length = strlen(gensec_gssapi_state->target_principal);


	maj_stat = gss_import_name (&min_stat,
				    &name_token,
				    name_type,
				    &gensec_gssapi_state->server_name);
	if (maj_stat) {
		DEBUG(2, ("GSS Import name of %s failed: %s\n",
			  (char *)name_token.value,
			  gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	return NT_STATUS_OK;
}
Exemple #7
0
/* Get the keytab (actually, a container containing the krb5_keytab)
 * attached to this context.  If this hasn't been done or set before,
 * it will be generated from the password.
 */
_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, 
					struct loadparm_context *lp_ctx,
					struct keytab_container **_ktc)
{
	krb5_error_code ret;
	struct keytab_container *ktc;
	struct smb_krb5_context *smb_krb5_context;
	const char *keytab_name;
	krb5_keytab keytab;
	TALLOC_CTX *mem_ctx;

	if (cred->keytab_obtained >= (MAX(cred->principal_obtained, 
					  cred->username_obtained))) {
		*_ktc = cred->keytab;
		return 0;
	}

	if (cli_credentials_is_anonymous(cred)) {
		return EINVAL;
	}

	ret = cli_credentials_get_krb5_context(cred, lp_ctx,
					       &smb_krb5_context);
	if (ret) {
		return ret;
	}

	mem_ctx = talloc_new(cred);
	if (!mem_ctx) {
		return ENOMEM;
	}

	ret = smb_krb5_create_memory_keytab(mem_ctx,
					smb_krb5_context->krb5_context,
					cli_credentials_get_password(cred),
					cli_credentials_get_username(cred),
					cli_credentials_get_realm(cred),
					cli_credentials_get_kvno(cred),
					&keytab, &keytab_name);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
					    keytab, keytab_name, &ktc);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	cred->keytab_obtained = (MAX(cred->principal_obtained, 
				     cred->username_obtained));

	/* We make this keytab up based on a password.  Therefore
	 * match-by-key is acceptable, we can't match on the wrong
	 * principal */
	ktc->password_based = true;

	talloc_steal(cred, ktc);
	cred->keytab = ktc;
	*_ktc = cred->keytab;
	talloc_free(mem_ctx);
	return ret;
}
static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
				struct tevent_context *ev,
				const DATA_BLOB in, DATA_BLOB *out)
{
	struct schannel_state *state = (struct schannel_state *)gensec_security->private_data;
	NTSTATUS status;
	enum ndr_err_code ndr_err;
	struct NL_AUTH_MESSAGE bind_schannel;
	struct NL_AUTH_MESSAGE bind_schannel_ack;
	struct netlogon_creds_CredentialState *creds;
	const char *workstation;
	const char *domain;

	*out = data_blob(NULL, 0);

	switch (gensec_security->gensec_role) {
	case GENSEC_CLIENT:
		if (state->state != SCHANNEL_STATE_START) {
			/* we could parse the bind ack, but we don't know what it is yet */
			return NT_STATUS_OK;
		}

		state->creds = cli_credentials_get_netlogon_creds(gensec_security->credentials);
		if (state->creds == NULL) {
			return NT_STATUS_INVALID_PARAMETER_MIX;
		}
		/*
		 * We need to create a reference here or we don't get
		 * updates performed on the credentials if we create a
		 * copy.
		 */
		state->creds = talloc_reference(state, state->creds);
		if (state->creds == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		bind_schannel.MessageType = NL_NEGOTIATE_REQUEST;
#if 0
		/* to support this we'd need to have access to the full domain name */
		/* 0x17, 23 */
		bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
				      NL_FLAG_OEM_NETBIOS_COMPUTER_NAME |
				      NL_FLAG_UTF8_DNS_DOMAIN_NAME |
				      NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME;
		bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
		bind_schannel.oem_netbios_computer.a = cli_credentials_get_workstation(gensec_security->credentials);
		bind_schannel.utf8_dns_domain = cli_credentials_get_realm(gensec_security->credentials);
		/* w2k3 refuses us if we use the full DNS workstation?
		 why? perhaps because we don't fill in the dNSHostName
		 attribute in the machine account? */
		bind_schannel.utf8_netbios_computer = cli_credentials_get_workstation(gensec_security->credentials);
#else
		bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
				      NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
		bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
		bind_schannel.oem_netbios_computer.a = cli_credentials_get_workstation(gensec_security->credentials);
#endif

		ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
					       (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not create schannel bind: %s\n",
				  nt_errstr(status)));
			return status;
		}

		state->state = SCHANNEL_STATE_UPDATE_1;

		return NT_STATUS_MORE_PROCESSING_REQUIRED;
	case GENSEC_SERVER:

		if (state->state != SCHANNEL_STATE_START) {
			/* no third leg on this protocol */
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* parse the schannel startup blob */
		ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
			(ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
				  nt_errstr(status)));
			return status;
		}

		if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME) {
			domain = bind_schannel.oem_netbios_domain.a;
			if (strcasecmp_m(domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)) != 0) {
				DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
					  domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else if (bind_schannel.Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME) {
			domain = bind_schannel.utf8_dns_domain.u;
			if (strcasecmp_m(domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)) != 0) {
				DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
					  domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(3, ("Request for schannel to without domain\n"));
			return NT_STATUS_LOGON_FAILURE;
		}

		if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME) {
			workstation = bind_schannel.oem_netbios_computer.a;
		} else if (bind_schannel.Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME) {
			workstation = bind_schannel.utf8_netbios_computer.u;
		} else {
			DEBUG(3, ("Request for schannel to without netbios workstation\n"));
			return NT_STATUS_LOGON_FAILURE;
		}

		status = schannel_get_creds_state(out_mem_ctx,
						  gensec_security->settings->lp_ctx,
						  workstation, &creds);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
				  workstation, nt_errstr(status)));
			if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
				return NT_STATUS_LOGON_FAILURE;
			}
			return status;
		}

		state->creds = talloc_steal(state, creds);

		bind_schannel_ack.MessageType = NL_NEGOTIATE_RESPONSE;
		bind_schannel_ack.Flags = 0;
		bind_schannel_ack.Buffer.dummy = 0x6c0000; /* actually I think
							    * this does not have
							    * any meaning here
							    * - gd */

		ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
					       (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
				  workstation, nt_errstr(status)));
			return status;
		}

		state->state = SCHANNEL_STATE_UPDATE_1;

		return NT_STATUS_OK;
	}
	return NT_STATUS_INVALID_PARAMETER;
}
Exemple #9
0
static PyObject *py_creds_get_realm(PyObject *self, PyObject *unused)
{
	return PyString_FromStringOrNULL(cli_credentials_get_realm(PyCredentials_AsCliCredentials(self)));
}
Exemple #10
0
/* Get the keytab (actually, a container containing the krb5_keytab)
 * attached to this context.  If this hasn't been done or set before,
 * it will be generated from the password.
 */
_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, 
					struct loadparm_context *lp_ctx,
					struct keytab_container **_ktc)
{
	krb5_error_code ret;
	struct keytab_container *ktc;
	struct smb_krb5_context *smb_krb5_context;
	const char *keytab_name;
	krb5_keytab keytab;
	TALLOC_CTX *mem_ctx;
	const char *username = cli_credentials_get_username(cred);
	const char *realm = cli_credentials_get_realm(cred);
	const char *error_string;
	const char *salt_principal;

	if (cred->keytab_obtained >= (MAX(cred->principal_obtained, 
					  cred->username_obtained))) {
		*_ktc = cred->keytab;
		return 0;
	}

	if (cli_credentials_is_anonymous(cred)) {
		return EINVAL;
	}

	ret = cli_credentials_get_krb5_context(cred, lp_ctx,
					       &smb_krb5_context);
	if (ret) {
		return ret;
	}

	mem_ctx = talloc_new(cred);
	if (!mem_ctx) {
		return ENOMEM;
	}

	/*
	 * FIXME: Currently there is no better way than to create the correct
	 * salt principal by checking if the username ends with a '$'. It would
	 * be better if it is part of the credentials.
	 */
	ret = smb_krb5_create_salt_principal(mem_ctx,
					     username,
					     realm,
					     &salt_principal,
					     &error_string);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	ret = smb_krb5_create_memory_keytab(mem_ctx,
					    smb_krb5_context->krb5_context,
					    cli_credentials_get_password(cred),
					    username,
					    realm,
					    salt_principal,
					    cli_credentials_get_kvno(cred),
					    &keytab,
					    &keytab_name);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
					    keytab, keytab_name, &ktc);
	if (ret) {
		talloc_free(mem_ctx);
		return ret;
	}

	cred->keytab_obtained = (MAX(cred->principal_obtained, 
				     cred->username_obtained));

	/* We make this keytab up based on a password.  Therefore
	 * match-by-key is acceptable, we can't match on the wrong
	 * principal */
	ktc->password_based = true;

	talloc_steal(cred, ktc);
	cred->keytab = ktc;
	*_ktc = cred->keytab;
	talloc_free(mem_ctx);
	return ret;
}