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