Line data Source code
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 4 : ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
27 : {
28 4 : const char *password = NULL;
29 4 : const char *new_password = NULL;
30 0 : ADS_STATUS ret;
31 4 : const char *domain = lp_workgroup();
32 4 : struct secrets_domain_info1 *info = NULL;
33 4 : struct secrets_domain_info1_change *prev = NULL;
34 4 : const DATA_BLOB *cleartext_blob = NULL;
35 4 : DATA_BLOB pw_blob = data_blob_null;
36 4 : DATA_BLOB new_pw_blob = data_blob_null;
37 0 : NTSTATUS status;
38 4 : struct timeval tv = timeval_current();
39 4 : NTTIME now = timeval_to_nttime(&tv);
40 4 : int role = lp_server_role();
41 0 : bool ok;
42 :
43 4 : 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 : }
47 :
48 4 : new_password = trust_pw_new_value(talloc_tos(), SEC_CHAN_WKSTA, SEC_ADS);
49 4 : 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 : }
54 :
55 4 : status = secrets_prepare_password_change(domain,
56 : ads->auth.kdc_server,
57 : new_password,
58 : talloc_tos(),
59 : &info, &prev);
60 4 : if (!NT_STATUS_IS_OK(status)) {
61 0 : return ADS_ERROR_NT(status);
62 : }
63 4 : if (prev != NULL) {
64 0 : status = NT_STATUS_REQUEST_NOT_ACCEPTED;
65 0 : secrets_failed_password_change("localhost",
66 : status,
67 0 : NT_STATUS_NOT_COMMITTED,
68 : info);
69 0 : return ADS_ERROR_NT(status);
70 : }
71 :
72 4 : cleartext_blob = &info->password->cleartext_blob;
73 4 : ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
74 4 : cleartext_blob->data,
75 4 : cleartext_blob->length,
76 : (void **)&pw_blob.data,
77 : &pw_blob.length);
78 4 : if (!ok) {
79 0 : status = NT_STATUS_UNMAPPABLE_CHARACTER;
80 0 : if (errno == ENOMEM) {
81 0 : status = NT_STATUS_NO_MEMORY;
82 : }
83 0 : DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
84 : "failed for password of %s - %s\n",
85 : domain, nt_errstr(status));
86 0 : return ADS_ERROR_NT(status);
87 : }
88 4 : password = (const char *)pw_blob.data;
89 :
90 4 : cleartext_blob = &info->next_change->password->cleartext_blob;
91 4 : ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
92 4 : cleartext_blob->data,
93 4 : cleartext_blob->length,
94 : (void **)&new_pw_blob.data,
95 : &new_pw_blob.length);
96 4 : if (!ok) {
97 0 : status = NT_STATUS_UNMAPPABLE_CHARACTER;
98 0 : if (errno == ENOMEM) {
99 0 : status = NT_STATUS_NO_MEMORY;
100 : }
101 0 : DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) "
102 : "failed for new_password of %s - %s\n",
103 : domain, nt_errstr(status));
104 0 : secrets_failed_password_change("localhost",
105 : status,
106 0 : NT_STATUS_NOT_COMMITTED,
107 : info);
108 0 : return ADS_ERROR_NT(status);
109 : }
110 4 : talloc_keep_secret(new_pw_blob.data);
111 4 : new_password = (const char *)new_pw_blob.data;
112 :
113 4 : ret = kerberos_set_password(host_principal,
114 : password,
115 : host_principal,
116 : new_password);
117 :
118 4 : if (!ADS_ERR_OK(ret)) {
119 0 : status = ads_ntstatus(ret);
120 0 : DBG_ERR("kerberos_set_password(%s, %s) "
121 : "failed for new_password of %s - %s\n",
122 : ads->auth.kdc_server, host_principal,
123 : domain, nt_errstr(status));
124 0 : secrets_failed_password_change(ads->auth.kdc_server,
125 0 : NT_STATUS_NOT_COMMITTED,
126 : status,
127 : info);
128 0 : return ret;
129 : }
130 :
131 4 : status = secrets_finish_password_change(ads->auth.kdc_server, now, info);
132 4 : if (!NT_STATUS_IS_OK(status)) {
133 0 : DEBUG(1,("Failed to save machine password\n"));
134 0 : return ADS_ERROR_NT(status);
135 : }
136 :
137 4 : return ADS_SUCCESS;
138 : }
139 : #endif
140 :
141 : /**
142 : * @brief Parses windows style SPN service/host:port/servicename
143 : * serviceclass - A string that identifies the general class of service
144 : * e.g. 'http'
145 : * host - A netbios name or fully-qualified DNS name
146 : * port - An optional TCP or UDP port number
147 : * servicename - An optional distinguished name, GUID, DNS name or
148 : * DNS name of an SRV or MX record. (not needed for host
149 : * based services)
150 : *
151 : * @param[in] ctx - Talloc context.
152 : * @param[in] srvprinc - The service principal
153 : *
154 : * @return - struct spn_struct containing the fields parsed or NULL
155 : * if srvprinc could not be parsed.
156 : */
157 18 : struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc)
158 : {
159 18 : struct spn_struct * result = NULL;
160 18 : char *tmp = NULL;
161 18 : char *port_str = NULL;
162 18 : char *host_str = NULL;
163 :
164 18 : result = talloc_zero(ctx, struct spn_struct);
165 18 : if (result == NULL) {
166 0 : DBG_ERR("Out of memory\n");
167 0 : return NULL;
168 : }
169 :
170 18 : result->serviceclass = talloc_strdup(result, srvprinc);
171 18 : if (result->serviceclass == NULL) {
172 0 : DBG_ERR("Out of memory\n");
173 0 : goto fail;
174 : }
175 18 : result->port = -1;
176 :
177 18 : tmp = strchr_m(result->serviceclass, '/');
178 18 : if (tmp == NULL) {
179 : /* illegal */
180 2 : DBG_ERR("Failed to parse spn %s, no host definition\n",
181 : srvprinc);
182 2 : goto fail;
183 : }
184 :
185 : /* terminate service principal */
186 16 : *tmp = '\0';
187 16 : tmp++;
188 16 : host_str = tmp;
189 :
190 16 : tmp = strchr_m(host_str, ':');
191 16 : if (tmp != NULL) {
192 6 : *tmp = '\0';
193 6 : tmp++;
194 6 : port_str = tmp;
195 : } else {
196 10 : tmp = host_str;
197 : }
198 :
199 16 : tmp = strchr_m(tmp, '/');
200 16 : if (tmp != NULL) {
201 2 : *tmp = '\0';
202 2 : tmp++;
203 2 : result->servicename = tmp;
204 : }
205 :
206 16 : if (strlen(host_str) == 0) {
207 : /* illegal */
208 0 : DBG_ERR("Failed to parse spn %s, illegal host definition\n",
209 : srvprinc);
210 0 : goto fail;
211 : }
212 16 : result->host = host_str;
213 :
214 16 : if (result->servicename != NULL && (strlen(result->servicename) == 0)) {
215 2 : DBG_ERR("Failed to parse spn %s, empty servicename "
216 : "definition\n", srvprinc);
217 2 : goto fail;
218 : }
219 14 : if (port_str != NULL) {
220 6 : if (strlen(port_str) == 0) {
221 2 : DBG_ERR("Failed to parse spn %s, empty port "
222 : "definition\n", srvprinc);
223 2 : goto fail;
224 : }
225 4 : result->port = (int32_t)strtol(port_str, NULL, 10);
226 4 : if (result->port <= 0
227 4 : || result->port > 65535
228 4 : || errno == ERANGE) {
229 0 : DBG_ERR("Failed to parse spn %s, port number "
230 : "conversion failed\n", srvprinc);
231 0 : errno = 0;
232 0 : goto fail;
233 : }
234 : }
235 12 : return result;
236 6 : fail:
237 6 : TALLOC_FREE(result);
238 6 : return NULL;
239 : }
|