s4:torture: Fix talloc_array in test_EnumValue()
[Samba.git] / source4 / kdc / kpasswd-service.c
blobb36cf402228349226736cba86539d66f0135089c
1 /*
2 Unix SMB/CIFS implementation.
4 Samba kpasswd implementation
6 Copyright (c) 2005 Andrew Bartlett <abartlet@samba.org>
7 Copyright (c) 2016 Andreas Schneider <asn@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "smbd/service_task.h"
25 #include "tsocket/tsocket.h"
26 #include "auth/credentials/credentials.h"
27 #include "auth/auth.h"
28 #include "auth/gensec/gensec.h"
29 #include "kdc/kdc-server.h"
30 #include "kdc/kpasswd-service.h"
31 #include "kdc/kpasswd-helper.h"
33 #define HEADER_LEN 6
34 #ifndef RFC3244_VERSION
35 #define RFC3244_VERSION 0xff80
36 #endif
38 kdc_code kpasswd_process(struct kdc_server *kdc,
39 TALLOC_CTX *mem_ctx,
40 DATA_BLOB *request,
41 DATA_BLOB *reply,
42 struct tsocket_address *remote_addr,
43 struct tsocket_address *local_addr,
44 int datagram)
46 uint16_t len;
47 uint16_t verno;
48 uint16_t ap_req_len;
49 uint16_t enc_data_len;
50 DATA_BLOB ap_req_blob = data_blob_null;
51 DATA_BLOB ap_rep_blob = data_blob_null;
52 DATA_BLOB enc_data_blob = data_blob_null;
53 DATA_BLOB dec_data_blob = data_blob_null;
54 DATA_BLOB kpasswd_dec_reply = data_blob_null;
55 const char *error_string = NULL;
56 krb5_error_code error_code = 0;
57 struct cli_credentials *server_credentials;
58 struct gensec_security *gensec_security;
59 #ifndef SAMBA4_USES_HEIMDAL
60 struct sockaddr_storage remote_ss;
61 #endif
62 struct sockaddr_storage local_ss;
63 ssize_t socklen;
64 TALLOC_CTX *tmp_ctx;
65 kdc_code rc = KDC_ERROR;
66 krb5_error_code code = 0;
67 NTSTATUS status;
68 int rv;
69 bool is_inet;
70 bool ok;
72 if (kdc->am_rodc) {
73 return KDC_PROXY_REQUEST;
76 tmp_ctx = talloc_new(mem_ctx);
77 if (tmp_ctx == NULL) {
78 return KDC_ERROR;
81 is_inet = tsocket_address_is_inet(remote_addr, "ip");
82 if (!is_inet) {
83 DBG_WARNING("Invalid remote IP address");
84 goto done;
87 #ifndef SAMBA4_USES_HEIMDAL
89 * FIXME: Heimdal fails to to do a krb5_rd_req() in gensec_krb5 if we
90 * set the remote address.
93 /* remote_addr */
94 socklen = tsocket_address_bsd_sockaddr(remote_addr,
95 (struct sockaddr *)&remote_ss,
96 sizeof(struct sockaddr_storage));
97 if (socklen < 0) {
98 DBG_WARNING("Invalid remote IP address");
99 goto done;
101 #endif
103 /* local_addr */
104 socklen = tsocket_address_bsd_sockaddr(local_addr,
105 (struct sockaddr *)&local_ss,
106 sizeof(struct sockaddr_storage));
107 if (socklen < 0) {
108 DBG_WARNING("Invalid local IP address");
109 goto done;
112 if (request->length <= HEADER_LEN) {
113 DBG_WARNING("Request truncated\n");
114 goto done;
117 len = RSVAL(request->data, 0);
118 if (request->length != len) {
119 DBG_WARNING("Request length does not match\n");
120 goto done;
123 verno = RSVAL(request->data, 2);
124 if (verno != 1 && verno != RFC3244_VERSION) {
125 DBG_WARNING("Unsupported version: 0x%04x\n", verno);
128 ap_req_len = RSVAL(request->data, 4);
129 if ((ap_req_len >= len) || ((ap_req_len + HEADER_LEN) >= len)) {
130 DBG_WARNING("AP_REQ truncated\n");
131 goto done;
134 ap_req_blob = data_blob_const(&request->data[HEADER_LEN], ap_req_len);
136 enc_data_len = len - ap_req_len;
137 enc_data_blob = data_blob_const(&request->data[HEADER_LEN + ap_req_len],
138 enc_data_len);
140 server_credentials = cli_credentials_init(tmp_ctx);
141 if (server_credentials == NULL) {
142 DBG_ERR("Failed to initialize server credentials!\n");
143 goto done;
147 * We want the credentials subsystem to use the krb5 context we already
148 * have, rather than a new context.
150 * On this context the KDB plugin has been loaded, so we can access
151 * dsdb.
153 status = cli_credentials_set_krb5_context(server_credentials,
154 kdc->smb_krb5_context);
155 if (!NT_STATUS_IS_OK(status)) {
156 goto done;
159 cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx);
161 ok = cli_credentials_set_username(server_credentials,
162 "kadmin/changepw",
163 CRED_SPECIFIED);
164 if (!ok) {
165 goto done;
168 rv = cli_credentials_set_keytab_name(server_credentials,
169 kdc->task->lp_ctx,
170 kdc->keytab_name,
171 CRED_SPECIFIED);
172 if (rv != 0) {
173 DBG_ERR("Failed to set credentials keytab name\n");
174 goto done;
177 status = samba_server_gensec_start(tmp_ctx,
178 kdc->task->event_ctx,
179 kdc->task->msg_ctx,
180 kdc->task->lp_ctx,
181 server_credentials,
182 "kpasswd",
183 &gensec_security);
184 if (!NT_STATUS_IS_OK(status)) {
185 goto done;
188 status = gensec_set_local_address(gensec_security, local_addr);
189 if (!NT_STATUS_IS_OK(status)) {
190 goto done;
193 #ifndef SAMBA4_USES_HEIMDAL
194 status = gensec_set_remote_address(gensec_security, remote_addr);
195 if (!NT_STATUS_IS_OK(status)) {
196 goto done;
198 #endif
200 /* We want the GENSEC wrap calls to generate PRIV tokens */
201 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
203 /* Use the krb5 gesec mechanism so we can load DB modules */
204 status = gensec_start_mech_by_name(gensec_security, "krb5");
205 if (!NT_STATUS_IS_OK(status)) {
206 goto done;
210 * Accept the AP-REQ and generate the AP-REP we need for the reply
212 * We only allow KRB5 and make sure the backend to is RPC/IPC free.
214 * See gensec_krb5_update_internal() as GENSEC_SERVER.
216 * It allows gensec_update() not to block.
218 * If that changes in future we need to use
219 * gensec_update_send/recv here!
221 status = gensec_update(gensec_security, tmp_ctx,
222 ap_req_blob, &ap_rep_blob);
223 if (!NT_STATUS_IS_OK(status) &&
224 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
225 ap_rep_blob = data_blob_null;
226 error_code = KRB5_KPASSWD_HARDERROR;
227 error_string = talloc_asprintf(tmp_ctx,
228 "gensec_update failed - %s\n",
229 nt_errstr(status));
230 DBG_ERR("%s", error_string);
231 goto reply;
234 status = gensec_unwrap(gensec_security,
235 tmp_ctx,
236 &enc_data_blob,
237 &dec_data_blob);
238 if (!NT_STATUS_IS_OK(status)) {
239 ap_rep_blob = data_blob_null;
240 error_code = KRB5_KPASSWD_HARDERROR;
241 error_string = talloc_asprintf(tmp_ctx,
242 "gensec_unwrap failed - %s\n",
243 nt_errstr(status));
244 DBG_ERR("%s", error_string);
245 goto reply;
248 code = kpasswd_handle_request(kdc,
249 tmp_ctx,
250 gensec_security,
251 verno,
252 &dec_data_blob,
253 &kpasswd_dec_reply,
254 &error_string);
255 if (code != 0) {
256 error_code = code;
257 goto reply;
260 status = gensec_wrap(gensec_security,
261 tmp_ctx,
262 &kpasswd_dec_reply,
263 &enc_data_blob);
264 if (!NT_STATUS_IS_OK(status)) {
265 error_code = KRB5_KPASSWD_HARDERROR;
266 error_string = talloc_asprintf(tmp_ctx,
267 "gensec_wrap failed - %s\n",
268 nt_errstr(status));
269 DBG_ERR("%s", error_string);
270 goto reply;
273 reply:
274 if (error_code != 0) {
275 krb5_data k_enc_data;
276 krb5_data k_dec_data;
277 const char *principal_string;
278 krb5_principal server_principal;
280 if (error_string == NULL) {
281 DBG_ERR("Invalid error string! This should not happen\n");
282 goto done;
285 ok = kpasswd_make_error_reply(tmp_ctx,
286 error_code,
287 error_string,
288 &dec_data_blob);
289 if (!ok) {
290 DBG_ERR("Failed to create error reply\n");
291 goto done;
294 k_dec_data.length = dec_data_blob.length;
295 k_dec_data.data = (char *)dec_data_blob.data;
297 principal_string = cli_credentials_get_principal(server_credentials,
298 tmp_ctx);
299 if (principal_string == NULL) {
300 goto done;
303 code = smb_krb5_parse_name(kdc->smb_krb5_context->krb5_context,
304 principal_string,
305 &server_principal);
306 if (code != 0) {
307 DBG_ERR("Failed to create principal: %s\n",
308 error_message(code));
309 goto done;
312 code = smb_krb5_mk_error(kdc->smb_krb5_context->krb5_context,
313 error_code,
314 NULL, /* e_text */
315 &k_dec_data,
316 NULL, /* client */
317 server_principal,
318 &k_enc_data);
319 krb5_free_principal(kdc->smb_krb5_context->krb5_context,
320 server_principal);
321 if (code != 0) {
322 DBG_ERR("Failed to create krb5 error reply: %s\n",
323 error_message(code));
324 goto done;
327 enc_data_blob = data_blob_talloc(tmp_ctx,
328 k_enc_data.data,
329 k_enc_data.length);
330 if (enc_data_blob.data == NULL) {
331 DBG_ERR("Failed to allocate memory for error reply\n");
332 goto done;
336 *reply = data_blob_talloc(mem_ctx,
337 NULL,
338 HEADER_LEN + ap_rep_blob.length + enc_data_blob.length);
339 if (reply->data == NULL) {
340 goto done;
342 RSSVAL(reply->data, 0, reply->length);
343 RSSVAL(reply->data, 2, 1);
344 RSSVAL(reply->data, 4, ap_rep_blob.length);
345 memcpy(reply->data + HEADER_LEN,
346 ap_rep_blob.data,
347 ap_rep_blob.length);
348 memcpy(reply->data + HEADER_LEN + ap_rep_blob.length,
349 enc_data_blob.data,
350 enc_data_blob.length);
352 rc = KDC_OK;
353 done:
354 talloc_free(tmp_ctx);
355 return rc;