Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libads/util.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   krb5 set password implementation
4
   Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "ads.h"
22
#include "secrets.h"
23
#include "librpc/gen_ndr/ndr_secrets.h"
24
25
#ifdef HAVE_KRB5
26
ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
27
0
{
28
0
  const char *password = NULL;
29
0
  const char *new_password = NULL;
30
0
  ADS_STATUS ret;
31
0
  const char *domain = lp_workgroup();
32
0
  struct secrets_domain_info1 *info = NULL;
33
0
  struct secrets_domain_info1_change *prev = NULL;
34
0
  const DATA_BLOB *cleartext_blob = NULL;
35
0
  DATA_BLOB pw_blob = data_blob_null;
36
0
  DATA_BLOB new_pw_blob = data_blob_null;
37
0
  NTSTATUS status;
38
0
  struct timeval tv = timeval_current();
39
0
  NTTIME now = timeval_to_nttime(&tv);
40
0
  int role = lp_server_role();
41
0
  bool ok;
42
43
0
  if (role != ROLE_DOMAIN_MEMBER) {
44
0
    DBG_ERR("Machine account password change only supported on a DOMAIN_MEMBER.\n");
45
0
    return ADS_ERROR_NT(NT_STATUS_INVALID_SERVER_STATE);
46
0
  }
47
48
0
  new_password = trust_pw_new_value(talloc_tos(), SEC_CHAN_WKSTA, SEC_ADS);
49
0
  if (new_password == NULL) {
50
0
    ret = ADS_ERROR_SYSTEM(errno);
51
0
    DEBUG(1,("Failed to generate machine password\n"));
52
0
    return ret;
53
0
  }
54
55
0
  status = secrets_prepare_password_change(domain,
56
0
             ads->auth.kdc_server,
57
0
             new_password,
58
0
             talloc_tos(),
59
0
             &info,
60
0
             &prev,
61
0
#ifdef HAVE_ADS
62
0
             sync_pw2keytabs,
63
#else
64
             NULL,
65
#endif
66
0
             ads->auth.kdc_server);
67
0
  if (!NT_STATUS_IS_OK(status)) {
68
0
    return ADS_ERROR_NT(status);
69
0
  }
70
0
  if (prev != NULL) {
71
0
    status = NT_STATUS_REQUEST_NOT_ACCEPTED;
72
0
    secrets_failed_password_change("localhost",
73
0
                 status,
74
0
                 NT_STATUS_NOT_COMMITTED,
75
0
                 info);
76
0
    return ADS_ERROR_NT(status);
77
0
  }
78
79
0
  cleartext_blob = &info->password->cleartext_blob;
80
0
  ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
81
0
           cleartext_blob->data,
82
0
           cleartext_blob->length,
83
0
           (void **)&pw_blob.data,
84
0
           &pw_blob.length);
85
0
  if (!ok) {
86
0
    status = NT_STATUS_UNMAPPABLE_CHARACTER;
87
0
    if (errno == ENOMEM) {
88
0
      status = NT_STATUS_NO_MEMORY;
89
0
    }
90
0
    DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
91
0
      "failed for password of %s - %s\n",
92
0
      domain, nt_errstr(status));
93
0
    return ADS_ERROR_NT(status);
94
0
  }
95
0
  password = (const char *)pw_blob.data;
96
97
0
  cleartext_blob = &info->next_change->password->cleartext_blob;
98
0
  ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
99
0
           cleartext_blob->data,
100
0
           cleartext_blob->length,
101
0
           (void **)&new_pw_blob.data,
102
0
           &new_pw_blob.length);
103
0
  if (!ok) {
104
0
    status = NT_STATUS_UNMAPPABLE_CHARACTER;
105
0
    if (errno == ENOMEM) {
106
0
      status = NT_STATUS_NO_MEMORY;
107
0
    }
108
0
    DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
109
0
      "failed for new_password of %s - %s\n",
110
0
      domain, nt_errstr(status));
111
0
    secrets_failed_password_change("localhost",
112
0
                 status,
113
0
                 NT_STATUS_NOT_COMMITTED,
114
0
                 info);
115
0
    return ADS_ERROR_NT(status);
116
0
  }
117
0
  talloc_keep_secret(new_pw_blob.data);
118
0
  new_password = (const char *)new_pw_blob.data;
119
120
0
  ret = kerberos_set_password(host_principal,
121
0
            password,
122
0
            host_principal,
123
0
            new_password);
124
125
0
  if (!ADS_ERR_OK(ret)) {
126
0
    status = ads_ntstatus(ret);
127
0
    DBG_ERR("kerberos_set_password(%s, %s) "
128
0
      "failed for new_password of %s - %s\n",
129
0
      ads->auth.kdc_server, host_principal,
130
0
      domain, nt_errstr(status));
131
0
    secrets_failed_password_change(ads->auth.kdc_server,
132
0
                 NT_STATUS_NOT_COMMITTED,
133
0
                 status,
134
0
                 info);
135
0
    return ret;
136
0
  }
137
138
0
  status = secrets_finish_password_change(ads->auth.kdc_server,
139
0
            now,
140
0
            info,
141
0
#ifdef HAVE_ADS
142
0
            sync_pw2keytabs,
143
#else
144
            NULL,
145
#endif
146
0
            ads->auth.kdc_server);
147
0
  if (!NT_STATUS_IS_OK(status)) {
148
0
    DEBUG(1,("Failed to save machine password\n"));
149
0
    return ADS_ERROR_NT(status);
150
0
  }
151
152
0
  return ADS_SUCCESS;
153
0
}
154
#endif
155
156
/**
157
* @brief Parses windows style SPN service/host:port/servicename
158
*      serviceclass - A string that identifies the general class of service
159
*            e.g. 'http'
160
*      host - A netbios name or fully-qualified DNS name
161
*      port - An optional TCP or UDP port number
162
*      servicename - An optional distinguished name, GUID, DNS name or
163
*                    DNS name of an SRV or MX record. (not needed for host
164
*                    based services)
165
*
166
* @param[in]  ctx   - Talloc context.
167
* @param[in]  srvprinc  - The service principal
168
*
169
* @return     - struct spn_struct containing the fields parsed or NULL
170
*       if srvprinc could not be parsed.
171
*/
172
struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc)
173
0
{
174
0
  struct spn_struct * result = NULL;
175
0
  char *tmp = NULL;
176
0
  char *port_str = NULL;
177
0
  char *host_str = NULL;
178
179
0
  result = talloc_zero(ctx, struct spn_struct);
180
0
  if (result == NULL) {
181
0
    DBG_ERR("Out of memory\n");
182
0
    return NULL;
183
0
  }
184
185
0
  result->serviceclass = talloc_strdup(result, srvprinc);
186
0
  if (result->serviceclass == NULL) {
187
0
    DBG_ERR("Out of memory\n");
188
0
    goto fail;
189
0
  }
190
0
  result->port = -1;
191
192
0
  tmp = strchr_m(result->serviceclass, '/');
193
0
  if (tmp == NULL) {
194
    /* illegal */
195
0
    DBG_ERR("Failed to parse spn %s, no host definition\n",
196
0
      srvprinc);
197
0
    goto fail;
198
0
  }
199
200
  /* terminate service principal */
201
0
  *tmp = '\0';
202
0
  tmp++;
203
0
  host_str = tmp;
204
205
0
  tmp = strchr_m(host_str, ':');
206
0
  if (tmp != NULL) {
207
0
    *tmp  = '\0';
208
0
    tmp++;
209
0
    port_str = tmp;
210
0
  } else {
211
0
    tmp = host_str;
212
0
  }
213
214
0
  tmp = strchr_m(tmp, '/');
215
0
  if (tmp != NULL) {
216
0
    *tmp  = '\0';
217
0
    tmp++;
218
0
    result->servicename = tmp;
219
0
  }
220
221
0
  if (strlen(host_str) == 0) {
222
    /* illegal */
223
0
    DBG_ERR("Failed to parse spn %s, illegal host definition\n",
224
0
      srvprinc);
225
0
    goto fail;
226
0
  }
227
0
  result->host = host_str;
228
229
0
  if (result->servicename != NULL && (strlen(result->servicename) == 0)) {
230
0
    DBG_ERR("Failed to parse spn %s, empty servicename "
231
0
      "definition\n", srvprinc);
232
0
    goto fail;
233
0
  }
234
0
  if (port_str != NULL) {
235
0
    if (strlen(port_str) == 0) {
236
0
      DBG_ERR("Failed to parse spn %s, empty port "
237
0
        "definition\n", srvprinc);
238
0
      goto fail;
239
0
    }
240
0
    result->port = (int32_t)strtol(port_str, NULL, 10);
241
0
    if (result->port <= 0
242
0
        || result->port > 65535
243
0
        || errno == ERANGE) {
244
0
      DBG_ERR("Failed to parse spn %s, port number "
245
0
        "conversion failed\n", srvprinc);
246
0
      errno = 0;
247
0
      goto fail;
248
0
    }
249
0
  }
250
0
  return result;
251
0
fail:
252
0
  TALLOC_FREE(result);
253
  return NULL;
254
0
}