LCOV - code coverage report
Current view: top level - source4/kdc - kpasswd-helper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 60 99 60.6 %
Date: 2024-04-21 15:09:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Samba kpasswd implementation
       5             : 
       6             :    Copyright (c) 2005      Andrew Bartlett <abartlet@samba.org>
       7             :    Copyright (c) 2016      Andreas Schneider <asn@samba.org>
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/kerberos.h"
      25             : #include "librpc/gen_ndr/samr.h"
      26             : #include "dsdb/samdb/samdb.h"
      27             : #include "auth/auth.h"
      28             : #include "kdc/kpasswd-helper.h"
      29             : 
      30             : #undef DBGC_CLASS
      31             : #define DBGC_CLASS DBGC_KERBEROS
      32             : 
      33         118 : bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
      34             :                               krb5_error_code error_code,
      35             :                               const char *error_string,
      36             :                               DATA_BLOB *error_data)
      37             : {
      38           0 :         bool ok;
      39           0 :         char *s;
      40           0 :         size_t slen;
      41             : 
      42         118 :         if (error_code == 0) {
      43          55 :                 DBG_DEBUG("kpasswd reply - %s\n", error_string);
      44             :         } else {
      45          63 :                 DBG_INFO("kpasswd reply - %s\n", error_string);
      46             :         }
      47             : 
      48         118 :         ok = push_utf8_talloc(mem_ctx, &s, error_string, &slen);
      49         118 :         if (!ok) {
      50           0 :                 return false;
      51             :         }
      52             : 
      53             :         /*
      54             :          * The string 's' has one terminating nul-byte which is also
      55             :          * reflected by 'slen'. We subtract it from the length.
      56             :          */
      57         118 :         if (slen < 1) {
      58           0 :                 talloc_free(s);
      59           0 :                 return false;
      60             :         }
      61         118 :         slen--;
      62             : 
      63             :         /* Two bytes are added to the length to account for the error code. */
      64         118 :         if (2 + slen < slen) {
      65           0 :                 talloc_free(s);
      66           0 :                 return false;
      67             :         }
      68         118 :         error_data->length = 2 + slen;
      69         118 :         error_data->data = talloc_size(mem_ctx, error_data->length);
      70         118 :         if (error_data->data == NULL) {
      71           0 :                 talloc_free(s);
      72           0 :                 return false;
      73             :         }
      74             : 
      75         118 :         RSSVAL(error_data->data, 0, error_code);
      76         118 :         memcpy(error_data->data + 2, s, slen);
      77             : 
      78         118 :         talloc_free(s);
      79             : 
      80         118 :         return true;
      81             : }
      82             : 
      83          80 : bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
      84             :                                  NTSTATUS status,
      85             :                                  enum samPwdChangeReason reject_reason,
      86             :                                  struct samr_DomInfo1 *dominfo,
      87             :                                  DATA_BLOB *error_blob)
      88             : {
      89          80 :         const char *reject_string = NULL;
      90             : 
      91          80 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
      92          15 :                 return kpasswd_make_error_reply(mem_ctx,
      93             :                                                 KRB5_KPASSWD_ACCESSDENIED,
      94             :                                                 "No such user when changing password",
      95             :                                                 error_blob);
      96          80 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
      97          15 :                 return kpasswd_make_error_reply(mem_ctx,
      98             :                                                 KRB5_KPASSWD_ACCESSDENIED,
      99             :                                                 "Not permitted to change password",
     100             :                                                 error_blob);
     101             :         }
     102          65 :         if (dominfo != NULL &&
     103          65 :             NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
     104          10 :                 switch (reject_reason) {
     105           4 :                 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
     106           0 :                         reject_string =
     107           4 :                                 talloc_asprintf(mem_ctx,
     108             :                                                 "Password too short, password "
     109             :                                                 "must be at least %d characters "
     110             :                                                 "long.",
     111           4 :                                                 dominfo->min_password_length);
     112           4 :                         if (reject_string == NULL) {
     113           0 :                                 reject_string = "Password too short";
     114             :                         }
     115           4 :                         break;
     116           6 :                 case SAM_PWD_CHANGE_NOT_COMPLEX:
     117           6 :                         reject_string = "Password does not meet complexity "
     118             :                                         "requirements";
     119           6 :                         break;
     120           0 :                 case SAM_PWD_CHANGE_PWD_IN_HISTORY:
     121           0 :                         reject_string =
     122           0 :                                 talloc_asprintf(mem_ctx,
     123             :                                                 "Password is already in password "
     124             :                                                 "history. New password must not "
     125             :                                                 "match any of your %d previous "
     126             :                                                 "passwords.",
     127           0 :                                                 dominfo->password_history_length);
     128           0 :                         if (reject_string == NULL) {
     129           0 :                                 reject_string = "Password is already in password "
     130             :                                                 "history";
     131             :                         }
     132           0 :                         break;
     133           0 :                 default:
     134           0 :                         reject_string = "Password change rejected, password "
     135             :                                         "changes may not be permitted on this "
     136             :                                         "account, or the minimum password age "
     137             :                                         "may not have elapsed.";
     138           0 :                         break;
     139             :                 }
     140             : 
     141          10 :                 return kpasswd_make_error_reply(mem_ctx,
     142             :                                                 KRB5_KPASSWD_SOFTERROR,
     143             :                                                 reject_string,
     144             :                                                 error_blob);
     145             :         }
     146             : 
     147          55 :         if (!NT_STATUS_IS_OK(status)) {
     148           0 :                 reject_string = talloc_asprintf(mem_ctx,
     149             :                                                 "Failed to set password: %s",
     150             :                                                 nt_errstr(status));
     151           0 :                 if (reject_string == NULL) {
     152           0 :                         reject_string = "Failed to set password";
     153             :                 }
     154           0 :                 return kpasswd_make_error_reply(mem_ctx,
     155             :                                                 KRB5_KPASSWD_HARDERROR,
     156             :                                                 reject_string,
     157             :                                                 error_blob);
     158             :         }
     159             : 
     160          55 :         return kpasswd_make_error_reply(mem_ctx,
     161             :                                         KRB5_KPASSWD_SUCCESS,
     162             :                                         "Password changed",
     163             :                                         error_blob);
     164             : }
     165             : 
     166          23 : NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
     167             :                                     struct tevent_context *event_ctx,
     168             :                                     struct loadparm_context *lp_ctx,
     169             :                                     struct auth_session_info *session_info,
     170             :                                     bool is_service_principal,
     171             :                                     const char *target_principal_name,
     172             :                                     DATA_BLOB *password,
     173             :                                     enum samPwdChangeReason *reject_reason,
     174             :                                     struct samr_DomInfo1 **dominfo)
     175             : {
     176           0 :         NTSTATUS status;
     177           0 :         struct ldb_context *samdb;
     178          23 :         struct ldb_dn *target_dn = NULL;
     179           0 :         int rc;
     180             : 
     181          23 :         samdb = samdb_connect(mem_ctx,
     182             :                               event_ctx,
     183             :                               lp_ctx,
     184             :                               session_info,
     185             :                               NULL,
     186             :                               0);
     187          23 :         if (samdb == NULL) {
     188           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     189             :         }
     190             : 
     191          23 :         DBG_INFO("%s\\%s (%s) is changing password of %s\n",
     192             :                  session_info->info->domain_name,
     193             :                  session_info->info->account_name,
     194             :                  dom_sid_string(mem_ctx,
     195             :                                 &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]),
     196             :                  target_principal_name);
     197             : 
     198          23 :         rc = ldb_transaction_start(samdb);
     199          23 :         if (rc != LDB_SUCCESS) {
     200           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
     201             :         }
     202             : 
     203          23 :         if (is_service_principal) {
     204           0 :                 status = crack_service_principal_name(samdb,
     205             :                                                       mem_ctx,
     206             :                                                       target_principal_name,
     207             :                                                       &target_dn,
     208             :                                                       NULL);
     209             :         } else {
     210          23 :                 status = crack_user_principal_name(samdb,
     211             :                                                    mem_ctx,
     212             :                                                    target_principal_name,
     213             :                                                    &target_dn,
     214             :                                                    NULL);
     215             :         }
     216          23 :         if (!NT_STATUS_IS_OK(status)) {
     217           0 :                 ldb_transaction_cancel(samdb);
     218           0 :                 return status;
     219             :         }
     220             : 
     221          23 :         status = samdb_set_password(samdb,
     222             :                                     mem_ctx,
     223             :                                     target_dn,
     224             :                                     password,
     225             :                                     NULL, /* ntNewHash */
     226             :                                     DSDB_PASSWORD_RESET,
     227             :                                     reject_reason,
     228             :                                     dominfo);
     229          23 :         if (NT_STATUS_IS_OK(status)) {
     230           8 :                 rc = ldb_transaction_commit(samdb);
     231           8 :                 if (rc != LDB_SUCCESS) {
     232           0 :                         DBG_WARNING("Failed to commit transaction to "
     233             :                                     "set password on %s: %s\n",
     234             :                                     ldb_dn_get_linearized(target_dn),
     235             :                                     ldb_errstring(samdb));
     236           0 :                         return NT_STATUS_TRANSACTION_ABORTED;
     237             :                 }
     238             :         } else {
     239          15 :                 ldb_transaction_cancel(samdb);
     240             :         }
     241             : 
     242          23 :         return status;
     243             : }
     244             : 
     245          98 : krb5_error_code kpasswd_check_non_tgt(struct auth_session_info *session_info,
     246             :                                       const char **error_string)
     247             : {
     248          98 :         switch(session_info->ticket_type) {
     249           8 :         case TICKET_TYPE_TGT:
     250             :                 /* TGTs are disallowed here. */
     251           8 :                 *error_string = "A TGT may not be used as a ticket to kpasswd";
     252           8 :                 return KRB5_KPASSWD_AUTHERROR;
     253          90 :         case TICKET_TYPE_NON_TGT:
     254             :                 /* Non-TGTs are permitted, and expected. */
     255          90 :                 break;
     256           0 :         default:
     257             :                 /* In case we forgot to set the type. */
     258           0 :                 *error_string = "Failed to ascertain that ticket to kpasswd is not a TGT";
     259           0 :                 return KRB5_KPASSWD_HARDERROR;
     260             :         }
     261             : 
     262          90 :         return 0;
     263             : }

Generated by: LCOV version 1.14