ctdb-server: Remove duplicate logic
[samba4-gss.git] / source3 / libads / util.c
blob243dd09f3d05ad5ddc282bcd820f0fb9bb0df0c4
1 /*
2 Unix SMB/CIFS implementation.
3 krb5 set password implementation
4 Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
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.
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.
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/>.
20 #include "includes.h"
21 #include "ads.h"
22 #include "secrets.h"
23 #include "librpc/gen_ndr/ndr_secrets.h"
25 #ifdef HAVE_KRB5
26 ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
28 const char *password = NULL;
29 const char *new_password = NULL;
30 ADS_STATUS ret;
31 const char *domain = lp_workgroup();
32 struct secrets_domain_info1 *info = NULL;
33 struct secrets_domain_info1_change *prev = NULL;
34 const DATA_BLOB *cleartext_blob = NULL;
35 DATA_BLOB pw_blob = data_blob_null;
36 DATA_BLOB new_pw_blob = data_blob_null;
37 NTSTATUS status;
38 struct timeval tv = timeval_current();
39 NTTIME now = timeval_to_nttime(&tv);
40 int role = lp_server_role();
41 bool ok;
43 if (role != ROLE_DOMAIN_MEMBER) {
44 DBG_ERR("Machine account password change only supported on a DOMAIN_MEMBER.\n");
45 return ADS_ERROR_NT(NT_STATUS_INVALID_SERVER_STATE);
48 new_password = trust_pw_new_value(talloc_tos(), SEC_CHAN_WKSTA, SEC_ADS);
49 if (new_password == NULL) {
50 ret = ADS_ERROR_SYSTEM(errno);
51 DEBUG(1,("Failed to generate machine password\n"));
52 return ret;
55 status = secrets_prepare_password_change(domain,
56 ads->auth.kdc_server,
57 new_password,
58 talloc_tos(),
59 &info,
60 &prev,
61 #ifdef HAVE_ADS
62 sync_pw2keytabs);
63 #else
64 NULL);
65 #endif
66 if (!NT_STATUS_IS_OK(status)) {
67 return ADS_ERROR_NT(status);
69 if (prev != NULL) {
70 status = NT_STATUS_REQUEST_NOT_ACCEPTED;
71 secrets_failed_password_change("localhost",
72 status,
73 NT_STATUS_NOT_COMMITTED,
74 info);
75 return ADS_ERROR_NT(status);
78 cleartext_blob = &info->password->cleartext_blob;
79 ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
80 cleartext_blob->data,
81 cleartext_blob->length,
82 (void **)&pw_blob.data,
83 &pw_blob.length);
84 if (!ok) {
85 status = NT_STATUS_UNMAPPABLE_CHARACTER;
86 if (errno == ENOMEM) {
87 status = NT_STATUS_NO_MEMORY;
89 DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
90 "failed for password of %s - %s\n",
91 domain, nt_errstr(status));
92 return ADS_ERROR_NT(status);
94 password = (const char *)pw_blob.data;
96 cleartext_blob = &info->next_change->password->cleartext_blob;
97 ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
98 cleartext_blob->data,
99 cleartext_blob->length,
100 (void **)&new_pw_blob.data,
101 &new_pw_blob.length);
102 if (!ok) {
103 status = NT_STATUS_UNMAPPABLE_CHARACTER;
104 if (errno == ENOMEM) {
105 status = NT_STATUS_NO_MEMORY;
107 DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
108 "failed for new_password of %s - %s\n",
109 domain, nt_errstr(status));
110 secrets_failed_password_change("localhost",
111 status,
112 NT_STATUS_NOT_COMMITTED,
113 info);
114 return ADS_ERROR_NT(status);
116 talloc_keep_secret(new_pw_blob.data);
117 new_password = (const char *)new_pw_blob.data;
119 ret = kerberos_set_password(host_principal,
120 password,
121 host_principal,
122 new_password);
124 if (!ADS_ERR_OK(ret)) {
125 status = ads_ntstatus(ret);
126 DBG_ERR("kerberos_set_password(%s, %s) "
127 "failed for new_password of %s - %s\n",
128 ads->auth.kdc_server, host_principal,
129 domain, nt_errstr(status));
130 secrets_failed_password_change(ads->auth.kdc_server,
131 NT_STATUS_NOT_COMMITTED,
132 status,
133 info);
134 return ret;
137 status = secrets_finish_password_change(ads->auth.kdc_server,
138 now,
139 info,
140 #ifdef HAVE_ADS
141 sync_pw2keytabs);
142 #else
143 NULL);
144 #endif
145 if (!NT_STATUS_IS_OK(status)) {
146 DEBUG(1,("Failed to save machine password\n"));
147 return ADS_ERROR_NT(status);
150 return ADS_SUCCESS;
152 #endif
155 * @brief Parses windows style SPN service/host:port/servicename
156 * serviceclass - A string that identifies the general class of service
157 * e.g. 'http'
158 * host - A netbios name or fully-qualified DNS name
159 * port - An optional TCP or UDP port number
160 * servicename - An optional distinguished name, GUID, DNS name or
161 * DNS name of an SRV or MX record. (not needed for host
162 * based services)
164 * @param[in] ctx - Talloc context.
165 * @param[in] srvprinc - The service principal
167 * @return - struct spn_struct containing the fields parsed or NULL
168 * if srvprinc could not be parsed.
170 struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc)
172 struct spn_struct * result = NULL;
173 char *tmp = NULL;
174 char *port_str = NULL;
175 char *host_str = NULL;
177 result = talloc_zero(ctx, struct spn_struct);
178 if (result == NULL) {
179 DBG_ERR("Out of memory\n");
180 return NULL;
183 result->serviceclass = talloc_strdup(result, srvprinc);
184 if (result->serviceclass == NULL) {
185 DBG_ERR("Out of memory\n");
186 goto fail;
188 result->port = -1;
190 tmp = strchr_m(result->serviceclass, '/');
191 if (tmp == NULL) {
192 /* illegal */
193 DBG_ERR("Failed to parse spn %s, no host definition\n",
194 srvprinc);
195 goto fail;
198 /* terminate service principal */
199 *tmp = '\0';
200 tmp++;
201 host_str = tmp;
203 tmp = strchr_m(host_str, ':');
204 if (tmp != NULL) {
205 *tmp = '\0';
206 tmp++;
207 port_str = tmp;
208 } else {
209 tmp = host_str;
212 tmp = strchr_m(tmp, '/');
213 if (tmp != NULL) {
214 *tmp = '\0';
215 tmp++;
216 result->servicename = tmp;
219 if (strlen(host_str) == 0) {
220 /* illegal */
221 DBG_ERR("Failed to parse spn %s, illegal host definition\n",
222 srvprinc);
223 goto fail;
225 result->host = host_str;
227 if (result->servicename != NULL && (strlen(result->servicename) == 0)) {
228 DBG_ERR("Failed to parse spn %s, empty servicename "
229 "definition\n", srvprinc);
230 goto fail;
232 if (port_str != NULL) {
233 if (strlen(port_str) == 0) {
234 DBG_ERR("Failed to parse spn %s, empty port "
235 "definition\n", srvprinc);
236 goto fail;
238 result->port = (int32_t)strtol(port_str, NULL, 10);
239 if (result->port <= 0
240 || result->port > 65535
241 || errno == ERANGE) {
242 DBG_ERR("Failed to parse spn %s, port number "
243 "conversion failed\n", srvprinc);
244 errno = 0;
245 goto fail;
248 return result;
249 fail:
250 TALLOC_FREE(result);
251 return NULL;