LCOV - code coverage report
Current view: top level - source4/kdc - kpasswd-helper.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 53 82 64.6 %
Date: 2021-09-23 10:06:22 Functions: 3 3 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          43 : bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
      31             :                               krb5_error_code error_code,
      32             :                               const char *error_string,
      33             :                               DATA_BLOB *error_data)
      34             : {
      35             :         bool ok;
      36             :         char *s;
      37             :         size_t slen;
      38             : 
      39          43 :         if (error_code == 0) {
      40          28 :                 DBG_DEBUG("kpasswd reply - %s\n", error_string);
      41             :         } else {
      42          15 :                 DBG_INFO("kpasswd reply - %s\n", error_string);
      43             :         }
      44             : 
      45          43 :         ok = push_utf8_talloc(mem_ctx, &s, error_string, &slen);
      46          43 :         if (!ok) {
      47           0 :                 return false;
      48             :         }
      49             : 
      50             :         /*
      51             :          * The string 's' has two terminating nul-bytes which are also
      52             :          * reflected by 'slen'. Normally Kerberos doesn't expect that strings
      53             :          * are nul-terminated, but Heimdal does!
      54             :          */
      55             : #ifndef SAMBA4_USES_HEIMDAL
      56           9 :         if (slen < 2) {
      57           0 :                 talloc_free(s);
      58           0 :                 return false;
      59             :         }
      60           9 :         slen -= 2;
      61             : #endif
      62          43 :         if (2 + slen < slen) {
      63           0 :                 talloc_free(s);
      64           0 :                 return false;
      65             :         }
      66          43 :         error_data->length = 2 + slen;
      67          43 :         error_data->data = talloc_size(mem_ctx, error_data->length);
      68          43 :         if (error_data->data == NULL) {
      69           0 :                 talloc_free(s);
      70           0 :                 return false;
      71             :         }
      72             : 
      73          43 :         RSSVAL(error_data->data, 0, error_code);
      74          43 :         memcpy(error_data->data + 2, s, slen);
      75             : 
      76          43 :         talloc_free(s);
      77             : 
      78          43 :         return true;
      79             : }
      80             : 
      81          43 : bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
      82             :                                  NTSTATUS status,
      83             :                                  enum samPwdChangeReason reject_reason,
      84             :                                  struct samr_DomInfo1 *dominfo,
      85             :                                  DATA_BLOB *error_blob)
      86             : {
      87          43 :         const char *reject_string = NULL;
      88             : 
      89          43 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
      90           0 :                 return kpasswd_make_error_reply(mem_ctx,
      91             :                                                 KRB5_KPASSWD_ACCESSDENIED,
      92             :                                                 "No such user when changing password",
      93             :                                                 error_blob);
      94          43 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
      95          13 :                 return kpasswd_make_error_reply(mem_ctx,
      96             :                                                 KRB5_KPASSWD_ACCESSDENIED,
      97             :                                                 "Not permitted to change password",
      98             :                                                 error_blob);
      99             :         }
     100          51 :         if (dominfo != NULL &&
     101          30 :             NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
     102           2 :                 switch (reject_reason) {
     103           1 :                 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
     104           1 :                         reject_string =
     105           1 :                                 talloc_asprintf(mem_ctx,
     106             :                                                 "Password too short, password "
     107             :                                                 "must be at least %d characters "
     108             :                                                 "long.",
     109           1 :                                                 dominfo->min_password_length);
     110           1 :                         if (reject_string == NULL) {
     111           0 :                                 reject_string = "Password too short";
     112             :                         }
     113           1 :                         break;
     114           1 :                 case SAM_PWD_CHANGE_NOT_COMPLEX:
     115           1 :                         reject_string = "Password does not meet complexity "
     116             :                                         "requirements";
     117           1 :                         break;
     118           0 :                 case SAM_PWD_CHANGE_PWD_IN_HISTORY:
     119           0 :                         reject_string =
     120           0 :                                 talloc_asprintf(mem_ctx,
     121             :                                                 "Password is already in password "
     122             :                                                 "history. New password must not "
     123             :                                                 "match any of your %d previous "
     124             :                                                 "passwords.",
     125           0 :                                                 dominfo->password_history_length);
     126           0 :                         if (reject_string == NULL) {
     127           0 :                                 reject_string = "Password is already in password "
     128             :                                                 "history";
     129             :                         }
     130           0 :                         break;
     131           0 :                 default:
     132           0 :                         reject_string = "Password change rejected, password "
     133             :                                         "changes may not be permitted on this "
     134             :                                         "account, or the minimum password age "
     135             :                                         "may not have elapsed.";
     136           0 :                         break;
     137             :                 }
     138             : 
     139           2 :                 return kpasswd_make_error_reply(mem_ctx,
     140             :                                                 KRB5_KPASSWD_SOFTERROR,
     141             :                                                 reject_string,
     142             :                                                 error_blob);
     143             :         }
     144             : 
     145          28 :         if (!NT_STATUS_IS_OK(status)) {
     146           0 :                 reject_string = talloc_asprintf(mem_ctx,
     147             :                                                 "Failed to set password: %s",
     148             :                                                 nt_errstr(status));
     149           0 :                 if (reject_string == NULL) {
     150           0 :                         reject_string = "Failed to set password";
     151             :                 }
     152           0 :                 return kpasswd_make_error_reply(mem_ctx,
     153             :                                                 KRB5_KPASSWD_HARDERROR,
     154             :                                                 reject_string,
     155             :                                                 error_blob);
     156             :         }
     157             : 
     158          28 :         return kpasswd_make_error_reply(mem_ctx,
     159             :                                         KRB5_KPASSWD_SUCCESS,
     160             :                                         "Password changed",
     161             :                                         error_blob);
     162             : }
     163             : 
     164          24 : NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
     165             :                                     struct tevent_context *event_ctx,
     166             :                                     struct loadparm_context *lp_ctx,
     167             :                                     struct auth_session_info *session_info,
     168             :                                     bool is_service_principal,
     169             :                                     const char *target_principal_name,
     170             :                                     DATA_BLOB *password,
     171             :                                     enum samPwdChangeReason *reject_reason,
     172             :                                     struct samr_DomInfo1 **dominfo)
     173             : {
     174             :         NTSTATUS status;
     175             :         struct ldb_context *samdb;
     176          24 :         struct ldb_dn *target_dn = NULL;
     177             :         int rc;
     178             : 
     179          24 :         samdb = samdb_connect(mem_ctx,
     180             :                               event_ctx,
     181             :                               lp_ctx,
     182             :                               session_info,
     183             :                               NULL,
     184             :                               0);
     185          24 :         if (samdb == NULL) {
     186           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     187             :         }
     188             : 
     189          24 :         DBG_INFO("%s\\%s (%s) is changing password of %s\n",
     190             :                  session_info->info->domain_name,
     191             :                  session_info->info->account_name,
     192             :                  dom_sid_string(mem_ctx,
     193             :                                 &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]),
     194             :                  target_principal_name);
     195             : 
     196          24 :         rc = ldb_transaction_start(samdb);
     197          24 :         if (rc != LDB_SUCCESS) {
     198           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
     199             :         }
     200             : 
     201          24 :         if (is_service_principal) {
     202           3 :                 status = crack_service_principal_name(samdb,
     203             :                                                       mem_ctx,
     204             :                                                       target_principal_name,
     205             :                                                       &target_dn,
     206             :                                                       NULL);
     207             :         } else {
     208          21 :                 status = crack_user_principal_name(samdb,
     209             :                                                    mem_ctx,
     210             :                                                    target_principal_name,
     211             :                                                    &target_dn,
     212             :                                                    NULL);
     213             :         }
     214          24 :         if (!NT_STATUS_IS_OK(status)) {
     215           0 :                 ldb_transaction_cancel(samdb);
     216           0 :                 return status;
     217             :         }
     218             : 
     219          24 :         status = samdb_set_password(samdb,
     220             :                                     mem_ctx,
     221             :                                     target_dn,
     222             :                                     NULL, /* domain_dn */
     223             :                                     password,
     224             :                                     NULL, /* lmNewHash */
     225             :                                     NULL, /* ntNewHash */
     226             :                                     NULL, /* lmOldHash */
     227             :                                     NULL, /* ntOldHash */
     228             :                                     reject_reason,
     229             :                                     dominfo);
     230          24 :         if (NT_STATUS_IS_OK(status)) {
     231          11 :                 rc = ldb_transaction_commit(samdb);
     232          11 :                 if (rc != LDB_SUCCESS) {
     233           0 :                         DBG_WARNING("Failed to commit transaction to "
     234             :                                     "set password on %s: %s\n",
     235             :                                     ldb_dn_get_linearized(target_dn),
     236             :                                     ldb_errstring(samdb));
     237           0 :                         return NT_STATUS_TRANSACTION_ABORTED;
     238             :                 }
     239             :         } else {
     240          13 :                 ldb_transaction_cancel(samdb);
     241             :         }
     242             : 
     243          24 :         return status;
     244             : }

Generated by: LCOV version 1.13