示例#1
0
static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
					       TALLOC_CTX *mem_ctx,
					       struct auth_session_info *session_info,
					       DATA_BLOB *password,
					       DATA_BLOB *kpasswd_reply,
					       const char **error_string)
{
	NTSTATUS status;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	enum samPwdChangeReason reject_reason;
	const char *reject_string = NULL;
	struct samr_DomInfo1 *dominfo;
	bool ok;

	status = samdb_kpasswd_change_password(mem_ctx,
					       kdc->task->lp_ctx,
					       kdc->task->event_ctx,
					       kdc->samdb,
					       session_info,
					       password,
					       &reject_reason,
					       &dominfo,
					       &reject_string,
					       &result);
	if (!NT_STATUS_IS_OK(status)) {
		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_ACCESSDENIED,
					      reject_string,
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
		/* We want to send an an authenticated packet. */
		return 0;
	}

	ok = kpasswd_make_pwchange_reply(mem_ctx,
					 result,
					 reject_reason,
					 dominfo,
					 kpasswd_reply);
	if (!ok) {
		*error_string = "Failed to create reply";
		return KRB5_KPASSWD_HARDERROR;
	}

	return 0;
}
示例#2
0
/*
   A user password change

   Return true if there is a valid error packet (or sucess) formed in
   the error_blob
*/
static bool kpasswdd_change_password(struct kdc_server *kdc,
				     TALLOC_CTX *mem_ctx,
				     struct auth_session_info *session_info,
				     const DATA_BLOB *password,
				     DATA_BLOB *reply)
{
	NTSTATUS status;
	enum samPwdChangeReason reject_reason;
	struct samr_DomInfo1 *dominfo;
	struct ldb_context *samdb;

	samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx));
	if (!samdb) {
		return kpasswdd_make_error_reply(kdc, mem_ctx,
						KRB5_KPASSWD_HARDERROR,
						"Failed to open samdb",
						reply);
	}

	DEBUG(3, ("Changing password of %s\\%s (%s)\n",
		  session_info->server_info->domain_name,
		  session_info->server_info->account_name,
		  dom_sid_string(mem_ctx, session_info->security_token->user_sid)));

	/* User password change */
	status = samdb_set_password_sid(samdb, mem_ctx,
					session_info->security_token->user_sid,
					password, NULL, NULL,
					true, /* this is a user password change */
					&reject_reason,
					&dominfo);
	return kpasswd_make_pwchange_reply(kdc, mem_ctx,
					   status,
					   reject_reason,
					   dominfo,
					   reply);

}
示例#3
0
static bool kpasswd_process_request(struct kdc_server *kdc,
				    TALLOC_CTX *mem_ctx,
				    struct gensec_security *gensec_security,
				    uint16_t version,
				    DATA_BLOB *input,
				    DATA_BLOB *reply)
{
	struct auth_session_info *session_info;
	size_t pw_len;

	if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
						 &session_info))) {
		return kpasswdd_make_error_reply(kdc, mem_ctx,
						KRB5_KPASSWD_HARDERROR,
						"gensec_session_info failed!",
						reply);
	}

	switch (version) {
	case KRB5_KPASSWD_VERS_CHANGEPW:
	{
		DATA_BLOB password;
		if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
					       CH_UTF8, CH_UTF16,
					       (const char *)input->data,
					       input->length,
					       (void **)&password.data, &pw_len, false)) {
			return false;
		}
		password.length = pw_len;

		return kpasswdd_change_password(kdc, mem_ctx, session_info,
						&password, reply);
		break;
	}
	case KRB5_KPASSWD_VERS_SETPW:
	{
		NTSTATUS status;
		enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
		struct samr_DomInfo1 *dominfo = NULL;
		struct ldb_context *samdb;
		struct ldb_message *msg;
		krb5_context context = kdc->smb_krb5_context->krb5_context;

		ChangePasswdDataMS chpw;
		DATA_BLOB password;

		krb5_principal principal;
		char *set_password_on_princ;
		struct ldb_dn *set_password_on_dn;

		size_t len;
		int ret;

		msg = ldb_msg_new(mem_ctx);
		if (!msg) {
			return false;
		}

		ret = decode_ChangePasswdDataMS(input->data, input->length,
						&chpw, &len);
		if (ret) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"failed to decode password change structure",
							reply);
		}

		if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx),
					       CH_UTF8, CH_UTF16,
					       (const char *)chpw.newpasswd.data,
					       chpw.newpasswd.length,
					       (void **)&password.data, &pw_len, false)) {
			free_ChangePasswdDataMS(&chpw);
			return false;
		}

		password.length = pw_len;

		if ((chpw.targname && !chpw.targrealm)
		    || (!chpw.targname && chpw.targrealm)) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"Realm and principal must be both present, or neither present",
							reply);
		}
		if (chpw.targname && chpw.targrealm) {
#ifdef SAMBA4_INTERNAL_HEIMDAL
			if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context,
							       &principal, *chpw.targname,
							       *chpw.targrealm) != 0) {
				free_ChangePasswdDataMS(&chpw);
				return kpasswdd_make_error_reply(kdc, mem_ctx,
								KRB5_KPASSWD_MALFORMED,
								"failed to extract principal to set",
								reply);

			}
#else /* SAMBA4_INTERNAL_HEIMDAL */
				return kpasswdd_make_error_reply(kdc, mem_ctx,
								KRB5_KPASSWD_BAD_VERSION,
								"Operation Not Implemented",
								reply);
#endif /* SAMBA4_INTERNAL_HEIMDAL */
		} else {
			free_ChangePasswdDataMS(&chpw);
			return kpasswdd_change_password(kdc, mem_ctx, session_info,
							&password, reply);
		}
		free_ChangePasswdDataMS(&chpw);

		if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) {
			krb5_free_principal(context, principal);
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							KRB5_KPASSWD_MALFORMED,
							"krb5_unparse_name failed!",
							reply);
		}

		krb5_free_principal(context, principal);

		samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info);
		if (!samdb) {
			return kpasswdd_make_error_reply(kdc, mem_ctx,
							 KRB5_KPASSWD_HARDERROR,
							 "Unable to open database!",
							 reply);
		}

		DEBUG(3, ("%s\\%s (%s) is changing password of %s\n",
			  session_info->server_info->domain_name,
			  session_info->server_info->account_name,
			  dom_sid_string(mem_ctx, session_info->security_token->user_sid),
			  set_password_on_princ));
		ret = ldb_transaction_start(samdb);
		if (ret) {
			status = NT_STATUS_TRANSACTION_ABORTED;
			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
							   status,
							   SAM_PWD_CHANGE_NO_ERROR,
							   NULL,
							   reply);
		}

		status = crack_user_principal_name(samdb, mem_ctx,
						   set_password_on_princ,
						   &set_password_on_dn, NULL);
		free(set_password_on_princ);
		if (!NT_STATUS_IS_OK(status)) {
			ldb_transaction_cancel(samdb);
			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
							   status,
							   SAM_PWD_CHANGE_NO_ERROR,
							   NULL,
							   reply);
		}

		msg = ldb_msg_new(mem_ctx);
		if (msg == NULL) {
			ldb_transaction_cancel(samdb);
			status = NT_STATUS_NO_MEMORY;
		} else {
			msg->dn = ldb_dn_copy(msg, set_password_on_dn);
			if (!msg->dn) {
				status = NT_STATUS_NO_MEMORY;
			}
		}

		if (NT_STATUS_IS_OK(status)) {
			/* Admin password set */
			status = samdb_set_password(samdb, mem_ctx,
						    set_password_on_dn, NULL,
						    msg, &password, NULL, NULL,
						    false, /* this is not a user password change */
						    &reject_reason, &dominfo);
		}

		if (NT_STATUS_IS_OK(status)) {
			/* modify the samdb record */
			ret = samdb_replace(samdb, mem_ctx, msg);
			if (ret != 0) {
				DEBUG(2,("Failed to modify record to set password on %s: %s\n",
					 ldb_dn_get_linearized(msg->dn),
					 ldb_errstring(samdb)));
				status = NT_STATUS_ACCESS_DENIED;
			}
		}
		if (NT_STATUS_IS_OK(status)) {
			ret = ldb_transaction_commit(samdb);
			if (ret != 0) {
				DEBUG(1,("Failed to commit transaction to set password on %s: %s\n",
					 ldb_dn_get_linearized(msg->dn),
					 ldb_errstring(samdb)));
				status = NT_STATUS_TRANSACTION_ABORTED;
			}
		} else {
			ldb_transaction_cancel(samdb);
		}
		return kpasswd_make_pwchange_reply(kdc, mem_ctx,
						   status,
						   reject_reason,
						   dominfo,
						   reply);
	}
	default:
		return kpasswdd_make_error_reply(kdc, mem_ctx,
						 KRB5_KPASSWD_BAD_VERSION,
						 talloc_asprintf(mem_ctx,
								 "Protocol version %u not supported",
								 version),
						 reply);
	}
	return true;
}
示例#4
0
static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
					    TALLOC_CTX *mem_ctx,
					    struct auth_session_info *session_info,
					    DATA_BLOB *decoded_data,
					    DATA_BLOB *kpasswd_reply,
					    const char **error_string)
{
	krb5_context context = kdc->smb_krb5_context->krb5_context;
	krb5_data k_dec_data;
	krb5_data *k_clear_data;
	krb5_principal target_principal;
	krb5_error_code code;
	DATA_BLOB password;
	char *target_realm = NULL;
	char *target_name = NULL;
	char *target_principal_string = NULL;
	bool is_service_principal = false;
	bool ok;
	size_t num_components;
	enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
	struct samr_DomInfo1 *dominfo = NULL;
	NTSTATUS status;

	k_dec_data.length = decoded_data->length;
	k_dec_data.data   = (char *)decoded_data->data;

	code = decode_krb5_setpw_req(&k_dec_data,
				     &k_clear_data,
				     &target_principal);
	if (code != 0) {
		DBG_WARNING("decode_krb5_setpw_req failed: %s\n",
			    error_message(code));
		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Failed to decode packet",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
		return 0;
	}

	ok = convert_string_talloc_handle(mem_ctx,
					  lpcfg_iconv_handle(kdc->task->lp_ctx),
					  CH_UTF8,
					  CH_UTF16,
					  (const char *)k_clear_data->data,
					  k_clear_data->length,
					  (void **)&password.data,
					  &password.length);
	krb5_free_data(context, k_clear_data);
	if (!ok) {
		DBG_WARNING("String conversion failed\n");
		*error_string = "String conversion failed";
		return KRB5_KPASSWD_HARDERROR;
	}

	target_realm = smb_krb5_principal_get_realm(context, target_principal);
	code = krb5_unparse_name_flags(context,
				       target_principal,
				       KRB5_PRINCIPAL_UNPARSE_NO_REALM,
				       &target_name);
	if (code != 0) {
		DBG_WARNING("Failed to parse principal\n");
		*error_string = "String conversion failed";
		return KRB5_KPASSWD_HARDERROR;
	}

	if ((target_name != NULL && target_realm == NULL) ||
	    (target_name == NULL && target_realm != NULL)) {
		krb5_free_principal(context, target_principal);
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);

		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Realm and principal must be "
					      "both present, or neither "
					      "present",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
		return 0;
	}

	if (target_name != NULL && target_realm != NULL) {
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);
	} else {
		krb5_free_principal(context, target_principal);
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);

		return kpasswd_change_password(kdc,
					       mem_ctx,
					       session_info,
					       &password,
					       kpasswd_reply,
					       error_string);
	}

	num_components = krb5_princ_size(context, target_principal);
	if (num_components >= 2) {
		is_service_principal = true;
		code = krb5_unparse_name_flags(context,
					       target_principal,
					       KRB5_PRINCIPAL_UNPARSE_SHORT,
					       &target_principal_string);
	} else {
		code = krb5_unparse_name(context,
					 target_principal,
					 &target_principal_string);
	}
	krb5_free_principal(context, target_principal);
	if (code != 0) {
		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Failed to parse principal",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
	}

	status = kpasswd_samdb_set_password(mem_ctx,
					    kdc->task->event_ctx,
					    kdc->task->lp_ctx,
					    session_info,
					    is_service_principal,
					    target_principal_string,
					    &password,
					    &reject_reason,
					    &dominfo);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
			nt_errstr(status));
	}

	ok = kpasswd_make_pwchange_reply(mem_ctx,
					 status,
					 reject_reason,
					 dominfo,
					 kpasswd_reply);
	if (!ok) {
		*error_string = "Failed to create reply";
		return KRB5_KPASSWD_HARDERROR;
	}

	return 0;
}