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(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset);
114 :
115 4 : 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 4 : status = secrets_finish_password_change(ads->auth.kdc_server, now, info);
129 4 : 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 4 : 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 18 : struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc)
155 : {
156 18 : struct spn_struct * result = NULL;
157 18 : char *tmp = NULL;
158 18 : char *port_str = NULL;
159 18 : char *host_str = NULL;
160 :
161 18 : result = talloc_zero(ctx, struct spn_struct);
162 18 : if (result == NULL) {
163 0 : DBG_ERR("Out of memory\n");
164 0 : return NULL;
165 : }
166 :
167 18 : result->serviceclass = talloc_strdup(result, srvprinc);
168 18 : if (result->serviceclass == NULL) {
169 0 : DBG_ERR("Out of memory\n");
170 0 : goto fail;
171 : }
172 18 : result->port = -1;
173 :
174 18 : tmp = strchr_m(result->serviceclass, '/');
175 18 : if (tmp == NULL) {
176 : /* illegal */
177 2 : DBG_ERR("Failed to parse spn %s, no host definition\n",
178 : srvprinc);
179 2 : goto fail;
180 : }
181 :
182 : /* terminate service principal */
183 16 : *tmp = '\0';
184 16 : tmp++;
185 16 : host_str = tmp;
186 :
187 16 : tmp = strchr_m(host_str, ':');
188 16 : if (tmp != NULL) {
189 6 : *tmp = '\0';
190 6 : tmp++;
191 6 : port_str = tmp;
192 : } else {
193 10 : tmp = host_str;
194 : }
195 :
196 16 : tmp = strchr_m(tmp, '/');
197 16 : if (tmp != NULL) {
198 2 : *tmp = '\0';
199 2 : tmp++;
200 2 : result->servicename = tmp;
201 : }
202 :
203 16 : 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 16 : result->host = host_str;
210 :
211 16 : if (result->servicename != NULL && (strlen(result->servicename) == 0)) {
212 2 : DBG_ERR("Failed to parse spn %s, empty servicename "
213 : "definition\n", srvprinc);
214 2 : goto fail;
215 : }
216 14 : if (port_str != NULL) {
217 6 : if (strlen(port_str) == 0) {
218 2 : DBG_ERR("Failed to parse spn %s, empty port "
219 : "definition\n", srvprinc);
220 2 : goto fail;
221 : }
222 4 : result->port = (int32_t)strtol(port_str, NULL, 10);
223 4 : if (result->port <= 0
224 4 : || result->port > 65535
225 4 : || 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 12 : return result;
233 6 : fail:
234 6 : TALLOC_FREE(result);
235 6 : return NULL;
236 : }
|