dfca27175a21813679c2eb25542676dd2730e1ba
[samba.git] / source4 / kdc / wdc-samba4.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    PAC Glue between Samba and the KDC
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7    Copyright (C) Simo Sorce <idra@samba.org> 2010
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "kdc/kdc-glue.h"
26 #include "kdc/db-glue.h"
27 #include "kdc/pac-glue.h"
28 #include "sdb.h"
29 #include "sdb_hdb.h"
30 #include "librpc/gen_ndr/auth.h"
31 #include <krb5_locl.h>
32
33 /*
34  * Given the right private pointer from hdb_samba4,
35  * get a PAC from the attached ldb messages.
36  *
37  * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
38  */
39 static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
40                                          krb5_kdc_configuration *config,
41                                          hdb_entry *client,
42                                          hdb_entry *server,
43                                          const krb5_keyblock *pk_reply_key,
44                                          uint64_t pac_attributes,
45                                          krb5_pac *pac)
46 {
47         TALLOC_CTX *mem_ctx;
48         DATA_BLOB *logon_blob = NULL;
49         DATA_BLOB *cred_ndr = NULL;
50         DATA_BLOB **cred_ndr_ptr = NULL;
51         DATA_BLOB _cred_blob = data_blob_null;
52         DATA_BLOB *cred_blob = NULL;
53         DATA_BLOB *upn_blob = NULL;
54         DATA_BLOB *pac_attrs_blob = NULL;
55         DATA_BLOB *requester_sid_blob = NULL;
56         krb5_error_code ret;
57         NTSTATUS nt_status;
58         struct samba_kdc_entry *skdc_entry =
59                 talloc_get_type_abort(client->context,
60                 struct samba_kdc_entry);
61         bool is_krbtgt;
62
63         mem_ctx = talloc_named(client->context, 0, "samba_get_pac context");
64         if (!mem_ctx) {
65                 return ENOMEM;
66         }
67
68         if (pk_reply_key != NULL) {
69                 cred_ndr_ptr = &cred_ndr;
70         }
71
72         is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
73
74         nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
75                                             &logon_blob,
76                                             cred_ndr_ptr,
77                                             &upn_blob,
78                                             is_krbtgt ? &pac_attrs_blob : NULL,
79                                             pac_attributes,
80                                             is_krbtgt ? &requester_sid_blob : NULL,
81                                             NULL);
82         if (!NT_STATUS_IS_OK(nt_status)) {
83                 talloc_free(mem_ctx);
84                 return EINVAL;
85         }
86
87         if (pk_reply_key != NULL && cred_ndr != NULL) {
88                 ret = samba_kdc_encrypt_pac_credentials(context,
89                                                         pk_reply_key,
90                                                         cred_ndr,
91                                                         mem_ctx,
92                                                         &_cred_blob);
93                 if (ret != 0) {
94                         talloc_free(mem_ctx);
95                         return ret;
96                 }
97                 cred_blob = &_cred_blob;
98         }
99
100         ret = krb5_pac_init(context, pac);
101         if (ret != 0) {
102                 talloc_free(mem_ctx);
103                 return ret;
104         }
105
106         ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
107                                   upn_blob, pac_attrs_blob,
108                                   requester_sid_blob, NULL, *pac);
109
110         talloc_free(mem_ctx);
111         return ret;
112 }
113
114 static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
115                                             const krb5_principal delegated_proxy_principal,
116                                             hdb_entry *client,
117                                             hdb_entry *server,
118                                             hdb_entry *krbtgt,
119                                             krb5_pac *pac,
120                                             krb5_cksumtype ctype)
121 {
122         struct samba_kdc_entry *server_skdc_entry =
123                 talloc_get_type_abort(server->context,
124                 struct samba_kdc_entry);
125         struct samba_kdc_entry *krbtgt_skdc_entry =
126                 talloc_get_type_abort(krbtgt->context,
127                 struct samba_kdc_entry);
128         TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry,
129                                            0,
130                                            "samba_kdc_reget_pac2 context");
131         krb5_pac new_pac = NULL;
132         DATA_BLOB *pac_blob = NULL;
133         DATA_BLOB *upn_blob = NULL;
134         DATA_BLOB *requester_sid_blob = NULL;
135         DATA_BLOB *deleg_blob = NULL;
136         krb5_error_code ret;
137         NTSTATUS nt_status;
138         bool is_in_db, is_untrusted;
139         bool is_krbtgt;
140         size_t num_types = 0;
141         uint32_t *types = NULL;
142         uint32_t forced_next_type = 0;
143         size_t i = 0;
144         ssize_t logon_info_idx = -1;
145         ssize_t delegation_idx = -1;
146         ssize_t logon_name_idx = -1;
147         ssize_t upn_dns_info_idx = -1;
148         ssize_t srv_checksum_idx = -1;
149         ssize_t kdc_checksum_idx = -1;
150         ssize_t tkt_checksum_idx = -1;
151         ssize_t attrs_info_idx = -1;
152         ssize_t requester_sid_idx = -1;
153
154         if (!mem_ctx) {
155                 return ENOMEM;
156         }
157
158         if (client != NULL) {
159                 struct samba_kdc_entry *client_skdc_entry = NULL;
160
161                 client_skdc_entry = talloc_get_type_abort(client->context,
162                                                           struct samba_kdc_entry);
163
164                 /*
165                  * Check the objectSID of the client and pac data are the same.
166                  * Does a parse and SID check, but no crypto.
167                  */
168                 ret = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac);
169                 if (ret != 0) {
170                         talloc_free(mem_ctx);
171                         return ret;
172                 }
173         }
174
175         /*
176          * If the krbtgt was generated by an RODC, and we are not that
177          * RODC, then we need to regenerate the PAC - we can't trust
178          * it, and confirm that the RODC was permitted to print this ticket
179          *
180          * Becasue of the samba_kdc_validate_pac_blob() step we can be
181          * sure that the record in 'client' matches the SID in the
182          * original PAC.
183          */
184         ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted);
185         if (ret != 0) {
186                 talloc_free(mem_ctx);
187                 return ret;
188         }
189
190         if (delegated_proxy_principal != NULL) {
191                 krb5_enctype etype;
192                 Key *key = NULL;
193
194                 if (!is_in_db) {
195                         /*
196                          * The RODC-issued PAC was signed by a KDC entry that we
197                          * don't have a key for. The server signature is not
198                          * trustworthy, since it could have been created by the
199                          * server we got the ticket from. We must not proceed as
200                          * otherwise the ticket signature is unchecked.
201                          */
202                         talloc_free(mem_ctx);
203                         return HDB_ERR_NOT_FOUND_HERE;
204                 }
205
206                 /* Fetch the correct key depending on the checksum type. */
207                 if (ctype == CKSUMTYPE_HMAC_MD5) {
208                         etype = ENCTYPE_ARCFOUR_HMAC;
209                 } else {
210                         ret = krb5_cksumtype_to_enctype(context,
211                                                         ctype,
212                                                         &etype);
213                         if (ret != 0) {
214                                 talloc_free(mem_ctx);
215                                 return ret;
216                         }
217                 }
218                 ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key);
219                 if (ret != 0) {
220                         talloc_free(mem_ctx);
221                         return ret;
222                 }
223
224                 /* Check the KDC and ticket signatures. */
225                 ret = krb5_pac_verify(context,
226                                       *pac,
227                                       0,
228                                       NULL,
229                                       NULL,
230                                       &key->key);
231                 if (ret != 0) {
232                         DEBUG(1, ("PAC KDC signature failed to verify\n"));
233                         talloc_free(mem_ctx);
234                         return ret;
235                 }
236
237                 deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
238                 if (!deleg_blob) {
239                         talloc_free(mem_ctx);
240                         return ENOMEM;
241                 }
242
243                 nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
244                                         context, *pac,
245                                         server->principal,
246                                         delegated_proxy_principal,
247                                         deleg_blob);
248                 if (!NT_STATUS_IS_OK(nt_status)) {
249                         DBG_ERR("samba_kdc_update_delegation_info_blob() failed: %s\n",
250                                 nt_errstr(nt_status));
251                         talloc_free(mem_ctx);
252                         return EINVAL;
253                 }
254         }
255
256         if (is_untrusted) {
257                 struct samba_kdc_entry *client_skdc_entry = NULL;
258                 struct auth_user_info_dc *user_info_dc = NULL;
259                 WERROR werr;
260
261                 if (client == NULL) {
262                         return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
263                 }
264
265                 client_skdc_entry = talloc_get_type_abort(client->context,
266                                                           struct samba_kdc_entry);
267
268                 nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
269                                                     &pac_blob, NULL, &upn_blob,
270                                                     NULL, PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
271                                                     &requester_sid_blob,
272                                                     &user_info_dc);
273                 if (!NT_STATUS_IS_OK(nt_status)) {
274                         talloc_free(mem_ctx);
275                         DBG_ERR("samba_kdc_get_pac_blobs() failed: %s\n",
276                                 nt_errstr(nt_status));
277                         return KRB5KDC_ERR_TGT_REVOKED;
278                 }
279
280                 /*
281                  * Now check if the SID list in the user_info_dc
282                  * intersects correctly with the RODC allow/deny
283                  * lists
284                  */
285
286                 werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
287                                                           user_info_dc->sids,
288                                                           krbtgt_skdc_entry,
289                                                           client_skdc_entry);
290                 if (!W_ERROR_IS_OK(werr)) {
291                         talloc_free(mem_ctx);
292                         if (W_ERROR_EQUAL(werr, WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
293                                 return KRB5KDC_ERR_POLICY;
294                         } else {
295                                 return KRB5KDC_ERR_TGT_REVOKED;
296                         }
297                 }
298         }
299
300         if (!is_untrusted) {
301                 pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
302                 if (!pac_blob) {
303                         talloc_free(mem_ctx);
304                         return ENOMEM;
305                 }
306
307                 nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
308                                                       krbtgt_skdc_entry->kdc_db_ctx->samdb,
309                                                       *pac, pac_blob,
310                                                       NULL, NULL);
311                 if (!NT_STATUS_IS_OK(nt_status)) {
312                         DBG_ERR("samba_kdc_update_pac_blob() failed: %s\n",
313                                 nt_errstr(nt_status));
314                         talloc_free(mem_ctx);
315                         return EINVAL;
316                 }
317         }
318
319         /* Check the types of the given PAC */
320         ret = krb5_pac_get_types(context, *pac, &num_types, &types);
321         if (ret != 0) {
322                 talloc_free(mem_ctx);
323                 return ret;
324         }
325
326         for (i = 0; i < num_types; i++) {
327                 switch (types[i]) {
328                 case PAC_TYPE_LOGON_INFO:
329                         if (logon_info_idx != -1) {
330                                 DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
331                                           types[i],
332                                           logon_info_idx,
333                                           i));
334                                 SAFE_FREE(types);
335                                 talloc_free(mem_ctx);
336                                 return EINVAL;
337                         }
338                         logon_info_idx = i;
339                         break;
340                 case PAC_TYPE_CONSTRAINED_DELEGATION:
341                         if (delegation_idx != -1) {
342                                 DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n",
343                                           types[i],
344                                           delegation_idx,
345                                           i));
346                                 SAFE_FREE(types);
347                                 talloc_free(mem_ctx);
348                                 return EINVAL;
349                         }
350                         delegation_idx = i;
351                         break;
352                 case PAC_TYPE_LOGON_NAME:
353                         if (logon_name_idx != -1) {
354                                 DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n",
355                                           types[i],
356                                           logon_name_idx,
357                                           i));
358                                 SAFE_FREE(types);
359                                 talloc_free(mem_ctx);
360                                 return EINVAL;
361                         }
362                         logon_name_idx = i;
363                         break;
364                 case PAC_TYPE_UPN_DNS_INFO:
365                         if (upn_dns_info_idx != -1) {
366                                 DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
367                                           types[i],
368                                           upn_dns_info_idx,
369                                           i));
370                                 SAFE_FREE(types);
371                                 talloc_free(mem_ctx);
372                                 return EINVAL;
373                         }
374                         upn_dns_info_idx = i;
375                         break;
376                 case PAC_TYPE_SRV_CHECKSUM:
377                         if (srv_checksum_idx != -1) {
378                                 DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
379                                           types[i],
380                                           srv_checksum_idx,
381                                           i));
382                                 SAFE_FREE(types);
383                                 talloc_free(mem_ctx);
384                                 return EINVAL;
385                         }
386                         srv_checksum_idx = i;
387                         break;
388                 case PAC_TYPE_KDC_CHECKSUM:
389                         if (kdc_checksum_idx != -1) {
390                                 DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
391                                           types[i],
392                                           kdc_checksum_idx,
393                                           i));
394                                 SAFE_FREE(types);
395                                 talloc_free(mem_ctx);
396                                 return EINVAL;
397                         }
398                         kdc_checksum_idx = i;
399                         break;
400                 case PAC_TYPE_TICKET_CHECKSUM:
401                         if (tkt_checksum_idx != -1) {
402                                 DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
403                                           types[i],
404                                           tkt_checksum_idx,
405                                           i));
406                                 SAFE_FREE(types);
407                                 talloc_free(mem_ctx);
408                                 return EINVAL;
409                         }
410                         tkt_checksum_idx = i;
411                         break;
412                 case PAC_TYPE_ATTRIBUTES_INFO:
413                         if (attrs_info_idx != -1) {
414                                 DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
415                                           types[i],
416                                           attrs_info_idx,
417                                           i));
418                                 SAFE_FREE(types);
419                                 talloc_free(mem_ctx);
420                                 return EINVAL;
421                         }
422                         attrs_info_idx = i;
423                         break;
424                 case PAC_TYPE_REQUESTER_SID:
425                         if (requester_sid_idx != -1) {
426                                 DEBUG(1, ("requester sid type[%"PRIu32"] twice [%zd] and [%zu]: \n",
427                                           types[i],
428                                           requester_sid_idx,
429                                           i));
430                                 SAFE_FREE(types);
431                                 talloc_free(mem_ctx);
432                                 return EINVAL;
433                         }
434                         requester_sid_idx = i;
435                         break;
436                 default:
437                         continue;
438                 }
439         }
440
441         if (logon_info_idx == -1) {
442                 DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
443                 SAFE_FREE(types);
444                 talloc_free(mem_ctx);
445                 return EINVAL;
446         }
447         if (logon_name_idx == -1) {
448                 DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
449                 SAFE_FREE(types);
450                 talloc_free(mem_ctx);
451                 return EINVAL;
452         }
453         if (srv_checksum_idx == -1) {
454                 DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
455                 SAFE_FREE(types);
456                 talloc_free(mem_ctx);
457                 return EINVAL;
458         }
459         if (kdc_checksum_idx == -1) {
460                 DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
461                 SAFE_FREE(types);
462                 talloc_free(mem_ctx);
463                 return EINVAL;
464         }
465         if (delegated_proxy_principal == NULL && requester_sid_idx == -1) {
466                 DEBUG(1, ("PAC_TYPE_REQUESTER_SID missing\n"));
467                 SAFE_FREE(types);
468                 talloc_free(mem_ctx);
469                 return KRB5KDC_ERR_TGT_REVOKED;
470         }
471
472         /*
473          * The server account may be set not to want the PAC.
474          *
475          * While this is wasteful if the above cacluations were done
476          * and now thrown away, this is cleaner as we do any ticket
477          * signature checking etc always.
478          *
479          * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
480          * time (eg not accepting a ticket from the RODC) we do not
481          * need to re-generate anything anyway.
482          */
483         if (!samba_princ_needs_pac(server_skdc_entry)) {
484                 ret = 0;
485                 new_pac = NULL;
486                 goto out;
487         }
488
489         is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
490
491         if (!is_untrusted && !is_krbtgt) {
492                 /*
493                  * The client may have requested no PAC when obtaining the
494                  * TGT.
495                  */
496                 bool requested_pac;
497                 ret = samba_client_requested_pac(context, pac, mem_ctx,
498                                                  &requested_pac);
499                 if (ret != 0 || !requested_pac) {
500                         new_pac = NULL;
501                         goto out;
502                 }
503         }
504
505         /* Otherwise build an updated PAC */
506         ret = krb5_pac_init(context, &new_pac);
507         if (ret != 0) {
508                 new_pac = NULL;
509                 goto out;
510         }
511
512         for (i = 0;;) {
513                 const uint8_t zero_byte = 0;
514                 krb5_data type_data;
515                 DATA_BLOB type_blob = data_blob_null;
516                 uint32_t type;
517
518                 if (forced_next_type != 0) {
519                         /*
520                          * We need to inject possible missing types
521                          */
522                         type = forced_next_type;
523                         forced_next_type = 0;
524                 } else if (i < num_types) {
525                         type = types[i];
526                         i++;
527                 } else {
528                         break;
529                 }
530
531                 switch (type) {
532                 case PAC_TYPE_LOGON_INFO:
533                         type_blob = *pac_blob;
534
535                         if (delegation_idx == -1 && deleg_blob != NULL) {
536                                 /* inject CONSTRAINED_DELEGATION behind */
537                                 forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
538                         }
539                         break;
540                 case PAC_TYPE_CONSTRAINED_DELEGATION:
541                         if (deleg_blob != NULL) {
542                                 type_blob = *deleg_blob;
543                         }
544                         break;
545                 case PAC_TYPE_CREDENTIAL_INFO:
546                         /*
547                          * Note that we copy the credential blob,
548                          * as it's only usable with the PKINIT based
549                          * AS-REP reply key, it's only available on the
550                          * host which did the AS-REQ/AS-REP exchange.
551                          *
552                          * This matches Windows 2008R2...
553                          */
554                         break;
555                 case PAC_TYPE_LOGON_NAME:
556                         /*
557                          * this is generated in the main KDC code
558                          * we just add a place holder here.
559                          */
560                         type_blob = data_blob_const(&zero_byte, 1);
561
562                         if (upn_dns_info_idx == -1 && upn_blob != NULL) {
563                                 /* inject UPN_DNS_INFO behind */
564                                 forced_next_type = PAC_TYPE_UPN_DNS_INFO;
565                         }
566                         break;
567                 case PAC_TYPE_UPN_DNS_INFO:
568                         /*
569                          * Replace in the RODC case, otherwise
570                          * upn_blob is NULL and we just copy.
571                          */
572                         if (upn_blob != NULL) {
573                                 type_blob = *upn_blob;
574                         }
575                         break;
576                 case PAC_TYPE_SRV_CHECKSUM:
577                         /*
578                          * this are generated in the main KDC code
579                          * we just add a place holder here.
580                          */
581                         type_blob = data_blob_const(&zero_byte, 1);
582
583                         if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
584                                 /* inject REQUESTER_SID behind */
585                                 forced_next_type = PAC_TYPE_REQUESTER_SID;
586                         }
587                         break;
588                 case PAC_TYPE_KDC_CHECKSUM:
589                         /*
590                          * this are generated in the main KDC code
591                          * we just add a place holders here.
592                          */
593                         type_blob = data_blob_const(&zero_byte, 1);
594                         break;
595                 case PAC_TYPE_ATTRIBUTES_INFO:
596                         if (!is_untrusted && is_krbtgt) {
597                                 /* just copy... */
598                                 break;
599                         } else {
600                                 continue;
601                         }
602                 case PAC_TYPE_REQUESTER_SID:
603                         if (is_krbtgt) {
604                                 /*
605                                  * Replace in the RODC case, otherwise
606                                  * requester_sid_blob is NULL and we just copy.
607                                  */
608                                 if (requester_sid_blob != NULL) {
609                                         type_blob = *requester_sid_blob;
610                                 }
611                                 break;
612                         } else {
613                                 continue;
614                         }
615                 default:
616                         /* just copy... */
617                         break;
618                 }
619
620                 if (type_blob.length != 0) {
621                         ret = smb_krb5_copy_data_contents(&type_data,
622                                                           type_blob.data,
623                                                           type_blob.length);
624                         if (ret != 0) {
625                                 SAFE_FREE(types);
626                                 krb5_pac_free(context, new_pac);
627                                 talloc_free(mem_ctx);
628                                 return ret;
629                         }
630                 } else {
631                         ret = krb5_pac_get_buffer(context, *pac,
632                                                   type, &type_data);
633                         if (ret != 0) {
634                                 SAFE_FREE(types);
635                                 krb5_pac_free(context, new_pac);
636                                 talloc_free(mem_ctx);
637                                 return ret;
638                         }
639                 }
640
641                 ret = krb5_pac_add_buffer(context, new_pac,
642                                           type, &type_data);
643                 smb_krb5_free_data_contents(context, &type_data);
644                 if (ret != 0) {
645                         SAFE_FREE(types);
646                         krb5_pac_free(context, new_pac);
647                         talloc_free(mem_ctx);
648                         return ret;
649                 }
650         }
651
652 out:
653
654         SAFE_FREE(types);
655
656         /* We now replace the pac */
657         krb5_pac_free(context, *pac);
658         *pac = new_pac;
659
660         talloc_free(mem_ctx);
661         return ret;
662 }
663
664 /* Resign (and reform, including possibly new groups) a PAC */
665
666 static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
667                                            krb5_kdc_configuration *config,
668                                            const krb5_principal client_principal,
669                                            const krb5_principal delegated_proxy_principal,
670                                            hdb_entry *client,
671                                            hdb_entry *server,
672                                            hdb_entry *krbtgt,
673                                            krb5_pac *pac)
674 {
675         struct samba_kdc_entry *krbtgt_skdc_entry =
676                 talloc_get_type_abort(krbtgt->context,
677                                       struct samba_kdc_entry);
678         krb5_error_code ret;
679         krb5_cksumtype ctype = CKSUMTYPE_NONE;
680         hdb_entry signing_krbtgt_hdb;
681
682         if (delegated_proxy_principal) {
683                 uint16_t rodc_id;
684                 unsigned int my_krbtgt_number;
685
686                 /*
687                  * We're using delegated_proxy_principal for the moment to
688                  * indicate cases where the ticket was encrypted with the server
689                  * key, and not a krbtgt key. This cannot be trusted, so we need
690                  * to find a krbtgt key that signs the PAC in order to trust the
691                  * ticket.
692                  *
693                  * The krbtgt passed in to this function refers to the krbtgt
694                  * used to decrypt the ticket of the server requesting
695                  * S4U2Proxy.
696                  *
697                  * When we implement service ticket renewal, we need to check
698                  * the PAC, and this will need to be updated.
699                  */
700                 ret = krb5_pac_get_kdc_checksum_info(context,
701                                                      *pac,
702                                                      &ctype,
703                                                      &rodc_id);
704                 if (ret != 0) {
705                         DEBUG(1, ("Failed to get PAC checksum info\n"));
706                         return ret;
707                 }
708
709                 /*
710                  * We need to check the KDC and ticket signatures, fetching the
711                  * correct key based on the enctype.
712                  */
713
714                 my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
715
716                 if (my_krbtgt_number != 0) {
717                         /*
718                          * If we are an RODC, and we are not the KDC that signed
719                          * the evidence ticket, then we need to proxy the
720                          * request.
721                          */
722                         if (rodc_id != my_krbtgt_number) {
723                                 return HDB_ERR_NOT_FOUND_HERE;
724                         }
725                 } else {
726                         /*
727                          * If we are a DC, the ticket may have been signed by a
728                          * different KDC than the one that issued the header
729                          * ticket.
730                          */
731                         if (rodc_id != krbtgt->kvno >> 16) {
732                                 struct sdb_entry_ex signing_krbtgt_sdb;
733
734                                 /*
735                                  * If we didn't sign the ticket, then return an
736                                  * error.
737                                  */
738                                 if (rodc_id != 0) {
739                                         return KRB5KRB_AP_ERR_MODIFIED;
740                                 }
741
742                                 /*
743                                  * Fetch our key from the database. To support
744                                  * key rollover, we're going to need to try
745                                  * multiple keys by trial and error. For now,
746                                  * krbtgt keys aren't assumed to change.
747                                  */
748                                 ret = samba_kdc_fetch(context,
749                                                       krbtgt_skdc_entry->kdc_db_ctx,
750                                                       krbtgt->principal,
751                                                       SDB_F_GET_KRBTGT | SDB_F_CANON,
752                                                       0,
753                                                       &signing_krbtgt_sdb);
754                                 if (ret != 0) {
755                                         return ret;
756                                 }
757
758                                 ret = sdb_entry_ex_to_hdb_entry_ex(context,
759                                                                    &signing_krbtgt_sdb,
760                                                                    &signing_krbtgt_hdb);
761                                 sdb_free_entry(&signing_krbtgt_sdb);
762                                 if (ret != 0) {
763                                         return ret;
764                                 }
765
766                                 /*
767                                  * Replace the krbtgt entry with our own entry
768                                  * for further processing.
769                                  */
770                                 krbtgt = &signing_krbtgt_hdb;
771                         }
772                 }
773         }
774
775         ret = samba_wdc_reget_pac2(context,
776                                    delegated_proxy_principal,
777                                    client,
778                                    server,
779                                    krbtgt,
780                                    pac,
781                                    ctype);
782
783         if (krbtgt == &signing_krbtgt_hdb) {
784                 hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb);
785         }
786
787         return ret;
788 }
789
790 static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
791 {
792         char *nb_name = NULL;
793         size_t len;
794         unsigned int i;
795
796         for (i = 0; addrs && i < addrs->len; i++) {
797                 if (addrs->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
798                         continue;
799                 }
800                 len = MIN(addrs->val[i].address.length, 15);
801                 nb_name = talloc_strndup(mem_ctx,
802                                          addrs->val[i].address.data, len);
803                 if (nb_name) {
804                         break;
805                 }
806         }
807
808         if ((nb_name == NULL) || (nb_name[0] == '\0')) {
809                 return NULL;
810         }
811
812         /* Strip space padding */
813         for (len = strlen(nb_name) - 1;
814              (len > 0) && (nb_name[len] == ' ');
815              --len) {
816                 nb_name[len] = '\0';
817         }
818
819         return nb_name;
820 }
821
822 /* this function allocates 'data' using malloc.
823  * The caller is responsible for freeing it */
824 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, krb5_data *e_data)
825 {
826         e_data->data = malloc(12);
827         if (e_data->data == NULL) {
828                 e_data->length = 0;
829                 e_data->data = NULL;
830                 return;
831         }
832         e_data->length = 12;
833
834         SIVAL(e_data->data, 0, NT_STATUS_V(nt_status));
835         SIVAL(e_data->data, 4, 0);
836         SIVAL(e_data->data, 8, 1);
837
838         return;
839 }
840
841 static krb5_error_code samba_wdc_check_client_access(void *priv,
842                                                      astgs_request_t r)
843 {
844         struct samba_kdc_entry *kdc_entry;
845         bool password_change;
846         char *workstation;
847         NTSTATUS nt_status;
848
849
850         kdc_entry = talloc_get_type(kdc_request_get_client(r)->context, struct samba_kdc_entry);
851         password_change = (kdc_request_get_server(r) && kdc_request_get_server(r)->flags.change_pw);
852         workstation = get_netbios_name((TALLOC_CTX *)kdc_request_get_client(r)->context,
853                                        kdc_request_get_req(r)->req_body.addresses);
854
855         nt_status = samba_kdc_check_client_access(kdc_entry,
856                                                   kdc_request_get_cname((kdc_request_t)r),
857                                                   workstation,
858                                                   password_change);
859
860         if (!NT_STATUS_IS_OK(nt_status)) {
861                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
862                         return ENOMEM;
863                 }
864
865                 if (kdc_request_get_rep(r)->padata) {
866                         int ret;
867                         krb5_data kd;
868
869                         samba_kdc_build_edata_reply(nt_status, &kd);
870                         ret = krb5_padata_add(kdc_request_get_context((kdc_request_t)r), kdc_request_get_rep(r)->padata,
871                                               KRB5_PADATA_PW_SALT,
872                                               kd.data, kd.length);
873                         if (ret != 0) {
874                                 /*
875                                  * So we do not leak the allocated
876                                  * memory on kd in the error case 
877                                  */
878                                 krb5_data_free(&kd);
879                         }
880                 }
881
882                 return samba_kdc_map_policy_err(nt_status);
883         }
884
885         /* Now do the standard Heimdal check */
886         return KRB5_PLUGIN_NO_HANDLE;
887 }
888
889 /* this function allocates 'data' using malloc.
890  * The caller is responsible for freeing it */
891 static krb5_error_code samba_kdc_build_supported_etypes(uint32_t supported_etypes,
892                                                         krb5_data *e_data)
893 {
894         e_data->data = malloc(4);
895         if (e_data->data == NULL) {
896                 return ENOMEM;
897         }
898         e_data->length = 4;
899
900         PUSH_LE_U32(e_data->data, 0, supported_etypes);
901
902         return 0;
903 }
904
905 static krb5_error_code samba_wdc_finalize_reply(void *priv,
906                                                 astgs_request_t r)
907 {
908         struct samba_kdc_entry *server_kdc_entry;
909         uint32_t supported_enctypes;
910
911         server_kdc_entry = talloc_get_type(kdc_request_get_server(r)->context, struct samba_kdc_entry);
912
913         /*
914          * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
915          * type to indicate what encryption types the server supports.
916          */
917         supported_enctypes = server_kdc_entry->supported_enctypes;
918         if (kdc_request_get_req(r)->req_body.kdc_options.canonicalize && supported_enctypes != 0) {
919                 krb5_error_code ret;
920
921                 PA_DATA md;
922
923                 ret = samba_kdc_build_supported_etypes(supported_enctypes, &md.padata_value);
924                 if (ret != 0) {
925                         return ret;
926                 }
927
928                 md.padata_type = KRB5_PADATA_SUPPORTED_ETYPES;
929
930                 ret = kdc_request_add_encrypted_padata(r, &md);
931                 if (ret != 0) {
932                         /*
933                          * So we do not leak the allocated
934                          * memory on kd in the error case
935                          */
936                         krb5_data_free(&md.padata_value);
937                 }
938         }
939
940         return 0;
941 }
942
943 static krb5_error_code samba_wdc_plugin_init(krb5_context context, void **ptr)
944 {
945         *ptr = NULL;
946         return 0;
947 }
948
949 static void samba_wdc_plugin_fini(void *ptr)
950 {
951         return;
952 }
953
954 static krb5_error_code samba_wdc_referral_policy(void *priv,
955                                                  astgs_request_t r)
956 {
957         return kdc_request_get_error_code((kdc_request_t)r);
958 }
959
960 struct krb5plugin_kdc_ftable kdc_plugin_table = {
961         .minor_version = KRB5_PLUGIN_KDC_VERSION_10,
962         .init = samba_wdc_plugin_init,
963         .fini = samba_wdc_plugin_fini,
964         .pac_verify = samba_wdc_reget_pac,
965         .client_access = samba_wdc_check_client_access,
966         .finalize_reply = samba_wdc_finalize_reply,
967         .pac_generate = samba_wdc_get_pac,
968         .referral_policy = samba_wdc_referral_policy,
969 };
970
971