s4:kdc: Have callers of samba_kdc_get_user_info_dc() themselves add the Claims Valid SID
[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 MIT'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("mitkdc", is_error, "%s", msg);
73 }
74
75 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         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 MIT'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 int mit_samba_generate_salt(krb5_data *salt)
143 {
144         if (salt == NULL) {
145                 return EINVAL;
146         }
147
148         salt->length = 16;
149         salt->data = malloc(salt->length);
150         if (salt->data == NULL) {
151                 return ENOMEM;
152         }
153
154         generate_random_buffer((uint8_t *)salt->data, salt->length);
155
156         return 0;
157 }
158
159 int mit_samba_generate_random_password(krb5_data *pwd)
160 {
161         TALLOC_CTX *tmp_ctx;
162         char *password;
163         char *data = NULL;
164         const unsigned length = 24;
165
166         if (pwd == NULL) {
167                 return EINVAL;
168         }
169
170         tmp_ctx = talloc_named(NULL,
171                                0,
172                                "mit_samba_generate_random_password context");
173         if (tmp_ctx == NULL) {
174                 return ENOMEM;
175         }
176
177         password = generate_random_password(tmp_ctx, length, length);
178         if (password == NULL) {
179                 talloc_free(tmp_ctx);
180                 return ENOMEM;
181         }
182
183         data = strdup(password);
184         talloc_free(tmp_ctx);
185         if (data == NULL) {
186                 return ENOMEM;
187         }
188
189         *pwd = smb_krb5_make_data(data, length);
190
191         return 0;
192 }
193
194 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         struct sdb_entry sentry = {};
200         krb5_db_entry *kentry;
201         krb5_error_code ret;
202         uint32_t sflags = 0;
203         krb5_principal referral_principal = NULL;
204
205         kentry = calloc(1, sizeof(krb5_db_entry));
206         if (kentry == NULL) {
207                 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         sflags |= SDB_F_FORCE_CANON;
215
216         if (kflags & KRB5_KDB_FLAG_REFERRAL_OK) {
217                 sflags |= SDB_F_CANON;
218         }
219
220         if (kflags & KRB5_KDB_FLAG_CLIENT) {
221                 sflags |= SDB_F_GET_CLIENT;
222                 sflags |= SDB_F_FOR_AS_REQ;
223         } else {
224                 int equal = smb_krb5_principal_is_tgs(ctx->context, principal);
225                 if (equal == -1) {
226                         return ENOMEM;
227                 }
228
229                 if (equal) {
230                         sflags |= SDB_F_GET_KRBTGT;
231                 } else {
232                         sflags |= SDB_F_GET_SERVER;
233                         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         sflags |= SDB_F_ADMIN_DATA;
240
241
242 fetch_referral_principal:
243         ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
244                               principal, sflags, 0, &sentry);
245         switch (ret) {
246         case 0:
247                 break;
248         case SDB_ERR_NOENTRY:
249                 ret = KRB5_KDB_NOENTRY;
250                 goto done;
251         case SDB_ERR_WRONG_REALM: {
252                 char *dest_realm = NULL;
253                 const char *our_realm = lpcfg_realm(ctx->db_ctx->lp_ctx);
254
255                 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                         ret = 0;
261                         break;
262                 }
263
264                 if (referral_principal != NULL) {
265                         sdb_entry_free(&sentry);
266                         ret = KRB5_KDB_NOENTRY;
267                         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 and 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                 dest_realm = smb_krb5_principal_get_realm(
296                         ctx, ctx->context, sentry.principal);
297                 sdb_entry_free(&sentry);
298                 if (dest_realm == NULL) {
299                         ret = KRB5_KDB_NOENTRY;
300                         goto done;
301                 }
302
303                 ret = smb_krb5_make_principal(ctx->context,
304                                               &referral_principal,
305                                               our_realm,
306                                               KRB5_TGS_NAME,
307                                               dest_realm,
308                                               NULL);
309                 TALLOC_FREE(dest_realm);
310                 if (ret != 0) {
311                         goto done;
312                 }
313
314                 principal = referral_principal;
315                 goto fetch_referral_principal;
316         }
317         case SDB_ERR_NOT_FOUND_HERE:
318                 /* FIXME: RODC support */
319         default:
320                 goto done;
321         }
322
323         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
324
325         sdb_entry_free(&sentry);
326
327 done:
328         krb5_free_principal(ctx->context, referral_principal);
329         referral_principal = NULL;
330
331         if (ret) {
332                 free(kentry);
333         } else {
334                 *_kentry = kentry;
335         }
336         return ret;
337 }
338
339 krb5_error_code mit_samba_get_firstkey(struct mit_samba_context *ctx,
340                                        krb5_db_entry **_kentry)
341 {
342         struct sdb_entry sentry = {};
343         krb5_db_entry *kentry;
344         krb5_error_code ret;
345
346         kentry = malloc(sizeof(krb5_db_entry));
347         if (kentry == NULL) {
348                 return ENOMEM;
349         }
350
351         ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
352         switch (ret) {
353         case 0:
354                 break;
355         case SDB_ERR_NOENTRY:
356                 free(kentry);
357                 return KRB5_KDB_NOENTRY;
358         case SDB_ERR_NOT_FOUND_HERE:
359                 /* FIXME: RODC support */
360         default:
361                 free(kentry);
362                 return ret;
363         }
364
365         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
366
367         sdb_entry_free(&sentry);
368
369         if (ret) {
370                 free(kentry);
371         } else {
372                 *_kentry = kentry;
373         }
374         return ret;
375 }
376
377 krb5_error_code mit_samba_get_nextkey(struct mit_samba_context *ctx,
378                                       krb5_db_entry **_kentry)
379 {
380         struct sdb_entry sentry = {};
381         krb5_db_entry *kentry;
382         krb5_error_code ret;
383
384         kentry = malloc(sizeof(krb5_db_entry));
385         if (kentry == NULL) {
386                 return ENOMEM;
387         }
388
389         ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
390         switch (ret) {
391         case 0:
392                 break;
393         case SDB_ERR_NOENTRY:
394                 free(kentry);
395                 return KRB5_KDB_NOENTRY;
396         case SDB_ERR_NOT_FOUND_HERE:
397                 /* FIXME: RODC support */
398         default:
399                 free(kentry);
400                 return ret;
401         }
402
403         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
404
405         sdb_entry_free(&sentry);
406
407         if (ret) {
408                 free(kentry);
409         } else {
410                 *_kentry = kentry;
411         }
412         return ret;
413 }
414
415 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         struct auth_user_info_dc *user_info_dc = NULL;
425         DATA_BLOB *logon_info_blob = NULL;
426         DATA_BLOB *upn_dns_info_blob = NULL;
427         DATA_BLOB *cred_ndr = NULL;
428         DATA_BLOB **cred_ndr_ptr = NULL;
429         DATA_BLOB cred_blob = data_blob_null;
430         DATA_BLOB *pcred_blob = NULL;
431         DATA_BLOB *pac_attrs_blob = NULL;
432         DATA_BLOB *requester_sid_blob = NULL;
433         const DATA_BLOB *client_claims_blob = NULL;
434         NTSTATUS nt_status;
435         krb5_error_code code;
436         struct samba_kdc_entry *skdc_entry;
437         struct samba_kdc_entry *server_entry = NULL;
438         bool is_krbtgt;
439         /* Only include resource groups in a service ticket. */
440         enum auth_group_inclusion group_inclusion;
441         enum samba_asserted_identity asserted_identity =
442                 (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
443                         SAMBA_ASSERTED_IDENTITY_SERVICE :
444                         SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
445
446         if (client == NULL) {
447                 return EINVAL;
448         }
449         skdc_entry = talloc_get_type_abort(client->e_data,
450                                            struct samba_kdc_entry);
451
452         if (server == NULL) {
453                 return EINVAL;
454         }
455         {
456                 int result = smb_krb5_principal_is_tgs(smb_ctx->context, server->princ);
457                 if (result == -1) {
458                         return ENOMEM;
459                 }
460
461                 is_krbtgt = result;
462         }
463         server_entry = talloc_get_type_abort(server->e_data,
464                                              struct samba_kdc_entry);
465
466         /* Only include resource groups in a service ticket. */
467         if (is_krbtgt) {
468                 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
469         } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
470                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
471         } else {
472                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
473         }
474
475         tmp_ctx = talloc_named(smb_ctx,
476                                0,
477                                "mit_samba_get_pac context");
478         if (tmp_ctx == NULL) {
479                 return ENOMEM;
480         }
481
482         /* Check if we have a PREAUTH key */
483         if (replaced_reply_key != NULL) {
484                 cred_ndr_ptr = &cred_ndr;
485         }
486
487         nt_status = samba_kdc_get_user_info_dc(tmp_ctx,
488                                                skdc_entry,
489                                                asserted_identity,
490                                                SAMBA_CLAIMS_VALID_EXCLUDE,
491                                                &user_info_dc);
492         if (!NT_STATUS_IS_OK(nt_status)) {
493                 talloc_free(tmp_ctx);
494                 if (NT_STATUS_EQUAL(nt_status,
495                                     NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
496                         return ENOENT;
497                 }
498                 return EINVAL;
499         }
500
501         nt_status = samba_kdc_add_claims_valid(SAMBA_CLAIMS_VALID_INCLUDE,
502                                                user_info_dc);
503         if (!NT_STATUS_IS_OK(nt_status)) {
504                 DBG_ERR("Failed to add Claims Valid: %s\n",
505                         nt_errstr(nt_status));
506                 talloc_free(tmp_ctx);
507                 return EINVAL;
508         }
509
510         nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
511                                                   user_info_dc,
512                                                   group_inclusion,
513                                                   &logon_info_blob);
514         if (!NT_STATUS_IS_OK(nt_status)) {
515                 talloc_free(tmp_ctx);
516                 return EINVAL;
517         }
518
519         if (cred_ndr_ptr != NULL) {
520                 nt_status = samba_kdc_get_cred_ndr_blob(tmp_ctx,
521                                                         skdc_entry,
522                                                         cred_ndr_ptr);
523                 if (!NT_STATUS_IS_OK(nt_status)) {
524                         talloc_free(tmp_ctx);
525                         return EINVAL;
526                 }
527         }
528
529         nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
530                                                 user_info_dc,
531                                                 &upn_dns_info_blob);
532         if (!NT_STATUS_IS_OK(nt_status)) {
533                 talloc_free(tmp_ctx);
534                 return EINVAL;
535         }
536
537         if (is_krbtgt) {
538                 nt_status = samba_kdc_get_pac_attrs_blob(tmp_ctx,
539                                                          PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
540                                                          &pac_attrs_blob);
541                 if (!NT_STATUS_IS_OK(nt_status)) {
542                         talloc_free(tmp_ctx);
543                         return EINVAL;
544                 }
545
546                 nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
547                                                              user_info_dc,
548                                                              &requester_sid_blob);
549                 if (!NT_STATUS_IS_OK(nt_status)) {
550                         talloc_free(tmp_ctx);
551                         return EINVAL;
552                 }
553         }
554
555         nt_status = samba_kdc_get_claims_blob(tmp_ctx,
556                                               skdc_entry,
557                                               &client_claims_blob);
558         if (!NT_STATUS_IS_OK(nt_status)) {
559                 talloc_free(tmp_ctx);
560                 return EINVAL;
561         }
562
563         if (replaced_reply_key != NULL && cred_ndr != NULL) {
564                 code = samba_kdc_encrypt_pac_credentials(context,
565                                                          replaced_reply_key,
566                                                          cred_ndr,
567                                                          tmp_ctx,
568                                                          &cred_blob);
569                 if (code != 0) {
570                         talloc_free(tmp_ctx);
571                         return code;
572                 }
573                 pcred_blob = &cred_blob;
574         }
575
576         code = samba_make_krb5_pac(context,
577                                    logon_info_blob,
578                                    pcred_blob,
579                                    upn_dns_info_blob,
580                                    pac_attrs_blob,
581                                    requester_sid_blob,
582                                    NULL /* deleg_blob */,
583                                    client_claims_blob,
584                                    NULL /* device_info_blob */,
585                                    NULL /* device_claims_blob */,
586                                    *pac);
587
588         talloc_free(tmp_ctx);
589         return code;
590 }
591
592 krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
593                                     krb5_context context,
594                                     int kdc_flags,
595                                     krb5_db_entry *client,
596                                     krb5_db_entry *server,
597                                     krb5_db_entry *krbtgt,
598                                     krb5_pac old_pac,
599                                     krb5_pac new_pac)
600 {
601         TALLOC_CTX *tmp_ctx = NULL;
602         krb5_error_code code;
603         struct samba_kdc_entry *client_skdc_entry = NULL;
604         struct samba_kdc_entry *server_skdc_entry = NULL;
605         struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
606         bool is_in_db = false;
607         bool is_trusted = false;
608         uint32_t flags = 0;
609
610         /* Create a memory context early so code can use talloc_stackframe() */
611         tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac context");
612         if (tmp_ctx == NULL) {
613                 return ENOMEM;
614         }
615
616         if (client != NULL) {
617                 client_skdc_entry =
618                         talloc_get_type_abort(client->e_data,
619                                               struct samba_kdc_entry);
620         }
621
622         if (krbtgt == NULL) {
623                 code = EINVAL;
624                 goto done;
625         }
626         krbtgt_skdc_entry =
627                 talloc_get_type_abort(krbtgt->e_data,
628                                       struct samba_kdc_entry);
629
630         if (server == NULL) {
631                 code = EINVAL;
632                 goto done;
633         }
634         server_skdc_entry =
635                 talloc_get_type_abort(server->e_data,
636                                       struct samba_kdc_entry);
637
638         /*
639          * If the krbtgt was generated by an RODC, and we are not that
640          * RODC, then we need to regenerate the PAC - we can't trust
641          * it, and confirm that the RODC was permitted to print this ticket
642          *
643          * Because of the samba_kdc_validate_pac_blob() step we can be
644          * sure that the record in 'client' or 'server' matches the SID in the
645          * original PAC.
646          */
647         code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
648                                      &is_in_db,
649                                      &is_trusted);
650         if (code != 0) {
651                 goto done;
652         }
653
654         if (is_trusted) {
655                 flags |=  SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED;
656         }
657
658         if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
659                 flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
660         }
661
662         if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
663                 flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
664         }
665
666         code = samba_kdc_verify_pac(tmp_ctx,
667                                     context,
668                                     flags,
669                                     client_skdc_entry,
670                                     krbtgt_skdc_entry,
671                                     NULL /* device */,
672                                     NULL /* device_pac */,
673                                     old_pac);
674         if (code != 0) {
675                 goto done;
676         }
677
678         code = samba_kdc_update_pac(tmp_ctx,
679                                     context,
680                                     krbtgt_skdc_entry->kdc_db_ctx->samdb,
681                                     krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
682                                     flags,
683                                     krbtgt_skdc_entry,
684                                     client_skdc_entry,
685                                     server->princ,
686                                     server_skdc_entry,
687                                     NULL /* delegated_proxy_principal */,
688                                     NULL /* delegated_proxy */,
689                                     NULL /* delegated_proxy_pac */,
690                                     NULL /* device_krbtgt */,
691                                     NULL /* device */,
692                                     NULL /* device_pac */,
693                                     old_pac,
694                                     new_pac,
695                                     NULL /* server_audit_info_out */,
696                                     NULL /* status_out */);
697         if (code != 0) {
698                 if (code == ENOATTR) {
699                         /*
700                          * We can't tell the KDC to not issue a PAC. It will
701                          * just return the newly allocated empty PAC.
702                          */
703                         code = 0;
704                 }
705         }
706
707 done:
708         talloc_free(tmp_ctx);
709         return code;
710 }
711
712 /* provide header, function is exported but there are no public headers */
713
714 krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
715
716 /* this function allocates 'data' using malloc.
717  * The caller is responsible for freeing it */
718 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
719 {
720         krb5_error_code ret = 0;
721         krb5_pa_data pa, *ppa[2];
722         krb5_data *d = NULL;
723
724         if (!e_data)
725                 return;
726
727         e_data->data   = NULL;
728         e_data->length = 0;
729
730         pa.magic                = KV5M_PA_DATA;
731         pa.pa_type              = KRB5_PADATA_PW_SALT /* KERB_ERR_TYPE_EXTENDED */;
732         pa.length               = 12;
733         pa.contents             = malloc(pa.length);
734         if (!pa.contents) {
735                 return;
736         }
737
738         SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
739         SIVAL(pa.contents, 4, 0);
740         SIVAL(pa.contents, 8, 1);
741
742         ppa[0] = &pa;
743         ppa[1] = NULL;
744
745         ret = encode_krb5_padata_sequence(ppa, &d);
746         free(pa.contents);
747         if (ret) {
748                 return;
749         }
750
751         e_data->data   = (uint8_t *)d->data;
752         e_data->length = d->length;
753
754         /* free d, not d->data - gd */
755         free(d);
756
757         return;
758 }
759
760 krb5_error_code mit_samba_check_client_access(struct mit_samba_context *ctx,
761                                               krb5_db_entry *client,
762                                               const char *client_name,
763                                               krb5_db_entry *server,
764                                               const char *server_name,
765                                               const char *netbios_name,
766                                               bool password_change,
767                                               DATA_BLOB *e_data)
768 {
769         struct samba_kdc_entry *skdc_entry;
770         NTSTATUS nt_status;
771
772         skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
773
774         nt_status = samba_kdc_check_client_access(skdc_entry,
775                                                   client_name,
776                                                   netbios_name,
777                                                   password_change);
778
779         if (!NT_STATUS_IS_OK(nt_status)) {
780                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
781                         return ENOMEM;
782                 }
783
784                 samba_kdc_build_edata_reply(nt_status, e_data);
785
786                 return samba_kdc_map_policy_err(nt_status);
787         }
788
789         return 0;
790 }
791
792 krb5_error_code mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
793                                           const krb5_db_entry *server,
794                                           krb5_const_principal target_principal)
795 {
796         struct samba_kdc_entry *server_skdc_entry =
797                 talloc_get_type_abort(server->e_data, struct samba_kdc_entry);
798         krb5_error_code code;
799
800         code = samba_kdc_check_s4u2proxy(ctx->context,
801                                          ctx->db_ctx,
802                                          server_skdc_entry,
803                                          target_principal);
804
805         return code;
806 }
807
808 krb5_error_code mit_samba_check_allowed_to_delegate_from(
809                 struct mit_samba_context *ctx,
810                 krb5_const_principal client_principal,
811                 krb5_const_principal server_principal,
812                 krb5_pac header_pac,
813                 const krb5_db_entry *proxy)
814 {
815         struct samba_kdc_entry *proxy_skdc_entry =
816                 talloc_get_type_abort(proxy->e_data, struct samba_kdc_entry);
817         krb5_error_code code;
818
819         code = samba_kdc_check_s4u2proxy_rbcd(ctx->context,
820                                               ctx->db_ctx,
821                                               client_principal,
822                                               server_principal,
823                                               header_pac,
824                                               proxy_skdc_entry);
825
826         return code;
827 }
828
829 static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
830                                                   NTSTATUS result,
831                                                   enum samPwdChangeReason reject_reason,
832                                                   struct samr_DomInfo1 *dominfo)
833 {
834         krb5_error_code code = KADM5_PASS_Q_GENERIC;
835
836         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
837                 code = KADM5_BAD_PRINCIPAL;
838                 krb5_set_error_message(context,
839                                        code,
840                                        "No such user when changing password");
841         }
842         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
843                 code = KADM5_PASS_Q_GENERIC;
844                 krb5_set_error_message(context,
845                                        code,
846                                        "Not permitted to change password");
847         }
848         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) &&
849             dominfo != NULL) {
850                 switch (reject_reason) {
851                 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
852                         code = KADM5_PASS_Q_TOOSHORT;
853                         krb5_set_error_message(context,
854                                                code,
855                                                "Password too short, password "
856                                                "must be at least %d characters "
857                                                "long.",
858                                                dominfo->min_password_length);
859                         break;
860                 case SAM_PWD_CHANGE_NOT_COMPLEX:
861                         code = KADM5_PASS_Q_DICT;
862                         krb5_set_error_message(context,
863                                                code,
864                                                "Password does not meet "
865                                                "complexity requirements");
866                         break;
867                 case SAM_PWD_CHANGE_PWD_IN_HISTORY:
868                         code = KADM5_PASS_TOOSOON;
869                         krb5_set_error_message(context,
870                                                code,
871                                                "Password is already in password "
872                                                "history. New password must not "
873                                                "match any of your %d previous "
874                                                "passwords.",
875                                                dominfo->password_history_length);
876                         break;
877                 default:
878                         code = KADM5_PASS_Q_GENERIC;
879                         krb5_set_error_message(context,
880                                                code,
881                                                "Password change rejected, "
882                                                "password changes may not be "
883                                                "permitted on this account, or "
884                                                "the minimum password age may "
885                                                "not have elapsed.");
886                         break;
887                 }
888         }
889
890         return code;
891 }
892
893 krb5_error_code mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
894                                                   char *pwd,
895                                                   krb5_db_entry *db_entry)
896 {
897         NTSTATUS status;
898         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
899         TALLOC_CTX *tmp_ctx;
900         DATA_BLOB password;
901         enum samPwdChangeReason reject_reason;
902         struct samr_DomInfo1 *dominfo;
903         const char *error_string = NULL;
904         const struct auth_user_info_dc *user_info_dc = NULL;
905         struct samba_kdc_entry *p =
906                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
907         krb5_error_code code = 0;
908
909 #ifdef DEBUG_PASSWORD
910         DBG_WARNING("mit_samba_kpasswd_change_password called with: %s\n", pwd);
911 #endif
912
913         tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
914         if (tmp_ctx == NULL) {
915                 return ENOMEM;
916         }
917
918         status = samba_kdc_get_user_info_from_db(p,
919                                                  p->msg,
920                                                  &user_info_dc);
921         if (!NT_STATUS_IS_OK(status)) {
922                 DBG_WARNING("samba_kdc_get_user_info_from_db failed: %s\n",
923                             nt_errstr(status));
924                 code = EINVAL;
925                 goto out;
926         }
927
928         status = auth_generate_session_info(tmp_ctx,
929                                             ctx->db_ctx->lp_ctx,
930                                             ctx->db_ctx->samdb,
931                                             user_info_dc,
932                                             0, /* session_info_flags */
933                                             &ctx->session_info);
934
935         if (!NT_STATUS_IS_OK(status)) {
936                 DBG_WARNING("auth_generate_session_info failed: %s\n",
937                             nt_errstr(status));
938                 code = EINVAL;
939                 goto out;
940         }
941
942         /* password is expected as UTF16 */
943
944         if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
945                                    pwd, strlen(pwd),
946                                    &password.data, &password.length)) {
947                 DBG_WARNING("convert_string_talloc failed\n");
948                 code = EINVAL;
949                 goto out;
950         }
951
952         status = samdb_kpasswd_change_password(tmp_ctx,
953                                                ctx->db_ctx->lp_ctx,
954                                                ctx->db_ctx->ev_ctx,
955                                                ctx->session_info,
956                                                &password,
957                                                &reject_reason,
958                                                &dominfo,
959                                                &error_string,
960                                                &result);
961         if (!NT_STATUS_IS_OK(status)) {
962                 DBG_WARNING("samdb_kpasswd_change_password failed: %s\n",
963                             nt_errstr(status));
964                 code = KADM5_PASS_Q_GENERIC;
965                 krb5_set_error_message(ctx->context, code, "%s", error_string);
966                 goto out;
967         }
968
969         if (!NT_STATUS_IS_OK(result)) {
970                 code = mit_samba_change_pwd_error(ctx->context,
971                                                   result,
972                                                   reject_reason,
973                                                   dominfo);
974         }
975
976 out:
977         talloc_free(tmp_ctx);
978
979         return code;
980 }
981
982 void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
983 {
984         /* struct netr_SendToSamBase *send_to_sam = NULL; */
985         struct samba_kdc_entry *p =
986                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
987         struct ldb_dn *domain_dn;
988
989         domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
990
991         authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
992                                          p->msg,
993                                          domain_dn,
994                                          true,
995                                          NULL, NULL);
996         /* TODO: RODC support */
997 }
998
999
1000 void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
1001 {
1002         struct samba_kdc_entry *p =
1003                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
1004
1005         authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
1006                                      p->msg,
1007                                      ldb_get_default_basedn(p->kdc_db_ctx->samdb));
1008 }
1009
1010 bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry)
1011 {
1012         struct samba_kdc_entry *skdc_entry =
1013                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
1014
1015         return samba_princ_needs_pac(skdc_entry);
1016 }