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 0 : ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
27 : {
28 0 : const char *password = NULL;
29 0 : const char *new_password = NULL;
30 : 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 : 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 : 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 : }
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 : }
54 :
55 0 : status = secrets_prepare_password_change(domain,
56 : ads->auth.kdc_server,
57 : new_password,
58 : talloc_tos(),
59 : &info, &prev);
60 0 : if (!NT_STATUS_IS_OK(status)) {
61 0 : return ADS_ERROR_NT(status);
62 : }
63 0 : 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 0 : cleartext_blob = &info->password->cleartext_blob;
73 0 : ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
74 0 : cleartext_blob->data,
75 0 : cleartext_blob->length,
76 : (void **)&pw_blob.data,
77 : &pw_blob.length);
78 0 : 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 0 : password = (const char *)pw_blob.data;
89 :
90 0 : cleartext_blob = &info->next_change->password->cleartext_blob;
91 0 : ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX,
92 0 : cleartext_blob->data,
93 0 : cleartext_blob->length,
94 : (void **)&new_pw_blob.data,
95 : &new_pw_blob.length);
96 0 : 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 0 : talloc_keep_secret(new_pw_blob.data);
111 0 : new_password = (const char *)new_pw_blob.data;
112 :
113 0 : ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset);
114 :
115 0 : if (!ADS_ERR_OK(ret)) {
116 0 : status = ads_ntstatus(ret);
117 0 : DBG_ERR("kerberos_set_password(%s, %s) "
118 : "failed for new_password of %s - %s\n",
119 : ads->auth.kdc_server, host_principal,
120 : domain, nt_errstr(status));
121 0 : secrets_failed_password_change(ads->auth.kdc_server,
122 0 : NT_STATUS_NOT_COMMITTED,
123 : status,
124 : info);
125 0 : return ret;
126 : }
127 :
128 0 : status = secrets_finish_password_change(ads->auth.kdc_server, now, info);
129 0 : if (!NT_STATUS_IS_OK(status)) {
130 0 : DEBUG(1,("Failed to save machine password\n"));
131 0 : return ADS_ERROR_NT(status);
132 : }
133 :
134 0 : return ADS_SUCCESS;
135 : }
136 : #endif
137 :
138 : /**
139 : * @brief Parses windows style SPN service/host:port/servicename
140 : * serviceclass - A string that identifies the general class of service
141 : * e.g. 'http'
142 : * host - A netbios name or fully-qualified DNS name
143 : * port - An optional TCP or UDP port number
144 : * servicename - An optional distinguished name, GUID, DNS name or
145 : * DNS name of an SRV or MX record. (not needed for host
146 : * based services)
147 : *
148 : * @param[in] ctx - Talloc context.
149 : * @param[in] srvprinc - The service principal
150 : *
151 : * @return - struct spn_struct containing the fields parsed or NULL
152 : * if srvprinc could not be parsed.
153 : */
154 0 : struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc)
155 : {
156 0 : struct spn_struct * result = NULL;
157 0 : char *tmp = NULL;
158 0 : char *port_str = NULL;
159 0 : char *host_str = NULL;
160 :
161 0 : result = talloc_zero(ctx, struct spn_struct);
162 0 : if (result == NULL) {
163 0 : DBG_ERR("Out of memory\n");
164 0 : return NULL;
165 : }
166 :
167 0 : result->serviceclass = talloc_strdup(result, srvprinc);
168 0 : if (result->serviceclass == NULL) {
169 0 : DBG_ERR("Out of memory\n");
170 0 : goto fail;
171 : }
172 0 : result->port = -1;
173 :
174 0 : tmp = strchr_m(result->serviceclass, '/');
175 0 : if (tmp == NULL) {
176 : /* illegal */
177 0 : DBG_ERR("Failed to parse spn %s, no host definition\n",
178 : srvprinc);
179 0 : goto fail;
180 : }
181 :
182 : /* terminate service principal */
183 0 : *tmp = '\0';
184 0 : tmp++;
185 0 : host_str = tmp;
186 :
187 0 : tmp = strchr_m(host_str, ':');
188 0 : if (tmp != NULL) {
189 0 : *tmp = '\0';
190 0 : tmp++;
191 0 : port_str = tmp;
192 : } else {
193 0 : tmp = host_str;
194 : }
195 :
196 0 : tmp = strchr_m(tmp, '/');
197 0 : if (tmp != NULL) {
198 0 : *tmp = '\0';
199 0 : tmp++;
200 0 : result->servicename = tmp;
201 : }
202 :
203 0 : if (strlen(host_str) == 0) {
204 : /* illegal */
205 0 : DBG_ERR("Failed to parse spn %s, illegal host definition\n",
206 : srvprinc);
207 0 : goto fail;
208 : }
209 0 : result->host = host_str;
210 :
211 0 : if (result->servicename != NULL && (strlen(result->servicename) == 0)) {
212 0 : DBG_ERR("Failed to parse spn %s, empty servicename "
213 : "definition\n", srvprinc);
214 0 : goto fail;
215 : }
216 0 : if (port_str != NULL) {
217 0 : if (strlen(port_str) == 0) {
218 0 : DBG_ERR("Failed to parse spn %s, empty port "
219 : "definition\n", srvprinc);
220 0 : goto fail;
221 : }
222 0 : result->port = (int32_t)strtol(port_str, NULL, 10);
223 0 : if (result->port <= 0
224 0 : || result->port > 65535
225 0 : || errno == ERANGE) {
226 0 : DBG_ERR("Failed to parse spn %s, port number "
227 : "conversion failed\n", srvprinc);
228 0 : errno = 0;
229 0 : goto fail;
230 : }
231 : }
232 0 : return result;
233 0 : fail:
234 0 : TALLOC_FREE(result);
235 0 : return NULL;
236 : }
|