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