Line data Source code
1 : /*
2 : MIT-Samba4 library
3 :
4 : Copyright (c) 2010, Simo Sorce <idra@samba.org>
5 : Copyright (c) 2014-2015 Guenther Deschner <gd@samba.org>
6 : Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #define TEVENT_DEPRECATED 1
23 :
24 : #include "includes.h"
25 : #include "param/param.h"
26 : #include "dsdb/samdb/samdb.h"
27 : #include "system/kerberos.h"
28 : #include "lib/replace/system/filesys.h"
29 : #include <com_err.h>
30 : #include <kdb.h>
31 : #include <kadm5/kadm_err.h>
32 : #include "kdc/sdb.h"
33 : #include "kdc/sdb_kdb.h"
34 : #include "auth/kerberos/kerberos.h"
35 : #include "auth/kerberos/pac_utils.h"
36 : #include "kdc/samba_kdc.h"
37 : #include "kdc/pac-glue.h"
38 : #include "kdc/db-glue.h"
39 : #include "auth/auth.h"
40 : #include "kdc/kpasswd_glue.h"
41 : #include "auth/auth_sam.h"
42 :
43 : #include "mit_samba.h"
44 :
45 : #undef DBGC_CLASS
46 : #define DBGC_CLASS DBGC_KERBEROS
47 :
48 17 : void mit_samba_context_free(struct mit_samba_context *ctx)
49 : {
50 : /* free MIT's krb5_context */
51 17 : if (ctx->context) {
52 17 : krb5_free_context(ctx->context);
53 : }
54 :
55 : /* then free everything else */
56 17 : talloc_free(ctx);
57 17 : }
58 :
59 : /*
60 : * Implement a callback to log to the MIT KDC log facility
61 : *
62 : * http://web.mit.edu/kerberos/krb5-devel/doc/plugindev/general.html#logging-from-kdc-and-kadmind-plugin-modules
63 : */
64 128 : static void mit_samba_debug(void *private_ptr, int msg_level, const char *msg)
65 : {
66 128 : int is_error = errno;
67 :
68 128 : if (msg_level > 0) {
69 48 : is_error = 0;
70 : }
71 :
72 128 : com_err("mitkdc", is_error, "%s", msg);
73 128 : }
74 :
75 17 : krb5_error_code mit_samba_context_init(struct mit_samba_context **_ctx)
76 : {
77 : NTSTATUS status;
78 : struct mit_samba_context *ctx;
79 : const char *s4_conf_file;
80 : krb5_error_code ret;
81 17 : struct samba_kdc_base_context base_ctx = {};
82 :
83 17 : ctx = talloc_zero(NULL, struct mit_samba_context);
84 17 : if (!ctx) {
85 0 : ret = ENOMEM;
86 0 : goto done;
87 : }
88 :
89 17 : base_ctx.ev_ctx = tevent_context_init(ctx);
90 17 : if (!base_ctx.ev_ctx) {
91 0 : ret = ENOMEM;
92 0 : goto done;
93 : }
94 17 : tevent_loop_allow_nesting(base_ctx.ev_ctx);
95 17 : base_ctx.lp_ctx = loadparm_init_global(false);
96 17 : if (!base_ctx.lp_ctx) {
97 0 : ret = ENOMEM;
98 0 : goto done;
99 : }
100 :
101 17 : debug_set_callback(NULL, mit_samba_debug);
102 :
103 : /* init s4 configuration */
104 17 : s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
105 17 : if (s4_conf_file != NULL) {
106 17 : char *p = talloc_strdup(ctx, s4_conf_file);
107 17 : if (p == NULL) {
108 0 : ret = ENOMEM;
109 0 : goto done;
110 : }
111 17 : lpcfg_load(base_ctx.lp_ctx, p);
112 17 : TALLOC_FREE(p);
113 : } else {
114 0 : lpcfg_load_default(base_ctx.lp_ctx);
115 : }
116 :
117 17 : status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
118 17 : if (!NT_STATUS_IS_OK(status)) {
119 0 : ret = EINVAL;
120 0 : goto done;
121 : }
122 :
123 : /* init MIT's krb_context and log facilities */
124 17 : ret = smb_krb5_init_context_basic(ctx,
125 17 : ctx->db_ctx->lp_ctx,
126 : &ctx->context);
127 17 : if (ret) {
128 0 : goto done;
129 : }
130 :
131 17 : ret = 0;
132 :
133 17 : done:
134 17 : if (ret) {
135 0 : mit_samba_context_free(ctx);
136 : } else {
137 17 : *_ctx = ctx;
138 : }
139 17 : return ret;
140 : }
141 :
142 0 : int mit_samba_generate_salt(krb5_data *salt)
143 : {
144 0 : if (salt == NULL) {
145 0 : return EINVAL;
146 : }
147 :
148 0 : salt->length = 16;
149 0 : salt->data = malloc(salt->length);
150 0 : if (salt->data == NULL) {
151 0 : return ENOMEM;
152 : }
153 :
154 0 : generate_random_buffer((uint8_t *)salt->data, salt->length);
155 :
156 0 : return 0;
157 : }
158 :
159 0 : int mit_samba_generate_random_password(krb5_data *pwd)
160 : {
161 : TALLOC_CTX *tmp_ctx;
162 : char *password;
163 0 : char *data = NULL;
164 0 : const unsigned length = 24;
165 :
166 0 : if (pwd == NULL) {
167 0 : return EINVAL;
168 : }
169 :
170 0 : tmp_ctx = talloc_named(NULL,
171 : 0,
172 : "mit_samba_generate_random_password context");
173 0 : if (tmp_ctx == NULL) {
174 0 : return ENOMEM;
175 : }
176 :
177 0 : password = generate_random_password(tmp_ctx, length, length);
178 0 : if (password == NULL) {
179 0 : talloc_free(tmp_ctx);
180 0 : return ENOMEM;
181 : }
182 :
183 0 : data = strdup(password);
184 0 : talloc_free(tmp_ctx);
185 0 : if (data == NULL) {
186 0 : return ENOMEM;
187 : }
188 :
189 0 : *pwd = smb_krb5_make_data(data, length);
190 :
191 0 : return 0;
192 : }
193 :
194 92 : krb5_error_code mit_samba_get_principal(struct mit_samba_context *ctx,
195 : krb5_const_principal principal,
196 : unsigned int kflags,
197 : krb5_db_entry **_kentry)
198 : {
199 92 : struct sdb_entry sentry = {};
200 : krb5_db_entry *kentry;
201 : krb5_error_code ret;
202 92 : uint32_t sflags = 0;
203 92 : krb5_principal referral_principal = NULL;
204 :
205 92 : kentry = calloc(1, sizeof(krb5_db_entry));
206 92 : if (kentry == NULL) {
207 0 : return ENOMEM;
208 : }
209 :
210 : /*
211 : * The MIT KDC code that wants the canonical name in all lookups, and
212 : * takes care to canonicalize only when appropriate.
213 : */
214 92 : sflags |= SDB_F_FORCE_CANON;
215 :
216 92 : if (kflags & KRB5_KDB_FLAG_REFERRAL_OK) {
217 0 : sflags |= SDB_F_CANON;
218 : }
219 :
220 92 : if (kflags & KRB5_KDB_FLAG_CLIENT) {
221 0 : sflags |= SDB_F_GET_CLIENT;
222 0 : sflags |= SDB_F_FOR_AS_REQ;
223 : } else {
224 92 : int equal = smb_krb5_principal_is_tgs(ctx->context, principal);
225 92 : if (equal == -1) {
226 0 : return ENOMEM;
227 : }
228 :
229 92 : if (equal) {
230 0 : sflags |= SDB_F_GET_KRBTGT;
231 : } else {
232 92 : sflags |= SDB_F_GET_SERVER;
233 92 : sflags |= SDB_F_FOR_TGS_REQ;
234 : }
235 : }
236 :
237 : /* always set this or the created_by data will not be populated by samba's
238 : * backend and we will fail to parse the entry later */
239 92 : sflags |= SDB_F_ADMIN_DATA;
240 :
241 :
242 92 : fetch_referral_principal:
243 92 : ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
244 : principal, sflags, 0, &sentry);
245 92 : switch (ret) {
246 92 : case 0:
247 92 : break;
248 0 : case SDB_ERR_NOENTRY:
249 0 : ret = KRB5_KDB_NOENTRY;
250 0 : goto done;
251 0 : case SDB_ERR_WRONG_REALM: {
252 0 : char *dest_realm = NULL;
253 0 : const char *our_realm = lpcfg_realm(ctx->db_ctx->lp_ctx);
254 :
255 0 : if (sflags & SDB_F_FOR_AS_REQ) {
256 : /*
257 : * If this is a request for a TGT, we are done. The KDC
258 : * will return the correct error to the client.
259 : */
260 0 : ret = 0;
261 0 : break;
262 : }
263 :
264 0 : if (referral_principal != NULL) {
265 0 : sdb_entry_free(&sentry);
266 0 : ret = KRB5_KDB_NOENTRY;
267 0 : goto done;
268 : }
269 :
270 : /*
271 : * We get a TGS request
272 : *
273 : * cifs/dc7.SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
274 : *
275 : * to our DC for the realm
276 : *
277 : * ADDOM.SAMBA.EXAMPLE.COM
278 : *
279 : * We look up if we have an entry in the database and get an
280 : * entry with the principal:
281 : *
282 : * cifs/dc7.SAMBA2008R2.EXAMPLE.COM@SAMBA2008R2.EXAMPLE.COM
283 : *
284 : * and the error: SDB_ERR_WRONG_REALM.
285 : *
286 : * In the case of a TGS-REQ we need to return a referral ticket
287 : * for the next trust hop to the client. This ticket will have
288 : * the following principal:
289 : *
290 : * krbtgt/SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
291 : *
292 : * We just redo the lookup in the database with the referral
293 : * principal and return success.
294 : */
295 0 : dest_realm = smb_krb5_principal_get_realm(
296 0 : ctx, ctx->context, sentry.principal);
297 0 : sdb_entry_free(&sentry);
298 0 : if (dest_realm == NULL) {
299 0 : ret = KRB5_KDB_NOENTRY;
300 0 : goto done;
301 : }
302 :
303 0 : ret = smb_krb5_make_principal(ctx->context,
304 : &referral_principal,
305 : our_realm,
306 : KRB5_TGS_NAME,
307 : dest_realm,
308 : NULL);
309 0 : TALLOC_FREE(dest_realm);
310 0 : if (ret != 0) {
311 0 : goto done;
312 : }
313 :
314 0 : principal = referral_principal;
315 0 : goto fetch_referral_principal;
316 : }
317 0 : case SDB_ERR_NOT_FOUND_HERE:
318 : /* FIXME: RODC support */
319 : default:
320 0 : goto done;
321 : }
322 :
323 92 : ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
324 :
325 92 : sdb_entry_free(&sentry);
326 :
327 92 : done:
328 92 : krb5_free_principal(ctx->context, referral_principal);
329 92 : referral_principal = NULL;
330 :
331 92 : if (ret) {
332 0 : free(kentry);
333 : } else {
334 92 : *_kentry = kentry;
335 : }
336 92 : return ret;
337 : }
338 :
339 0 : krb5_error_code mit_samba_get_firstkey(struct mit_samba_context *ctx,
340 : krb5_db_entry **_kentry)
341 : {
342 0 : struct sdb_entry sentry = {};
343 : krb5_db_entry *kentry;
344 : krb5_error_code ret;
345 :
346 0 : kentry = malloc(sizeof(krb5_db_entry));
347 0 : if (kentry == NULL) {
348 0 : return ENOMEM;
349 : }
350 :
351 0 : ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
352 0 : switch (ret) {
353 0 : case 0:
354 0 : break;
355 0 : case SDB_ERR_NOENTRY:
356 0 : free(kentry);
357 0 : return KRB5_KDB_NOENTRY;
358 0 : case SDB_ERR_NOT_FOUND_HERE:
359 : /* FIXME: RODC support */
360 : default:
361 0 : free(kentry);
362 0 : return ret;
363 : }
364 :
365 0 : ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
366 :
367 0 : sdb_entry_free(&sentry);
368 :
369 0 : if (ret) {
370 0 : free(kentry);
371 : } else {
372 0 : *_kentry = kentry;
373 : }
374 0 : return ret;
375 : }
376 :
377 0 : krb5_error_code mit_samba_get_nextkey(struct mit_samba_context *ctx,
378 : krb5_db_entry **_kentry)
379 : {
380 0 : struct sdb_entry sentry = {};
381 : krb5_db_entry *kentry;
382 : krb5_error_code ret;
383 :
384 0 : kentry = malloc(sizeof(krb5_db_entry));
385 0 : if (kentry == NULL) {
386 0 : return ENOMEM;
387 : }
388 :
389 0 : ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
390 0 : switch (ret) {
391 0 : case 0:
392 0 : break;
393 0 : case SDB_ERR_NOENTRY:
394 0 : free(kentry);
395 0 : return KRB5_KDB_NOENTRY;
396 0 : case SDB_ERR_NOT_FOUND_HERE:
397 : /* FIXME: RODC support */
398 : default:
399 0 : free(kentry);
400 0 : return ret;
401 : }
402 :
403 0 : ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
404 :
405 0 : sdb_entry_free(&sentry);
406 :
407 0 : if (ret) {
408 0 : free(kentry);
409 : } else {
410 0 : *_kentry = kentry;
411 : }
412 0 : return ret;
413 : }
414 :
415 0 : krb5_error_code mit_samba_get_pac(struct mit_samba_context *smb_ctx,
416 : krb5_context context,
417 : uint32_t flags,
418 : krb5_db_entry *client,
419 : krb5_db_entry *server,
420 : krb5_keyblock *replaced_reply_key,
421 : krb5_pac *pac)
422 : {
423 : TALLOC_CTX *tmp_ctx;
424 0 : const struct auth_user_info_dc *user_info_dc = NULL;
425 0 : struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
426 0 : DATA_BLOB *logon_info_blob = NULL;
427 0 : DATA_BLOB *upn_dns_info_blob = NULL;
428 0 : DATA_BLOB *cred_ndr = NULL;
429 0 : DATA_BLOB **cred_ndr_ptr = NULL;
430 0 : DATA_BLOB cred_blob = data_blob_null;
431 0 : DATA_BLOB *pcred_blob = NULL;
432 0 : DATA_BLOB *pac_attrs_blob = NULL;
433 0 : DATA_BLOB *requester_sid_blob = NULL;
434 0 : const DATA_BLOB *client_claims_blob = NULL;
435 : NTSTATUS nt_status;
436 : krb5_error_code code;
437 : struct samba_kdc_entry *skdc_entry;
438 0 : struct samba_kdc_entry *server_entry = NULL;
439 : bool is_krbtgt;
440 : /* Only include resource groups in a service ticket. */
441 : enum auth_group_inclusion group_inclusion;
442 0 : enum samba_asserted_identity asserted_identity =
443 0 : (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
444 0 : SAMBA_ASSERTED_IDENTITY_SERVICE :
445 : SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
446 :
447 0 : if (client == NULL) {
448 0 : return EINVAL;
449 : }
450 0 : skdc_entry = talloc_get_type_abort(client->e_data,
451 : struct samba_kdc_entry);
452 :
453 0 : if (server == NULL) {
454 0 : return EINVAL;
455 : }
456 : {
457 0 : int result = smb_krb5_principal_is_tgs(smb_ctx->context, server->princ);
458 0 : if (result == -1) {
459 0 : return ENOMEM;
460 : }
461 :
462 0 : is_krbtgt = result;
463 : }
464 0 : server_entry = talloc_get_type_abort(server->e_data,
465 : struct samba_kdc_entry);
466 :
467 : /* Only include resource groups in a service ticket. */
468 0 : if (is_krbtgt) {
469 0 : group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
470 0 : } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
471 0 : group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
472 : } else {
473 0 : group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
474 : }
475 :
476 0 : tmp_ctx = talloc_named(smb_ctx,
477 : 0,
478 : "mit_samba_get_pac context");
479 0 : if (tmp_ctx == NULL) {
480 0 : return ENOMEM;
481 : }
482 :
483 : /* Check if we have a PREAUTH key */
484 0 : if (replaced_reply_key != NULL) {
485 0 : cred_ndr_ptr = &cred_ndr;
486 : }
487 :
488 0 : code = samba_kdc_get_user_info_from_db(tmp_ctx,
489 0 : server_entry->kdc_db_ctx->samdb,
490 : skdc_entry,
491 0 : skdc_entry->msg,
492 : &user_info_dc);
493 0 : if (code) {
494 0 : talloc_free(tmp_ctx);
495 0 : return code;
496 : }
497 :
498 : /* Make a shallow copy of the user_info_dc structure. */
499 0 : nt_status = authsam_shallow_copy_user_info_dc(tmp_ctx,
500 : user_info_dc,
501 : &user_info_dc_shallow_copy);
502 0 : user_info_dc = NULL;
503 :
504 0 : if (!NT_STATUS_IS_OK(nt_status)) {
505 0 : DBG_ERR("Failed to allocate shallow copy of user_info_dc: %s\n",
506 : nt_errstr(nt_status));
507 0 : talloc_free(tmp_ctx);
508 0 : return map_errno_from_nt_status(nt_status);
509 : }
510 :
511 :
512 0 : nt_status = samba_kdc_add_asserted_identity(asserted_identity,
513 : user_info_dc_shallow_copy);
514 0 : if (!NT_STATUS_IS_OK(nt_status)) {
515 0 : DBG_ERR("Failed to add asserted identity: %s\n",
516 : nt_errstr(nt_status));
517 0 : talloc_free(tmp_ctx);
518 0 : return EINVAL;
519 : }
520 :
521 0 : nt_status = samba_kdc_add_claims_valid(user_info_dc_shallow_copy);
522 0 : if (!NT_STATUS_IS_OK(nt_status)) {
523 0 : DBG_ERR("Failed to add Claims Valid: %s\n",
524 : nt_errstr(nt_status));
525 0 : talloc_free(tmp_ctx);
526 0 : return EINVAL;
527 : }
528 :
529 : /* We no longer need to modify this, so assign to const variable */
530 0 : user_info_dc = user_info_dc_shallow_copy;
531 :
532 0 : nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
533 : user_info_dc,
534 : group_inclusion,
535 : &logon_info_blob);
536 0 : if (!NT_STATUS_IS_OK(nt_status)) {
537 0 : talloc_free(tmp_ctx);
538 0 : return EINVAL;
539 : }
540 :
541 0 : if (cred_ndr_ptr != NULL) {
542 0 : nt_status = samba_kdc_get_cred_ndr_blob(tmp_ctx,
543 : skdc_entry,
544 : cred_ndr_ptr);
545 0 : if (!NT_STATUS_IS_OK(nt_status)) {
546 0 : talloc_free(tmp_ctx);
547 0 : return EINVAL;
548 : }
549 : }
550 :
551 0 : nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
552 : user_info_dc,
553 : &upn_dns_info_blob);
554 0 : if (!NT_STATUS_IS_OK(nt_status)) {
555 0 : talloc_free(tmp_ctx);
556 0 : return EINVAL;
557 : }
558 :
559 0 : if (is_krbtgt) {
560 0 : nt_status = samba_kdc_get_pac_attrs_blob(tmp_ctx,
561 : PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
562 : &pac_attrs_blob);
563 0 : if (!NT_STATUS_IS_OK(nt_status)) {
564 0 : talloc_free(tmp_ctx);
565 0 : return EINVAL;
566 : }
567 :
568 0 : nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
569 : user_info_dc,
570 : &requester_sid_blob);
571 0 : if (!NT_STATUS_IS_OK(nt_status)) {
572 0 : talloc_free(tmp_ctx);
573 0 : return EINVAL;
574 : }
575 : }
576 :
577 0 : nt_status = samba_kdc_get_claims_blob(tmp_ctx,
578 : skdc_entry,
579 : &client_claims_blob);
580 0 : if (!NT_STATUS_IS_OK(nt_status)) {
581 0 : talloc_free(tmp_ctx);
582 0 : return EINVAL;
583 : }
584 :
585 0 : if (replaced_reply_key != NULL && cred_ndr != NULL) {
586 0 : code = samba_kdc_encrypt_pac_credentials(context,
587 : replaced_reply_key,
588 : cred_ndr,
589 : tmp_ctx,
590 : &cred_blob);
591 0 : if (code != 0) {
592 0 : talloc_free(tmp_ctx);
593 0 : return code;
594 : }
595 0 : pcred_blob = &cred_blob;
596 : }
597 :
598 0 : code = samba_make_krb5_pac(context,
599 : logon_info_blob,
600 : pcred_blob,
601 : upn_dns_info_blob,
602 : pac_attrs_blob,
603 : requester_sid_blob,
604 : NULL /* deleg_blob */,
605 : client_claims_blob,
606 : NULL /* device_info_blob */,
607 : NULL /* device_claims_blob */,
608 : *pac);
609 :
610 0 : talloc_free(tmp_ctx);
611 0 : return code;
612 : }
613 :
614 0 : krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
615 : krb5_context context,
616 : int kdc_flags,
617 : krb5_db_entry *client,
618 : krb5_db_entry *server,
619 : krb5_db_entry *krbtgt,
620 : krb5_pac old_pac,
621 : krb5_pac new_pac)
622 : {
623 0 : TALLOC_CTX *tmp_ctx = NULL;
624 : krb5_error_code code;
625 0 : struct samba_kdc_entry *client_skdc_entry = NULL;
626 0 : struct samba_kdc_entry *server_skdc_entry = NULL;
627 0 : struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
628 0 : struct samba_kdc_entry_pac client_pac_entry = {};
629 0 : bool is_in_db = false;
630 0 : bool is_trusted = false;
631 0 : uint32_t flags = 0;
632 :
633 : /* Create a memory context early so code can use talloc_stackframe() */
634 0 : tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac context");
635 0 : if (tmp_ctx == NULL) {
636 0 : return ENOMEM;
637 : }
638 :
639 0 : if (client != NULL) {
640 : client_skdc_entry =
641 0 : talloc_get_type_abort(client->e_data,
642 : struct samba_kdc_entry);
643 : }
644 :
645 0 : if (krbtgt == NULL) {
646 0 : code = EINVAL;
647 0 : goto done;
648 : }
649 : krbtgt_skdc_entry =
650 0 : talloc_get_type_abort(krbtgt->e_data,
651 : struct samba_kdc_entry);
652 :
653 0 : if (server == NULL) {
654 0 : code = EINVAL;
655 0 : goto done;
656 : }
657 : server_skdc_entry =
658 0 : talloc_get_type_abort(server->e_data,
659 : struct samba_kdc_entry);
660 :
661 : /*
662 : * If the krbtgt was generated by an RODC, and we are not that
663 : * RODC, then we need to regenerate the PAC - we can't trust
664 : * it, and confirm that the RODC was permitted to print this ticket
665 : *
666 : * Because of the samba_kdc_validate_pac_blob() step we can be
667 : * sure that the record in 'client' or 'server' matches the SID in the
668 : * original PAC.
669 : */
670 0 : code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
671 : &is_in_db,
672 : &is_trusted);
673 0 : if (code != 0) {
674 0 : goto done;
675 : }
676 :
677 0 : if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
678 0 : flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
679 : }
680 :
681 0 : if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
682 0 : flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
683 : }
684 :
685 0 : client_pac_entry = samba_kdc_entry_pac_from_trusted(old_pac,
686 : client_skdc_entry,
687 0 : samba_kdc_entry_is_trust(krbtgt_skdc_entry),
688 : is_trusted);
689 :
690 0 : code = samba_kdc_verify_pac(tmp_ctx,
691 : context,
692 0 : krbtgt_skdc_entry->kdc_db_ctx->samdb,
693 : flags,
694 : client_pac_entry,
695 : krbtgt_skdc_entry);
696 0 : if (code != 0) {
697 0 : goto done;
698 : }
699 :
700 0 : code = samba_kdc_update_pac(tmp_ctx,
701 : context,
702 0 : krbtgt_skdc_entry->kdc_db_ctx->samdb,
703 0 : krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
704 : flags,
705 : client_pac_entry,
706 0 : server->princ,
707 : server_skdc_entry,
708 : NULL /* delegated_proxy_principal */,
709 0 : (struct samba_kdc_entry_pac) {} /* delegated_proxy */,
710 0 : (struct samba_kdc_entry_pac) {} /* device */,
711 : new_pac,
712 : NULL /* server_audit_info_out */,
713 : NULL /* status_out */);
714 0 : if (code != 0) {
715 0 : if (code == ENOATTR) {
716 : /*
717 : * We can't tell the KDC to not issue a PAC. It will
718 : * just return the newly allocated empty PAC.
719 : */
720 0 : code = 0;
721 : }
722 : }
723 :
724 0 : done:
725 0 : talloc_free(tmp_ctx);
726 0 : return code;
727 : }
728 :
729 : /* provide header, function is exported but there are no public headers */
730 :
731 : krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
732 :
733 : /* this function allocates 'data' using malloc.
734 : * The caller is responsible for freeing it */
735 0 : static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
736 : {
737 0 : krb5_error_code ret = 0;
738 : krb5_pa_data pa, *ppa[2];
739 0 : krb5_data *d = NULL;
740 :
741 0 : if (!e_data)
742 0 : return;
743 :
744 0 : e_data->data = NULL;
745 0 : e_data->length = 0;
746 :
747 0 : pa.magic = KV5M_PA_DATA;
748 0 : pa.pa_type = KRB5_PADATA_PW_SALT /* KERB_ERR_TYPE_EXTENDED */;
749 0 : pa.length = 12;
750 0 : pa.contents = malloc(pa.length);
751 0 : if (!pa.contents) {
752 0 : return;
753 : }
754 :
755 0 : SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
756 0 : SIVAL(pa.contents, 4, 0);
757 0 : SIVAL(pa.contents, 8, 1);
758 :
759 0 : ppa[0] = &pa;
760 0 : ppa[1] = NULL;
761 :
762 0 : ret = encode_krb5_padata_sequence(ppa, &d);
763 0 : free(pa.contents);
764 0 : if (ret) {
765 0 : return;
766 : }
767 :
768 0 : e_data->data = (uint8_t *)d->data;
769 0 : e_data->length = d->length;
770 :
771 : /* free d, not d->data - gd */
772 0 : free(d);
773 :
774 0 : return;
775 : }
776 :
777 0 : krb5_error_code mit_samba_check_client_access(struct mit_samba_context *ctx,
778 : krb5_db_entry *client,
779 : const char *client_name,
780 : krb5_db_entry *server,
781 : const char *server_name,
782 : const char *netbios_name,
783 : bool password_change,
784 : DATA_BLOB *e_data)
785 : {
786 : struct samba_kdc_entry *skdc_entry;
787 : NTSTATUS nt_status;
788 :
789 0 : skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
790 :
791 0 : nt_status = samba_kdc_check_client_access(skdc_entry,
792 : client_name,
793 : netbios_name,
794 : password_change);
795 :
796 0 : if (!NT_STATUS_IS_OK(nt_status)) {
797 0 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
798 0 : return ENOMEM;
799 : }
800 :
801 0 : samba_kdc_build_edata_reply(nt_status, e_data);
802 :
803 0 : return samba_kdc_map_policy_err(nt_status);
804 : }
805 :
806 0 : return 0;
807 : }
808 :
809 0 : krb5_error_code mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
810 : const krb5_db_entry *server,
811 : krb5_const_principal target_principal)
812 : {
813 : struct samba_kdc_entry *server_skdc_entry =
814 0 : talloc_get_type_abort(server->e_data, struct samba_kdc_entry);
815 : krb5_error_code code;
816 :
817 0 : code = samba_kdc_check_s4u2proxy(ctx->context,
818 : ctx->db_ctx,
819 : server_skdc_entry,
820 : target_principal);
821 :
822 0 : return code;
823 : }
824 :
825 0 : krb5_error_code mit_samba_check_allowed_to_delegate_from(
826 : struct mit_samba_context *ctx,
827 : krb5_const_principal client_principal,
828 : krb5_const_principal server_principal,
829 : krb5_pac header_pac,
830 : const krb5_db_entry *proxy)
831 : {
832 : struct samba_kdc_entry *proxy_skdc_entry =
833 0 : talloc_get_type_abort(proxy->e_data, struct samba_kdc_entry);
834 0 : struct auth_user_info_dc *user_info_dc = NULL;
835 0 : TALLOC_CTX *mem_ctx = NULL;
836 : krb5_error_code code;
837 :
838 0 : mem_ctx = talloc_new(NULL);
839 0 : if (mem_ctx == NULL) {
840 0 : return ENOMEM;
841 : }
842 :
843 : /*
844 : * FIXME: If ever we support RODCs, we must check that the PAC has not
845 : * been issued by an RODC (other than ourselves) — otherwise the PAC
846 : * cannot be trusted. Because the plugin interface does not give us the
847 : * client entry, we cannot look up its groups in the database.
848 : */
849 0 : code = kerberos_pac_to_user_info_dc(mem_ctx,
850 : header_pac,
851 : ctx->context,
852 : &user_info_dc,
853 : AUTH_INCLUDE_RESOURCE_GROUPS,
854 : NULL,
855 : NULL,
856 : NULL);
857 0 : if (code != 0) {
858 0 : goto out;
859 : }
860 :
861 0 : code = samba_kdc_check_s4u2proxy_rbcd(ctx->context,
862 : ctx->db_ctx,
863 : client_principal,
864 : server_principal,
865 : user_info_dc,
866 : NULL /* device_info_dc */,
867 0 : (struct auth_claims) {},
868 : proxy_skdc_entry);
869 0 : out:
870 0 : talloc_free(mem_ctx);
871 0 : return code;
872 : }
873 :
874 0 : static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
875 : NTSTATUS result,
876 : enum samPwdChangeReason reject_reason,
877 : struct samr_DomInfo1 *dominfo)
878 : {
879 0 : krb5_error_code code = KADM5_PASS_Q_GENERIC;
880 :
881 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
882 0 : code = KADM5_BAD_PRINCIPAL;
883 0 : krb5_set_error_message(context,
884 : code,
885 : "No such user when changing password");
886 : }
887 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
888 0 : code = KADM5_PASS_Q_GENERIC;
889 0 : krb5_set_error_message(context,
890 : code,
891 : "Not permitted to change password");
892 : }
893 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) &&
894 : dominfo != NULL) {
895 0 : switch (reject_reason) {
896 0 : case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
897 0 : code = KADM5_PASS_Q_TOOSHORT;
898 0 : krb5_set_error_message(context,
899 : code,
900 : "Password too short, password "
901 : "must be at least %d characters "
902 : "long.",
903 0 : dominfo->min_password_length);
904 0 : break;
905 0 : case SAM_PWD_CHANGE_NOT_COMPLEX:
906 0 : code = KADM5_PASS_Q_DICT;
907 0 : krb5_set_error_message(context,
908 : code,
909 : "Password does not meet "
910 : "complexity requirements");
911 0 : break;
912 0 : case SAM_PWD_CHANGE_PWD_IN_HISTORY:
913 0 : code = KADM5_PASS_TOOSOON;
914 0 : krb5_set_error_message(context,
915 : code,
916 : "Password is already in password "
917 : "history. New password must not "
918 : "match any of your %d previous "
919 : "passwords.",
920 0 : dominfo->password_history_length);
921 0 : break;
922 0 : default:
923 0 : code = KADM5_PASS_Q_GENERIC;
924 0 : krb5_set_error_message(context,
925 : code,
926 : "Password change rejected, "
927 : "password changes may not be "
928 : "permitted on this account, or "
929 : "the minimum password age may "
930 : "not have elapsed.");
931 0 : break;
932 : }
933 : }
934 :
935 0 : return code;
936 : }
937 :
938 0 : krb5_error_code mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
939 : char *pwd,
940 : krb5_db_entry *db_entry)
941 : {
942 : NTSTATUS status;
943 0 : NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
944 : TALLOC_CTX *tmp_ctx;
945 : DATA_BLOB password;
946 : enum samPwdChangeReason reject_reason;
947 : struct samr_DomInfo1 *dominfo;
948 0 : const char *error_string = NULL;
949 0 : const struct auth_user_info_dc *user_info_dc = NULL;
950 : struct samba_kdc_entry *p =
951 0 : talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
952 0 : krb5_error_code code = 0;
953 :
954 : #ifdef DEBUG_PASSWORD
955 0 : DBG_WARNING("mit_samba_kpasswd_change_password called with: %s\n", pwd);
956 : #endif
957 :
958 0 : tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
959 0 : if (tmp_ctx == NULL) {
960 0 : return ENOMEM;
961 : }
962 :
963 0 : code = samba_kdc_get_user_info_from_db(tmp_ctx,
964 0 : ctx->db_ctx->samdb,
965 : p,
966 0 : p->msg,
967 : &user_info_dc);
968 0 : if (code) {
969 0 : const char *krb5err = krb5_get_error_message(ctx->context, code);
970 0 : DBG_WARNING("samba_kdc_get_user_info_from_db failed: %s\n",
971 : krb5err != NULL ? krb5err : "<unknown>");
972 0 : krb5_free_error_message(ctx->context, krb5err);
973 :
974 0 : goto out;
975 : }
976 :
977 0 : status = auth_generate_session_info(tmp_ctx,
978 0 : ctx->db_ctx->lp_ctx,
979 0 : ctx->db_ctx->samdb,
980 : user_info_dc,
981 : 0, /* session_info_flags */
982 : &ctx->session_info);
983 :
984 0 : if (!NT_STATUS_IS_OK(status)) {
985 0 : DBG_WARNING("auth_generate_session_info failed: %s\n",
986 : nt_errstr(status));
987 0 : code = EINVAL;
988 0 : goto out;
989 : }
990 :
991 : /* password is expected as UTF16 */
992 :
993 0 : if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
994 : pwd, strlen(pwd),
995 : &password.data, &password.length)) {
996 0 : DBG_WARNING("convert_string_talloc failed\n");
997 0 : code = EINVAL;
998 0 : goto out;
999 : }
1000 :
1001 0 : status = samdb_kpasswd_change_password(tmp_ctx,
1002 0 : ctx->db_ctx->lp_ctx,
1003 0 : ctx->db_ctx->ev_ctx,
1004 : ctx->session_info,
1005 : &password,
1006 : &reject_reason,
1007 : &dominfo,
1008 : &error_string,
1009 : &result);
1010 0 : if (!NT_STATUS_IS_OK(status)) {
1011 0 : DBG_WARNING("samdb_kpasswd_change_password failed: %s\n",
1012 : nt_errstr(status));
1013 0 : code = KADM5_PASS_Q_GENERIC;
1014 0 : krb5_set_error_message(ctx->context, code, "%s", error_string);
1015 0 : goto out;
1016 : }
1017 :
1018 0 : if (!NT_STATUS_IS_OK(result)) {
1019 0 : code = mit_samba_change_pwd_error(ctx->context,
1020 : result,
1021 : reject_reason,
1022 : dominfo);
1023 : }
1024 :
1025 0 : out:
1026 0 : talloc_free(tmp_ctx);
1027 :
1028 0 : return code;
1029 : }
1030 :
1031 0 : void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
1032 : {
1033 : /* struct netr_SendToSamBase *send_to_sam = NULL; */
1034 : struct samba_kdc_entry *p =
1035 0 : talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
1036 : struct ldb_dn *domain_dn;
1037 :
1038 0 : domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
1039 :
1040 0 : authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
1041 0 : p->msg,
1042 : domain_dn,
1043 : true,
1044 : NULL, NULL);
1045 : /* TODO: RODC support */
1046 0 : }
1047 :
1048 :
1049 0 : void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
1050 : {
1051 : struct samba_kdc_entry *p =
1052 0 : talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
1053 :
1054 0 : authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
1055 : p->msg,
1056 0 : ldb_get_default_basedn(p->kdc_db_ctx->samdb));
1057 0 : }
1058 :
1059 0 : bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry)
1060 : {
1061 : struct samba_kdc_entry *skdc_entry =
1062 0 : talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
1063 :
1064 0 : return samba_princ_needs_pac(skdc_entry);
1065 : }
|