mit-samba: Remove obsolete mit_samba_update_pac_data()
[amitay/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 <kdb.h>
29 #include <kadm5/kadm_err.h>
30 #include "kdc/sdb.h"
31 #include "kdc/sdb_kdb.h"
32 #include "auth/kerberos/kerberos.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "kdc/samba_kdc.h"
35 #include "kdc/pac-glue.h"
36 #include "kdc/db-glue.h"
37 #include "auth/auth.h"
38 #include "kdc/kpasswd_glue.h"
39 #include "auth/auth_sam.h"
40
41 #include "mit_samba.h"
42
43 void mit_samba_context_free(struct mit_samba_context *ctx)
44 {
45         /* free heimdal's krb5_context */
46         if (ctx->context) {
47                 krb5_free_context(ctx->context);
48         }
49
50         /* then free everything else */
51         talloc_free(ctx);
52 }
53
54 int mit_samba_context_init(struct mit_samba_context **_ctx)
55 {
56         NTSTATUS status;
57         struct mit_samba_context *ctx;
58         const char *s4_conf_file;
59         int ret;
60         struct samba_kdc_base_context base_ctx;
61
62         ctx = talloc_zero(NULL, struct mit_samba_context);
63         if (!ctx) {
64                 ret = ENOMEM;
65                 goto done;
66         }
67
68         base_ctx.ev_ctx = tevent_context_init(ctx);
69         if (!base_ctx.ev_ctx) {
70                 ret = ENOMEM;
71                 goto done;
72         }
73         tevent_loop_allow_nesting(base_ctx.ev_ctx);
74         base_ctx.lp_ctx = loadparm_init_global(false);
75         if (!base_ctx.lp_ctx) {
76                 ret = ENOMEM;
77                 goto done;
78         }
79
80         setup_logging("mitkdc", DEBUG_DEFAULT_STDOUT);
81
82         /* init s4 configuration */
83         s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
84         if (s4_conf_file) {
85                 lpcfg_load(base_ctx.lp_ctx, s4_conf_file);
86         } else {
87                 lpcfg_load_default(base_ctx.lp_ctx);
88         }
89
90         status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
91         if (!NT_STATUS_IS_OK(status)) {
92                 ret = EINVAL;
93                 goto done;
94         }
95
96         /* init heimdal's krb_context and log facilities */
97         ret = smb_krb5_init_context_basic(ctx,
98                                           ctx->db_ctx->lp_ctx,
99                                           &ctx->context);
100         if (ret) {
101                 goto done;
102         }
103
104         ret = 0;
105
106 done:
107         if (ret) {
108                 mit_samba_context_free(ctx);
109         } else {
110                 *_ctx = ctx;
111         }
112         return ret;
113 }
114
115 static krb5_error_code ks_is_tgs_principal(struct mit_samba_context *ctx,
116                                            krb5_const_principal principal)
117 {
118         char *p;
119         int eq = -1;
120
121         p = smb_krb5_principal_get_comp_string(ctx, ctx->context, principal, 0);
122
123         eq = krb5_princ_size(ctx->context, principal) == 2 &&
124              (strcmp(p, KRB5_TGS_NAME) == 0);
125
126         talloc_free(p);
127
128         return eq;
129 }
130
131 int mit_samba_generate_salt(krb5_data *salt)
132 {
133         if (salt == NULL) {
134                 return EINVAL;
135         }
136
137         salt->length = 16;
138         salt->data = malloc(salt->length);
139         if (salt->data == NULL) {
140                 return ENOMEM;
141         }
142
143         generate_random_buffer((uint8_t *)salt->data, salt->length);
144
145         return 0;
146 }
147
148 int mit_samba_generate_random_password(krb5_data *pwd)
149 {
150         TALLOC_CTX *tmp_ctx;
151         char *password;
152
153         if (pwd == NULL) {
154                 return EINVAL;
155         }
156         pwd->length = 24;
157
158         tmp_ctx = talloc_named(NULL,
159                                0,
160                                "mit_samba_create_principal_password context");
161         if (tmp_ctx == NULL) {
162                 return ENOMEM;
163         }
164
165         password = generate_random_password(tmp_ctx, pwd->length, pwd->length);
166         if (password == NULL) {
167                 talloc_free(tmp_ctx);
168                 return ENOMEM;
169         }
170
171         pwd->data = strdup(password);
172         talloc_free(tmp_ctx);
173         if (pwd->data == NULL) {
174                 return ENOMEM;
175         }
176
177         return 0;
178 }
179
180 int mit_samba_get_principal(struct mit_samba_context *ctx,
181                             krb5_const_principal principal,
182                             unsigned int kflags,
183                             krb5_db_entry **_kentry)
184 {
185         struct sdb_entry_ex sentry = {
186                 .free_entry = NULL,
187         };
188         krb5_db_entry *kentry;
189         int ret;
190         int sflags = 0;
191
192         kentry = calloc(1, sizeof(krb5_db_entry));
193         if (kentry == NULL) {
194                 return ENOMEM;
195         }
196
197         if (kflags & KRB5_KDB_FLAG_CANONICALIZE) {
198                 sflags |= SDB_F_CANON;
199         }
200         if (kflags & (KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY |
201                       KRB5_KDB_FLAG_INCLUDE_PAC)) {
202                 /*
203                  * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is equal to
204                  * SDB_F_FOR_AS_REQ
205                  *
206                  * We use ANY to also allow AS_REQ for service principal names
207                  * This is supported by Windows.
208                  */
209                 sflags |= SDB_F_GET_ANY|SDB_F_FOR_AS_REQ;
210         } else if (ks_is_tgs_principal(ctx, principal)) {
211                 sflags |= SDB_F_GET_KRBTGT;
212         } else {
213                 sflags |= SDB_F_GET_SERVER|SDB_F_FOR_TGS_REQ;
214         }
215
216         /* always set this or the created_by data will not be populated by samba's
217          * backend and we will fail to parse the entry later */
218         sflags |= SDB_F_ADMIN_DATA;
219
220         ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
221                               principal, sflags, 0, &sentry);
222         switch (ret) {
223         case 0:
224                 break;
225         case SDB_ERR_NOENTRY:
226                 ret = KRB5_KDB_NOENTRY;
227                 goto done;
228         case SDB_ERR_WRONG_REALM:
229                 /*
230                  * If we have a wrong realm e.g. if we try get a cross forest
231                  * ticket, we return a ticket with the correct realm. The KDC
232                  * will detect this an return the appropriate return code.
233                  */
234                 ret = 0;
235                 break;
236         case SDB_ERR_NOT_FOUND_HERE:
237                 /* FIXME: RODC support */
238         default:
239                 goto done;
240         }
241
242         ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
243
244         sdb_free_entry(&sentry);
245
246 done:
247         if (ret) {
248                 free(kentry);
249         } else {
250                 *_kentry = kentry;
251         }
252         return ret;
253 }
254
255 int mit_samba_get_firstkey(struct mit_samba_context *ctx,
256                            krb5_db_entry **_kentry)
257 {
258         struct sdb_entry_ex sentry = {
259                 .free_entry = NULL,
260         };
261         krb5_db_entry *kentry;
262         int ret;
263
264         kentry = malloc(sizeof(krb5_db_entry));
265         if (kentry == NULL) {
266                 return ENOMEM;
267         }
268
269         ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
270         switch (ret) {
271         case 0:
272                 break;
273         case SDB_ERR_NOENTRY:
274                 free(kentry);
275                 return KRB5_KDB_NOENTRY;
276         case SDB_ERR_NOT_FOUND_HERE:
277                 /* FIXME: RODC support */
278         default:
279                 free(kentry);
280                 return ret;
281         }
282
283         ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
284
285         sdb_free_entry(&sentry);
286
287         if (ret) {
288                 free(kentry);
289         } else {
290                 *_kentry = kentry;
291         }
292         return ret;
293 }
294
295 int mit_samba_get_nextkey(struct mit_samba_context *ctx,
296                           krb5_db_entry **_kentry)
297 {
298         struct sdb_entry_ex sentry = {
299                 .free_entry = NULL,
300         };
301         krb5_db_entry *kentry;
302         int ret;
303
304         kentry = malloc(sizeof(krb5_db_entry));
305         if (kentry == NULL) {
306                 return ENOMEM;
307         }
308
309         ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
310         switch (ret) {
311         case 0:
312                 break;
313         case SDB_ERR_NOENTRY:
314                 free(kentry);
315                 return KRB5_KDB_NOENTRY;
316         case SDB_ERR_NOT_FOUND_HERE:
317                 /* FIXME: RODC support */
318         default:
319                 free(kentry);
320                 return ret;
321         }
322
323         ret = sdb_entry_ex_to_kdb_entry_ex(ctx->context, &sentry, kentry);
324
325         sdb_free_entry(&sentry);
326
327         if (ret) {
328                 free(kentry);
329         } else {
330                 *_kentry = kentry;
331         }
332         return ret;
333 }
334
335 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
336                       krb5_context context,
337                       krb5_db_entry *client,
338                       krb5_keyblock *client_key,
339                       krb5_pac *pac)
340 {
341         TALLOC_CTX *tmp_ctx;
342         DATA_BLOB *logon_info_blob = NULL;
343         DATA_BLOB *upn_dns_info_blob = NULL;
344         DATA_BLOB *cred_ndr = NULL;
345         DATA_BLOB **cred_ndr_ptr = NULL;
346         DATA_BLOB cred_blob = data_blob_null;
347         DATA_BLOB *pcred_blob = NULL;
348         NTSTATUS nt_status;
349         krb5_error_code code;
350         struct samba_kdc_entry *skdc_entry;
351
352         skdc_entry = talloc_get_type_abort(client->e_data,
353                                            struct samba_kdc_entry);
354
355         tmp_ctx = talloc_named(smb_ctx,
356                                0,
357                                "mit_samba_get_pac_data_blobs context");
358         if (tmp_ctx == NULL) {
359                 return ENOMEM;
360         }
361
362 #if 0 /* TODO Find out if this is a pkinit_reply key */
363         /* Check if we have a PREAUTH key */
364         if (client_key != NULL) {
365                 cred_ndr_ptr = &cred_ndr;
366         }
367 #endif
368
369         nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
370                                             skdc_entry,
371                                             &logon_info_blob,
372                                             cred_ndr_ptr,
373                                             &upn_dns_info_blob);
374         if (!NT_STATUS_IS_OK(nt_status)) {
375                 talloc_free(tmp_ctx);
376                 return EINVAL;
377         }
378
379         if (cred_ndr != NULL) {
380                 code = samba_kdc_encrypt_pac_credentials(context,
381                                                          client_key,
382                                                          cred_ndr,
383                                                          tmp_ctx,
384                                                          &cred_blob);
385                 if (code != 0) {
386                         talloc_free(tmp_ctx);
387                         return code;
388                 }
389                 pcred_blob = &cred_blob;
390         }
391
392         code = samba_make_krb5_pac(context,
393                                    logon_info_blob,
394                                    pcred_blob,
395                                    upn_dns_info_blob,
396                                    NULL,
397                                    pac);
398
399         talloc_free(tmp_ctx);
400         return code;
401 }
402
403 krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
404                                     krb5_context context,
405                                     int flags,
406                                     krb5_const_principal client_principal,
407                                     krb5_db_entry *client,
408                                     krb5_db_entry *server,
409                                     krb5_db_entry *krbtgt,
410                                     krb5_keyblock *krbtgt_keyblock,
411                                     krb5_pac *pac)
412 {
413         TALLOC_CTX *tmp_ctx;
414         krb5_error_code code;
415         NTSTATUS nt_status;
416         DATA_BLOB *pac_blob = NULL;
417         DATA_BLOB *upn_blob = NULL;
418         DATA_BLOB *deleg_blob = NULL;
419         struct samba_kdc_entry *client_skdc_entry = NULL;
420         struct samba_kdc_entry *krbtgt_skdc_entry;
421         bool is_in_db = false;
422         bool is_untrusted = false;
423         size_t num_types = 0;
424         uint32_t *types = NULL;
425         uint32_t forced_next_type = 0;
426         size_t i = 0;
427         ssize_t logon_info_idx = -1;
428         ssize_t delegation_idx = -1;
429         ssize_t logon_name_idx = -1;
430         ssize_t upn_dns_info_idx = -1;
431         ssize_t srv_checksum_idx = -1;
432         ssize_t kdc_checksum_idx = -1;
433         krb5_pac new_pac = NULL;
434         bool ok;
435
436         if (client != NULL) {
437                 client_skdc_entry =
438                         talloc_get_type_abort(client->e_data,
439                                               struct samba_kdc_entry);
440
441                 /* The user account may be set not to want the PAC */
442                 ok = samba_princ_needs_pac(client_skdc_entry);
443                 if (!ok) {
444                         return EINVAL;
445                 }
446         }
447
448         if (krbtgt == NULL) {
449                 return EINVAL;
450         }
451         krbtgt_skdc_entry =
452                 talloc_get_type_abort(krbtgt->e_data,
453                                       struct samba_kdc_entry);
454
455         tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
456         if (tmp_ctx == NULL) {
457                 return ENOMEM;
458         }
459
460         code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
461                                      &is_in_db,
462                                      &is_untrusted);
463         if (code != 0) {
464                 goto done;
465         }
466
467         if (is_untrusted) {
468                 if (client == NULL) {
469                         code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
470                         goto done;
471                 }
472
473                 nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
474                                                     client_skdc_entry,
475                                                     &pac_blob,
476                                                     NULL,
477                                                     &upn_blob);
478                 if (!NT_STATUS_IS_OK(nt_status)) {
479                         code = EINVAL;
480                         goto done;
481                 }
482         } else {
483                 struct PAC_SIGNATURE_DATA *pac_srv_sig;
484                 struct PAC_SIGNATURE_DATA *pac_kdc_sig;
485
486                 pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
487                 if (pac_blob == NULL) {
488                         code = ENOMEM;
489                         goto done;
490                 }
491
492                 pac_srv_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
493                 if (pac_srv_sig == NULL) {
494                         code = ENOMEM;
495                         goto done;
496                 }
497
498                 pac_kdc_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
499                 if (pac_kdc_sig == NULL) {
500                         code = ENOMEM;
501                         goto done;
502                 }
503
504                 nt_status = samba_kdc_update_pac_blob(tmp_ctx,
505                                                       context,
506                                                       *pac,
507                                                       pac_blob,
508                                                       pac_srv_sig,
509                                                       pac_kdc_sig);
510                 if (!NT_STATUS_IS_OK(nt_status)) {
511                         DEBUG(0, ("Update PAC blob failed: %s\n",
512                                   nt_errstr(nt_status)));
513                         code = EINVAL;
514                         goto done;
515                 }
516
517                 if (is_in_db) {
518                         /*
519                          * Now check the KDC signature, fetching the correct
520                          * key based on the enc type.
521                          */
522                         code = check_pac_checksum(pac_srv_sig->signature,
523                                                   pac_kdc_sig,
524                                                   context,
525                                                   krbtgt_keyblock);
526                         if (code != 0) {
527                                 DBG_INFO("PAC KDC signature failed to verify\n");
528                                 goto done;
529                         }
530                 }
531         }
532
533         if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
534                 deleg_blob = talloc_zero(tmp_ctx, DATA_BLOB);
535                 if (deleg_blob == NULL) {
536                         code = ENOMEM;
537                         goto done;
538                 }
539
540                 nt_status = samba_kdc_update_delegation_info_blob(tmp_ctx,
541                                                                   context,
542                                                                   *pac,
543                                                                   server->princ,
544                                                                   discard_const(client_principal),
545                                                                   deleg_blob);
546                 if (!NT_STATUS_IS_OK(nt_status)) {
547                         DEBUG(0, ("Update delegation info failed: %s\n",
548                                   nt_errstr(nt_status)));
549                         code = EINVAL;
550                         goto done;
551                 }
552         }
553
554         /* Check the types of the given PAC */
555         code = krb5_pac_get_types(context, *pac, &num_types, &types);
556         if (code != 0) {
557                 goto done;
558         }
559
560         for (i = 0; i < num_types; i++) {
561                 switch (types[i]) {
562                 case PAC_TYPE_LOGON_INFO:
563                         if (logon_info_idx != -1) {
564                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
565                                             types[i],
566                                             logon_info_idx,
567                                             i);
568                                 SAFE_FREE(types);
569                                 code = EINVAL;
570                                 goto done;
571                         }
572                         logon_info_idx = i;
573                         break;
574                 case PAC_TYPE_CONSTRAINED_DELEGATION:
575                         if (delegation_idx != -1) {
576                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
577                                             types[i],
578                                             delegation_idx,
579                                             i);
580                                 SAFE_FREE(types);
581                                 code = EINVAL;
582                                 goto done;
583                         }
584                         delegation_idx = i;
585                         break;
586                 case PAC_TYPE_LOGON_NAME:
587                         if (logon_name_idx != -1) {
588                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
589                                             types[i],
590                                             logon_name_idx,
591                                             i);
592                                 SAFE_FREE(types);
593                                 code = EINVAL;
594                                 goto done;
595                         }
596                         logon_name_idx = i;
597                         break;
598                 case PAC_TYPE_UPN_DNS_INFO:
599                         if (upn_dns_info_idx != -1) {
600                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
601                                             types[i],
602                                             upn_dns_info_idx,
603                                             i);
604                                 SAFE_FREE(types);
605                                 code = EINVAL;
606                                 goto done;
607                         }
608                         upn_dns_info_idx = i;
609                         break;
610                 case PAC_TYPE_SRV_CHECKSUM:
611                         if (srv_checksum_idx != -1) {
612                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
613                                             types[i],
614                                             srv_checksum_idx,
615                                             i);
616                                 SAFE_FREE(types);
617                                 code = EINVAL;
618                                 goto done;
619                         }
620                         srv_checksum_idx = i;
621                         break;
622                 case PAC_TYPE_KDC_CHECKSUM:
623                         if (kdc_checksum_idx != -1) {
624                                 DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
625                                             types[i],
626                                             kdc_checksum_idx,
627                                             i);
628                                 SAFE_FREE(types);
629                                 code = EINVAL;
630                                 goto done;
631                         }
632                         kdc_checksum_idx = i;
633                         break;
634                 default:
635                         continue;
636                 }
637         }
638
639         if (logon_info_idx == -1) {
640                 DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
641                 SAFE_FREE(types);
642                 code = EINVAL;
643                 goto done;
644         }
645         if (logon_name_idx == -1) {
646                 DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
647                 SAFE_FREE(types);
648                 code = EINVAL;
649                 goto done;
650         }
651         if (srv_checksum_idx == -1) {
652                 DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
653                 SAFE_FREE(types);
654                 code = EINVAL;
655                 goto done;
656         }
657         if (kdc_checksum_idx == -1) {
658                 DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
659                 SAFE_FREE(types);
660                 code = EINVAL;
661                 goto done;
662         }
663
664         /* Build an updated PAC */
665         code = krb5_pac_init(context, &new_pac);
666         if (code != 0) {
667                 SAFE_FREE(types);
668                 goto done;
669         }
670
671         for (i = 0;;) {
672                 krb5_data type_data;
673                 DATA_BLOB type_blob = data_blob_null;
674                 uint32_t type;
675
676                 if (forced_next_type != 0) {
677                         /*
678                          * We need to inject possible missing types
679                          */
680                         type = forced_next_type;
681                         forced_next_type = 0;
682                 } else if (i < num_types) {
683                         type = types[i];
684                         i++;
685                 } else {
686                         break;
687                 }
688
689                 switch (type) {
690                 case PAC_TYPE_LOGON_INFO:
691                         type_blob = *pac_blob;
692
693                         if (delegation_idx == -1 && deleg_blob != NULL) {
694                                 /* inject CONSTRAINED_DELEGATION behind */
695                                 forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
696                         }
697                         break;
698                 case PAC_TYPE_CONSTRAINED_DELEGATION:
699                         if (deleg_blob != NULL) {
700                                 type_blob = *deleg_blob;
701                         }
702                         break;
703                 case PAC_TYPE_CREDENTIAL_INFO:
704                         /*
705                          * Note that we copy the credential blob,
706                          * as it's only usable with the PKINIT based
707                          * AS-REP reply key, it's only available on the
708                          * host which did the AS-REQ/AS-REP exchange.
709                          *
710                          * This matches Windows 2008R2...
711                          */
712                         break;
713                 case PAC_TYPE_LOGON_NAME:
714                         /*
715                          * This is generated in the main KDC code
716                          */
717                         continue;
718                 case PAC_TYPE_UPN_DNS_INFO:
719                         /*
720                          * Replace in the RODC case, otherwise
721                          * upn_blob is NULL and we just copy.
722                          */
723                         if (upn_blob != NULL) {
724                                 type_blob = *upn_blob;
725                         }
726                         break;
727                 case PAC_TYPE_SRV_CHECKSUM:
728                         /*
729                          * This is generated in the main KDC code
730                          */
731                         continue;
732                 case PAC_TYPE_KDC_CHECKSUM:
733                         /*
734                          * This is generated in the main KDC code
735                          */
736                         continue;
737                 default:
738                         /* just copy... */
739                         break;
740                 }
741
742                 if (type_blob.length != 0) {
743                         code = smb_krb5_copy_data_contents(&type_data,
744                                                            type_blob.data,
745                                                            type_blob.length);
746                         if (code != 0) {
747                                 SAFE_FREE(types);
748                                 krb5_pac_free(context, new_pac);
749                                 goto done;
750                         }
751                 } else {
752                         code = krb5_pac_get_buffer(context,
753                                                    *pac,
754                                                    type,
755                                                    &type_data);
756                         if (code != 0) {
757                                 SAFE_FREE(types);
758                                 krb5_pac_free(context, new_pac);
759                                 goto done;
760                         }
761                 }
762
763                 code = krb5_pac_add_buffer(context,
764                                            new_pac,
765                                            type,
766                                            &type_data);
767                 smb_krb5_free_data_contents(context, &type_data);
768                 if (code != 0) {
769                         SAFE_FREE(types);
770                         krb5_pac_free(context, new_pac);
771                         goto done;
772                 }
773         }
774
775         SAFE_FREE(types);
776
777         /* We now replace the pac */
778         krb5_pac_free(context, *pac);
779         *pac = new_pac;
780 done:
781         talloc_free(tmp_ctx);
782         return code;
783 }
784
785 /* provide header, function is exported but there are no public headers */
786
787 krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
788
789 /* this function allocates 'data' using malloc.
790  * The caller is responsible for freeing it */
791 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
792 {
793         krb5_error_code ret = 0;
794         krb5_pa_data pa, *ppa = NULL;
795         krb5_data *d = NULL;
796
797         if (!e_data)
798                 return;
799
800         e_data->data   = NULL;
801         e_data->length = 0;
802
803         pa.magic                = KV5M_PA_DATA;
804         pa.pa_type              = KRB5_PADATA_PW_SALT;
805         pa.length               = 12;
806         pa.contents             = malloc(pa.length);
807         if (!pa.contents) {
808                 return;
809         }
810
811         SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
812         SIVAL(pa.contents, 4, 0);
813         SIVAL(pa.contents, 8, 1);
814
815         ppa = &pa;
816
817         ret = encode_krb5_padata_sequence(&ppa, &d);
818         free(pa.contents);
819         if (ret) {
820                 return;
821         }
822
823         e_data->data   = (uint8_t *)d->data;
824         e_data->length = d->length;
825
826         /* free d, not d->data - gd */
827         free(d);
828
829         return;
830 }
831
832 int mit_samba_check_client_access(struct mit_samba_context *ctx,
833                                   krb5_db_entry *client,
834                                   const char *client_name,
835                                   krb5_db_entry *server,
836                                   const char *server_name,
837                                   const char *netbios_name,
838                                   bool password_change,
839                                   DATA_BLOB *e_data)
840 {
841         struct samba_kdc_entry *skdc_entry;
842         NTSTATUS nt_status;
843
844         skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
845
846         nt_status = samba_kdc_check_client_access(skdc_entry,
847                                                   client_name,
848                                                   netbios_name,
849                                                   password_change);
850
851         if (!NT_STATUS_IS_OK(nt_status)) {
852                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
853                         return ENOMEM;
854                 }
855
856                 samba_kdc_build_edata_reply(nt_status, e_data);
857
858                 return samba_kdc_map_policy_err(nt_status);
859         }
860
861         return 0;
862 }
863
864 int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
865                               krb5_db_entry *kentry,
866                               const char *target_name,
867                               bool is_nt_enterprise_name)
868 {
869 #if 1
870         /*
871          * This is disabled because mit_samba_update_pac_data() does not handle
872          * S4U_DELEGATION_INFO
873          */
874
875         return KRB5KDC_ERR_BADOPTION;
876 #else
877         krb5_principal target_principal;
878         int flags = 0;
879         int ret;
880
881         if (is_nt_enterprise_name) {
882                 flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
883         }
884
885         ret = krb5_parse_name_flags(ctx->context, target_name,
886                                     flags, &target_principal);
887         if (ret) {
888                 return ret;
889         }
890
891         ret = samba_kdc_check_s4u2proxy(ctx->context,
892                                         ctx->db_ctx,
893                                         skdc_entry,
894                                         target_principal);
895
896         krb5_free_principal(ctx->context, target_principal);
897
898         return ret;
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         krb5_error_code code = 0;
980
981 #ifdef DEBUG_PASSWORD
982         DEBUG(1,("mit_samba_kpasswd_change_password called with: %s\n", pwd));
983 #endif
984
985         tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
986         if (tmp_ctx == NULL) {
987                 return ENOMEM;
988         }
989
990         p = (struct samba_kdc_entry *)db_entry->e_data;
991
992         status = authsam_make_user_info_dc(tmp_ctx,
993                                            ctx->db_ctx->samdb,
994                                            lpcfg_netbios_name(ctx->db_ctx->lp_ctx),
995                                            lpcfg_sam_name(ctx->db_ctx->lp_ctx),
996                                            lpcfg_sam_dnsname(ctx->db_ctx->lp_ctx),
997                                            p->realm_dn,
998                                            p->msg,
999                                            data_blob(NULL, 0),
1000                                            data_blob(NULL, 0),
1001                                            &user_info_dc);
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 DEBUG(1,("authsam_make_user_info_dc failed: %s\n",
1004                         nt_errstr(status)));
1005                 talloc_free(tmp_ctx);
1006                 return EINVAL;
1007         }
1008
1009         status = auth_generate_session_info(tmp_ctx,
1010                                             ctx->db_ctx->lp_ctx,
1011                                             ctx->db_ctx->samdb,
1012                                             user_info_dc,
1013                                             0, /* session_info_flags */
1014                                             &ctx->session_info);
1015
1016         if (!NT_STATUS_IS_OK(status)) {
1017                 DEBUG(1,("auth_generate_session_info failed: %s\n",
1018                         nt_errstr(status)));
1019                 talloc_free(tmp_ctx);
1020                 return EINVAL;
1021         }
1022
1023         /* password is expected as UTF16 */
1024
1025         if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
1026                                    pwd, strlen(pwd),
1027                                    &password.data, &password.length)) {
1028                 DEBUG(1,("convert_string_talloc failed\n"));
1029                 talloc_free(tmp_ctx);
1030                 return EINVAL;
1031         }
1032
1033         status = samdb_kpasswd_change_password(tmp_ctx,
1034                                                ctx->db_ctx->lp_ctx,
1035                                                ctx->db_ctx->ev_ctx,
1036                                                ctx->db_ctx->samdb,
1037                                                ctx->session_info,
1038                                                &password,
1039                                                &reject_reason,
1040                                                &dominfo,
1041                                                &error_string,
1042                                                &result);
1043         if (!NT_STATUS_IS_OK(status)) {
1044                 DEBUG(1,("samdb_kpasswd_change_password failed: %s\n",
1045                         nt_errstr(status)));
1046                 code = KADM5_PASS_Q_GENERIC;
1047                 krb5_set_error_message(ctx->context, code, "%s", error_string);
1048                 goto out;
1049         }
1050
1051         if (!NT_STATUS_IS_OK(result)) {
1052                 code = mit_samba_change_pwd_error(ctx->context,
1053                                                   result,
1054                                                   reject_reason,
1055                                                   dominfo);
1056         }
1057
1058 out:
1059         talloc_free(tmp_ctx);
1060
1061         return code;
1062 }
1063
1064 void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
1065 {
1066         struct samba_kdc_entry *p;
1067         struct ldb_dn *domain_dn;
1068
1069         p = (struct samba_kdc_entry *)db_entry->e_data;
1070
1071         domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
1072
1073         authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
1074                                          p->msg,
1075                                          domain_dn,
1076                                          true);
1077 }
1078
1079
1080 void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
1081 {
1082         struct samba_kdc_entry *p;
1083
1084         p = (struct samba_kdc_entry *)db_entry->e_data;
1085
1086         authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
1087                                      p->msg,
1088                                      ldb_get_default_basedn(p->kdc_db_ctx->samdb));
1089 }