CVE-2020-25719 s4:kdc: Add KDC support for PAC_ATTRIBUTES_INFO PAC buffer
[Samba.git] / source4 / kdc / wdc-samba4.c
blob11d9ff84f04b7afb9e589408299fbce425af46fb
1 /*
2 Unix SMB/CIFS implementation.
4 PAC Glue between Samba and the KDC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 Copyright (C) Simo Sorce <idra@samba.org> 2010
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.
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.
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/>.
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"
32 * Given the right private pointer from hdb_samba4,
33 * get a PAC from the attached ldb messages.
35 * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
37 static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
38 struct hdb_entry_ex *client,
39 const krb5_keyblock *pk_reply_key,
40 const krb5_boolean *pac_request,
41 krb5_pac *pac)
43 TALLOC_CTX *mem_ctx;
44 DATA_BLOB *logon_blob = NULL;
45 DATA_BLOB *cred_ndr = NULL;
46 DATA_BLOB **cred_ndr_ptr = NULL;
47 DATA_BLOB _cred_blob = data_blob_null;
48 DATA_BLOB *cred_blob = NULL;
49 DATA_BLOB *upn_blob = NULL;
50 DATA_BLOB *pac_attrs_blob = NULL;
51 krb5_error_code ret;
52 NTSTATUS nt_status;
53 struct samba_kdc_entry *skdc_entry =
54 talloc_get_type_abort(client->ctx,
55 struct samba_kdc_entry);
57 mem_ctx = talloc_named(client->ctx, 0, "samba_get_pac context");
58 if (!mem_ctx) {
59 return ENOMEM;
62 if (pk_reply_key != NULL) {
63 cred_ndr_ptr = &cred_ndr;
66 nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
67 &logon_blob,
68 cred_ndr_ptr,
69 &upn_blob,
70 &pac_attrs_blob,
71 pac_request);
72 if (!NT_STATUS_IS_OK(nt_status)) {
73 talloc_free(mem_ctx);
74 return EINVAL;
77 if (pk_reply_key != NULL && cred_ndr != NULL) {
78 ret = samba_kdc_encrypt_pac_credentials(context,
79 pk_reply_key,
80 cred_ndr,
81 mem_ctx,
82 &_cred_blob);
83 if (ret != 0) {
84 talloc_free(mem_ctx);
85 return ret;
87 cred_blob = &_cred_blob;
90 ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
91 upn_blob, pac_attrs_blob,
92 NULL, pac);
94 talloc_free(mem_ctx);
95 return ret;
98 static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context,
99 struct hdb_entry_ex *client,
100 const krb5_boolean *pac_request,
101 krb5_pac *pac)
103 return samba_wdc_get_pac(priv, context, client, NULL, pac_request, pac);
106 static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
107 const krb5_principal delegated_proxy_principal,
108 struct hdb_entry_ex *client,
109 struct hdb_entry_ex *server,
110 struct hdb_entry_ex *krbtgt,
111 krb5_pac *pac,
112 krb5_cksumtype ctype)
114 struct samba_kdc_entry *server_skdc_entry =
115 talloc_get_type_abort(server->ctx,
116 struct samba_kdc_entry);
117 struct samba_kdc_entry *krbtgt_skdc_entry =
118 talloc_get_type_abort(krbtgt->ctx,
119 struct samba_kdc_entry);
120 TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry,
122 "samba_kdc_reget_pac2 context");
123 krb5_pac new_pac = NULL;
124 DATA_BLOB *pac_blob = NULL;
125 DATA_BLOB *upn_blob = NULL;
126 DATA_BLOB *deleg_blob = NULL;
127 krb5_error_code ret;
128 NTSTATUS nt_status;
129 bool is_in_db, is_untrusted;
130 size_t num_types = 0;
131 uint32_t *types = NULL;
132 uint32_t forced_next_type = 0;
133 size_t i = 0;
134 ssize_t logon_info_idx = -1;
135 ssize_t delegation_idx = -1;
136 ssize_t logon_name_idx = -1;
137 ssize_t upn_dns_info_idx = -1;
138 ssize_t srv_checksum_idx = -1;
139 ssize_t kdc_checksum_idx = -1;
140 ssize_t tkt_checksum_idx = -1;
141 ssize_t attrs_info_idx = -1;
143 if (!mem_ctx) {
144 return ENOMEM;
147 if (client != NULL) {
148 struct samba_kdc_entry *client_skdc_entry = NULL;
150 client_skdc_entry = talloc_get_type_abort(client->ctx,
151 struct samba_kdc_entry);
154 * Check the objectSID of the client and pac data are the same.
155 * Does a parse and SID check, but no crypto.
157 ret = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac);
158 if (ret != 0) {
159 talloc_free(mem_ctx);
160 return ret;
164 /* If the krbtgt was generated by an RODC, and we are not that
165 * RODC, then we need to regenerate the PAC - we can't trust
166 * it */
167 ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted);
168 if (ret != 0) {
169 talloc_free(mem_ctx);
170 return ret;
173 if (delegated_proxy_principal != NULL) {
174 krb5_enctype etype;
175 Key *key = NULL;
177 if (!is_in_db) {
179 * The RODC-issued PAC was signed by a KDC entry that we
180 * don't have a key for. The server signature is not
181 * trustworthy, since it could have been created by the
182 * server we got the ticket from. We must not proceed as
183 * otherwise the ticket signature is unchecked.
185 talloc_free(mem_ctx);
186 return HDB_ERR_NOT_FOUND_HERE;
189 /* Fetch the correct key depending on the checksum type. */
190 if (ctype == CKSUMTYPE_HMAC_MD5) {
191 etype = ENCTYPE_ARCFOUR_HMAC;
192 } else {
193 ret = krb5_cksumtype_to_enctype(context,
194 ctype,
195 &etype);
196 if (ret != 0) {
197 talloc_free(mem_ctx);
198 return ret;
201 ret = hdb_enctype2key(context, &krbtgt->entry, etype, &key);
202 if (ret != 0) {
203 return ret;
206 /* Check the KDC and ticket signatures. */
207 ret = krb5_pac_verify(context,
208 *pac,
210 NULL,
211 NULL,
212 &key->key);
213 if (ret != 0) {
214 DEBUG(1, ("PAC KDC signature failed to verify\n"));
215 talloc_free(mem_ctx);
216 return ret;
219 deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
220 if (!deleg_blob) {
221 talloc_free(mem_ctx);
222 return ENOMEM;
225 nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
226 context, *pac,
227 server->entry.principal,
228 delegated_proxy_principal,
229 deleg_blob);
230 if (!NT_STATUS_IS_OK(nt_status)) {
231 DEBUG(0, ("Building PAC failed: %s\n",
232 nt_errstr(nt_status)));
233 talloc_free(mem_ctx);
234 return EINVAL;
238 if (is_untrusted) {
239 struct samba_kdc_entry *client_skdc_entry = NULL;
241 if (client == NULL) {
242 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
245 client_skdc_entry = talloc_get_type_abort(client->ctx,
246 struct samba_kdc_entry);
248 nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
249 &pac_blob, NULL, &upn_blob,
250 NULL, NULL);
251 if (!NT_STATUS_IS_OK(nt_status)) {
252 talloc_free(mem_ctx);
253 return EINVAL;
255 } else {
256 pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
257 if (!pac_blob) {
258 talloc_free(mem_ctx);
259 return ENOMEM;
262 nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
263 krbtgt_skdc_entry->kdc_db_ctx->samdb,
264 *pac, pac_blob,
265 NULL, NULL);
266 if (!NT_STATUS_IS_OK(nt_status)) {
267 DEBUG(0, ("Building PAC failed: %s\n",
268 nt_errstr(nt_status)));
269 talloc_free(mem_ctx);
270 return EINVAL;
274 /* Check the types of the given PAC */
275 ret = krb5_pac_get_types(context, *pac, &num_types, &types);
276 if (ret != 0) {
277 talloc_free(mem_ctx);
278 return ret;
281 for (i = 0; i < num_types; i++) {
282 switch (types[i]) {
283 case PAC_TYPE_LOGON_INFO:
284 if (logon_info_idx != -1) {
285 DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
286 types[i],
287 logon_info_idx,
288 i));
289 SAFE_FREE(types);
290 talloc_free(mem_ctx);
291 return EINVAL;
293 logon_info_idx = i;
294 break;
295 case PAC_TYPE_CONSTRAINED_DELEGATION:
296 if (delegation_idx != -1) {
297 DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n",
298 types[i],
299 delegation_idx,
300 i));
301 SAFE_FREE(types);
302 talloc_free(mem_ctx);
303 return EINVAL;
305 delegation_idx = i;
306 break;
307 case PAC_TYPE_LOGON_NAME:
308 if (logon_name_idx != -1) {
309 DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n",
310 types[i],
311 logon_name_idx,
312 i));
313 SAFE_FREE(types);
314 talloc_free(mem_ctx);
315 return EINVAL;
317 logon_name_idx = i;
318 break;
319 case PAC_TYPE_UPN_DNS_INFO:
320 if (upn_dns_info_idx != -1) {
321 DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
322 types[i],
323 upn_dns_info_idx,
324 i));
325 SAFE_FREE(types);
326 talloc_free(mem_ctx);
327 return EINVAL;
329 upn_dns_info_idx = i;
330 break;
331 case PAC_TYPE_SRV_CHECKSUM:
332 if (srv_checksum_idx != -1) {
333 DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
334 types[i],
335 srv_checksum_idx,
336 i));
337 SAFE_FREE(types);
338 talloc_free(mem_ctx);
339 return EINVAL;
341 srv_checksum_idx = i;
342 break;
343 case PAC_TYPE_KDC_CHECKSUM:
344 if (kdc_checksum_idx != -1) {
345 DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
346 types[i],
347 kdc_checksum_idx,
348 i));
349 SAFE_FREE(types);
350 talloc_free(mem_ctx);
351 return EINVAL;
353 kdc_checksum_idx = i;
354 break;
355 case PAC_TYPE_TICKET_CHECKSUM:
356 if (tkt_checksum_idx != -1) {
357 DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
358 types[i],
359 tkt_checksum_idx,
360 i));
361 SAFE_FREE(types);
362 talloc_free(mem_ctx);
363 return EINVAL;
365 tkt_checksum_idx = i;
366 break;
367 case PAC_TYPE_ATTRIBUTES_INFO:
368 if (attrs_info_idx != -1) {
369 DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
370 types[i],
371 attrs_info_idx,
372 i));
373 SAFE_FREE(types);
374 talloc_free(mem_ctx);
375 return EINVAL;
377 attrs_info_idx = i;
378 break;
379 default:
380 continue;
384 if (logon_info_idx == -1) {
385 DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
386 SAFE_FREE(types);
387 talloc_free(mem_ctx);
388 return EINVAL;
390 if (logon_name_idx == -1) {
391 DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
392 SAFE_FREE(types);
393 talloc_free(mem_ctx);
394 return EINVAL;
396 if (srv_checksum_idx == -1) {
397 DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
398 SAFE_FREE(types);
399 talloc_free(mem_ctx);
400 return EINVAL;
402 if (kdc_checksum_idx == -1) {
403 DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
404 SAFE_FREE(types);
405 talloc_free(mem_ctx);
406 return EINVAL;
410 * The server account may be set not to want the PAC.
412 * While this is wasteful if the above cacluations were done
413 * and now thrown away, this is cleaner as we do any ticket
414 * signature checking etc always.
416 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
417 * time (eg not accepting a ticket from the RODC) we do not
418 * need to re-generate anything anyway.
420 if (!samba_princ_needs_pac(server_skdc_entry)) {
421 ret = 0;
422 new_pac = NULL;
423 goto out;
426 if (!server_skdc_entry->is_krbtgt) {
428 * The client may have requested no PAC when obtaining the
429 * TGT.
431 bool requested_pac;
432 ret = samba_client_requested_pac(context, pac, mem_ctx,
433 &requested_pac);
434 if (ret != 0 || !requested_pac) {
435 new_pac = NULL;
436 goto out;
440 /* Otherwise build an updated PAC */
441 ret = krb5_pac_init(context, &new_pac);
442 if (ret != 0) {
443 new_pac = NULL;
444 goto out;
447 for (i = 0;;) {
448 const uint8_t zero_byte = 0;
449 krb5_data type_data;
450 DATA_BLOB type_blob = data_blob_null;
451 uint32_t type;
453 if (forced_next_type != 0) {
455 * We need to inject possible missing types
457 type = forced_next_type;
458 forced_next_type = 0;
459 } else if (i < num_types) {
460 type = types[i];
461 i++;
462 } else {
463 break;
466 switch (type) {
467 case PAC_TYPE_LOGON_INFO:
468 type_blob = *pac_blob;
470 if (delegation_idx == -1 && deleg_blob != NULL) {
471 /* inject CONSTRAINED_DELEGATION behind */
472 forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
474 break;
475 case PAC_TYPE_CONSTRAINED_DELEGATION:
476 if (deleg_blob != NULL) {
477 type_blob = *deleg_blob;
479 break;
480 case PAC_TYPE_CREDENTIAL_INFO:
482 * Note that we copy the credential blob,
483 * as it's only usable with the PKINIT based
484 * AS-REP reply key, it's only available on the
485 * host which did the AS-REQ/AS-REP exchange.
487 * This matches Windows 2008R2...
489 break;
490 case PAC_TYPE_LOGON_NAME:
492 * this is generated in the main KDC code
493 * we just add a place holder here.
495 type_blob = data_blob_const(&zero_byte, 1);
497 if (upn_dns_info_idx == -1 && upn_blob != NULL) {
498 /* inject UPN_DNS_INFO behind */
499 forced_next_type = PAC_TYPE_UPN_DNS_INFO;
501 break;
502 case PAC_TYPE_UPN_DNS_INFO:
504 * Replace in the RODC case, otherwise
505 * upn_blob is NULL and we just copy.
507 if (upn_blob != NULL) {
508 type_blob = *upn_blob;
510 break;
511 case PAC_TYPE_SRV_CHECKSUM:
513 * this are generated in the main KDC code
514 * we just add a place holder here.
516 type_blob = data_blob_const(&zero_byte, 1);
517 break;
518 case PAC_TYPE_KDC_CHECKSUM:
520 * this are generated in the main KDC code
521 * we just add a place holders here.
523 type_blob = data_blob_const(&zero_byte, 1);
524 break;
525 case PAC_TYPE_ATTRIBUTES_INFO:
526 /* just copy... */
527 break;
528 default:
529 /* just copy... */
530 break;
533 if (type_blob.length != 0) {
534 ret = smb_krb5_copy_data_contents(&type_data,
535 type_blob.data,
536 type_blob.length);
537 if (ret != 0) {
538 SAFE_FREE(types);
539 krb5_pac_free(context, new_pac);
540 talloc_free(mem_ctx);
541 return ret;
543 } else {
544 ret = krb5_pac_get_buffer(context, *pac,
545 type, &type_data);
546 if (ret != 0) {
547 SAFE_FREE(types);
548 krb5_pac_free(context, new_pac);
549 talloc_free(mem_ctx);
550 return ret;
554 ret = krb5_pac_add_buffer(context, new_pac,
555 type, &type_data);
556 smb_krb5_free_data_contents(context, &type_data);
557 if (ret != 0) {
558 SAFE_FREE(types);
559 krb5_pac_free(context, new_pac);
560 talloc_free(mem_ctx);
561 return ret;
565 out:
567 SAFE_FREE(types);
569 /* We now replace the pac */
570 krb5_pac_free(context, *pac);
571 *pac = new_pac;
573 talloc_free(mem_ctx);
574 return ret;
577 /* Resign (and reform, including possibly new groups) a PAC */
579 static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
580 const krb5_principal client_principal,
581 const krb5_principal delegated_proxy_principal,
582 struct hdb_entry_ex *client,
583 struct hdb_entry_ex *server,
584 struct hdb_entry_ex *krbtgt,
585 krb5_pac *pac)
587 struct samba_kdc_entry *krbtgt_skdc_entry =
588 talloc_get_type_abort(krbtgt->ctx,
589 struct samba_kdc_entry);
590 krb5_error_code ret;
591 krb5_cksumtype ctype = CKSUMTYPE_NONE;
592 struct hdb_entry_ex signing_krbtgt_hdb;
594 if (delegated_proxy_principal) {
595 uint16_t rodc_id;
596 unsigned int my_krbtgt_number;
599 * We're using delegated_proxy_principal for the moment to
600 * indicate cases where the ticket was encrypted with the server
601 * key, and not a krbtgt key. This cannot be trusted, so we need
602 * to find a krbtgt key that signs the PAC in order to trust the
603 * ticket.
605 * The krbtgt passed in to this function refers to the krbtgt
606 * used to decrypt the ticket of the server requesting
607 * S4U2Proxy.
609 * When we implement service ticket renewal, we need to check
610 * the PAC, and this will need to be updated.
612 ret = krb5_pac_get_kdc_checksum_info(context,
613 *pac,
614 &ctype,
615 &rodc_id);
616 if (ret != 0) {
617 DEBUG(1, ("Failed to get PAC checksum info\n"));
618 return ret;
622 * We need to check the KDC and ticket signatures, fetching the
623 * correct key based on the enctype.
626 my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
628 if (my_krbtgt_number != 0) {
630 * If we are an RODC, and we are not the KDC that signed
631 * the evidence ticket, then we need to proxy the
632 * request.
634 if (rodc_id != my_krbtgt_number) {
635 return HDB_ERR_NOT_FOUND_HERE;
637 } else {
639 * If we are a DC, the ticket may have been signed by a
640 * different KDC than the one that issued the header
641 * ticket.
643 if (rodc_id != krbtgt->entry.kvno >> 16) {
644 struct sdb_entry_ex signing_krbtgt_sdb;
647 * If we didn't sign the ticket, then return an
648 * error.
650 if (rodc_id != 0) {
651 return KRB5KRB_AP_ERR_MODIFIED;
655 * Fetch our key from the database. To support
656 * key rollover, we're going to need to try
657 * multiple keys by trial and error. For now,
658 * krbtgt keys aren't assumed to change.
660 ret = samba_kdc_fetch(context,
661 krbtgt_skdc_entry->kdc_db_ctx,
662 krbtgt->entry.principal,
663 SDB_F_GET_KRBTGT | SDB_F_CANON,
665 &signing_krbtgt_sdb);
666 if (ret != 0) {
667 return ret;
670 ret = sdb_entry_ex_to_hdb_entry_ex(context,
671 &signing_krbtgt_sdb,
672 &signing_krbtgt_hdb);
673 sdb_free_entry(&signing_krbtgt_sdb);
674 if (ret != 0) {
675 return ret;
679 * Replace the krbtgt entry with our own entry
680 * for further processing.
682 krbtgt = &signing_krbtgt_hdb;
687 ret = samba_wdc_reget_pac2(context,
688 delegated_proxy_principal,
689 client,
690 server,
691 krbtgt,
692 pac,
693 ctype);
695 if (krbtgt == &signing_krbtgt_hdb) {
696 hdb_free_entry(context, &signing_krbtgt_hdb);
699 return ret;
702 static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
704 char *nb_name = NULL;
705 size_t len;
706 unsigned int i;
708 for (i = 0; addrs && i < addrs->len; i++) {
709 if (addrs->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
710 continue;
712 len = MIN(addrs->val[i].address.length, 15);
713 nb_name = talloc_strndup(mem_ctx,
714 addrs->val[i].address.data, len);
715 if (nb_name) {
716 break;
720 if ((nb_name == NULL) || (nb_name[0] == '\0')) {
721 return NULL;
724 /* Strip space padding */
725 for (len = strlen(nb_name) - 1;
726 (len > 0) && (nb_name[len] == ' ');
727 --len) {
728 nb_name[len] = '\0';
731 return nb_name;
734 static krb5_data fill_krb5_data(void *data, size_t length)
736 krb5_data kdata;
738 kdata.data = data;
739 kdata.length = length;
741 return kdata;
744 /* this function allocates 'data' using malloc.
745 * The caller is responsible for freeing it */
746 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
748 krb5_error_code ret = 0;
749 PA_DATA pa;
750 unsigned char *buf;
751 size_t len;
753 if (!e_data)
754 return;
756 e_data->data = NULL;
757 e_data->length = 0;
759 pa.padata_type = KRB5_PADATA_PW_SALT;
760 pa.padata_value.length = 12;
761 pa.padata_value.data = malloc(pa.padata_value.length);
762 if (!pa.padata_value.data) {
763 e_data->length = 0;
764 e_data->data = NULL;
765 return;
768 SIVAL(pa.padata_value.data, 0, NT_STATUS_V(nt_status));
769 SIVAL(pa.padata_value.data, 4, 0);
770 SIVAL(pa.padata_value.data, 8, 1);
772 ASN1_MALLOC_ENCODE(PA_DATA, buf, len, &pa, &len, ret);
773 free(pa.padata_value.data);
774 if (ret) {
775 return;
778 e_data->data = buf;
779 e_data->length = len;
781 return;
785 static krb5_error_code samba_wdc_check_client_access(void *priv,
786 krb5_context context,
787 krb5_kdc_configuration *config,
788 hdb_entry_ex *client_ex, const char *client_name,
789 hdb_entry_ex *server_ex, const char *server_name,
790 KDC_REQ *req,
791 krb5_data *e_data)
793 struct samba_kdc_entry *kdc_entry;
794 bool password_change;
795 char *workstation;
796 NTSTATUS nt_status;
798 kdc_entry = talloc_get_type(client_ex->ctx, struct samba_kdc_entry);
799 password_change = (server_ex && server_ex->entry.flags.change_pw);
800 workstation = get_netbios_name((TALLOC_CTX *)client_ex->ctx,
801 req->req_body.addresses);
803 nt_status = samba_kdc_check_client_access(kdc_entry,
804 client_name,
805 workstation,
806 password_change);
808 if (!NT_STATUS_IS_OK(nt_status)) {
809 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
810 return ENOMEM;
813 if (e_data) {
814 DATA_BLOB data;
816 samba_kdc_build_edata_reply(nt_status, &data);
817 *e_data = fill_krb5_data(data.data, data.length);
820 return samba_kdc_map_policy_err(nt_status);
823 /* Now do the standard Heimdal check */
824 return kdc_check_flags(context, config,
825 client_ex, client_name,
826 server_ex, server_name,
827 req->msg_type == krb_as_req);
830 static krb5_error_code samba_wdc_plugin_init(krb5_context context, void **ptr)
832 *ptr = NULL;
833 return 0;
836 static void samba_wdc_plugin_fini(void *ptr)
838 return;
841 struct krb5plugin_windc_ftable windc_plugin_table = {
842 .minor_version = KRB5_WINDC_PLUGIN_MINOR,
843 .init = samba_wdc_plugin_init,
844 .fini = samba_wdc_plugin_fini,
845 .pac_generate = samba_wdc_get_pac_compat,
846 .pac_verify = samba_wdc_reget_pac,
847 .client_access = samba_wdc_check_client_access,
848 .pac_pk_generate = samba_wdc_get_pac,