mit_samba: Add function to change the password
authorAndreas Schneider <asn@samba.org>
Thu, 30 Jul 2015 12:46:48 +0000 (14:46 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 17 Mar 2016 03:32:28 +0000 (04:32 +0100)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/kdc/mit_samba.c
source4/kdc/mit_samba.h
source4/kdc/wscript_build

index 6abb7330a9ae895f615d69a0749d892e5b1d6d66..0f5e1a68cd139706d6d08d8f6d6d5dd3b373b6ba 100644 (file)
 #include "dsdb/samdb/samdb.h"
 #include "system/kerberos.h"
 #include <kdb.h>
+#include <kadm5/kadm_err.h>
 #include "kdc/sdb.h"
 #include "kdc/sdb_kdb.h"
 #include "auth/kerberos/kerberos.h"
 #include "kdc/samba_kdc.h"
 #include "kdc/pac-glue.h"
 #include "kdc/db-glue.h"
+#include "auth/auth.h"
+#include "kdc/kpasswd_glue.h"
 
 #include "mit_samba.h"
 
@@ -475,3 +478,164 @@ int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
        return ret;
 #endif
 }
+
+static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
+                                                 NTSTATUS result,
+                                                 enum samPwdChangeReason reject_reason,
+                                                 struct samr_DomInfo1 *dominfo)
+{
+       krb5_error_code code = KADM5_PASS_Q_GENERIC;
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
+               code = KADM5_BAD_PRINCIPAL;
+               krb5_set_error_message(context,
+                                      code,
+                                      "No such user when changing password");
+       }
+       if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+               code = KADM5_PASS_Q_GENERIC;
+               krb5_set_error_message(context,
+                                      code,
+                                      "Not permitted to change password");
+       }
+       if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) &&
+           dominfo != NULL) {
+               switch (reject_reason) {
+               case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
+                       code = KADM5_PASS_Q_TOOSHORT;
+                       krb5_set_error_message(context,
+                                              code,
+                                              "Password too short, password "
+                                              "must be at least %d characters "
+                                              "long.",
+                                              dominfo->min_password_length);
+                       break;
+               case SAM_PWD_CHANGE_NOT_COMPLEX:
+                       code = KADM5_PASS_Q_DICT;
+                       krb5_set_error_message(context,
+                                              code,
+                                              "Password does not meet "
+                                              "complexity requirements");
+                       break;
+               case SAM_PWD_CHANGE_PWD_IN_HISTORY:
+                       code = KADM5_PASS_TOOSOON;
+                       krb5_set_error_message(context,
+                                              code,
+                                              "Password is already in password "
+                                              "history. New password must not "
+                                              "match any of your %d previous "
+                                              "passwords.",
+                                              dominfo->password_history_length);
+                       break;
+               default:
+                       code = KADM5_PASS_Q_GENERIC;
+                       krb5_set_error_message(context,
+                                              code,
+                                              "Password change rejected, "
+                                              "password changes may not be "
+                                              "permitted on this account, or "
+                                              "the minimum password age may "
+                                              "not have elapsed.");
+                       break;
+               }
+       }
+
+       return code;
+}
+
+int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
+                                     char *pwd,
+                                     krb5_db_entry *db_entry)
+{
+       NTSTATUS status;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       TALLOC_CTX *tmp_ctx;
+       DATA_BLOB password;
+       enum samPwdChangeReason reject_reason;
+       struct samr_DomInfo1 *dominfo;
+       const char *error_string = NULL;
+       struct auth_user_info_dc *user_info_dc;
+       struct samba_kdc_entry *p;
+       krb5_error_code code = 0;
+
+#ifdef DEBUG_PASSWORD
+       DEBUG(1,("mit_samba_kpasswd_change_password called with: %s\n", pwd));
+#endif
+
+       tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
+       if (tmp_ctx == NULL) {
+               return ENOMEM;
+       }
+
+       p = (struct samba_kdc_entry *)db_entry->e_data;
+
+       status = authsam_make_user_info_dc(tmp_ctx,
+                                          ctx->db_ctx->samdb,
+                                          lpcfg_netbios_name(ctx->db_ctx->lp_ctx),
+                                          lpcfg_sam_name(ctx->db_ctx->lp_ctx),
+                                          p->realm_dn,
+                                          p->msg,
+                                          data_blob(NULL, 0),
+                                          data_blob(NULL, 0),
+                                          &user_info_dc);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("authsam_make_user_info_dc failed: %s\n",
+                       nt_errstr(status)));
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       status = auth_generate_session_info(tmp_ctx,
+                                           ctx->db_ctx->lp_ctx,
+                                           ctx->db_ctx->samdb,
+                                           user_info_dc,
+                                           0, /* session_info_flags */
+                                           &ctx->session_info);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("auth_generate_session_info failed: %s\n",
+                       nt_errstr(status)));
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       /* password is expected as UTF16 */
+
+       if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
+                                  pwd, strlen(pwd),
+                                  &password.data, &password.length)) {
+               DEBUG(1,("convert_string_talloc failed\n"));
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       status = samdb_kpasswd_change_password(tmp_ctx,
+                                              ctx->db_ctx->lp_ctx,
+                                              ctx->db_ctx->ev_ctx,
+                                              ctx->db_ctx->samdb,
+                                              ctx->session_info,
+                                              &password,
+                                              &reject_reason,
+                                              &dominfo,
+                                              &error_string,
+                                              &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("samdb_kpasswd_change_password failed: %s\n",
+                       nt_errstr(status)));
+               code = KADM5_PASS_Q_GENERIC;
+               krb5_set_error_message(ctx->context, code, "%s", error_string);
+               goto out;
+       }
+
+       if (!NT_STATUS_IS_OK(result)) {
+               code = mit_samba_change_pwd_error(ctx->context,
+                                                 result,
+                                                 reject_reason,
+                                                 dominfo);
+       }
+
+out:
+       talloc_free(tmp_ctx);
+
+       return code;
+}
index 022d8c7364dd54f8257e03df78cec7ca9a9740fe..b7fd16062393618050337be1ffd32ab988c35269 100644 (file)
@@ -71,4 +71,8 @@ int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
                              const char *target_name,
                              bool is_nt_enterprise_name);
 
+int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
+                                     char *pwd,
+                                     krb5_db_entry *db_entry);
+
 #endif /* _MIT_SAMBA_H */
index f6779247bf6a594dd988cc95cc7a69a06638effa..89e4fd293d56597416fcdda4b014e1ec7b623988 100755 (executable)
@@ -114,6 +114,7 @@ bld.SAMBA_SUBSYSTEM('MIT_SAMBA',
                          samba-credentials
                          db-glue
                          PAC_GLUE
+                         KPASSWD_GLUE
                          samba-hostconfig
                          com_err
                          sdb_kdb