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

Generated by: LCOV version 1.13