s4-libnet: Improve debugging of libnet_BecomeDC LDAP errors
[ambi/samba-autobuild/.git] / source4 / kdc / pac-glue.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 "../libds/common/flags.h"
26 #include <ldb.h>
27 #include "auth/auth.h"
28 #include "auth/auth_sam_reply.h"
29 #include "kdc/kdc-glue.h"
30 #include "kdc/pac-glue.h"
31 #include "param/param.h"
32 #include "librpc/gen_ndr/ndr_krb5pac.h"
33 #include "libcli/security/security.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "auth/kerberos/pac_utils.h"
36
37 static
38 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
39                                        struct auth_user_info_dc *info,
40                                        DATA_BLOB *pac_data)
41 {
42         struct netr_SamInfo3 *info3;
43         union PAC_INFO pac_info;
44         enum ndr_err_code ndr_err;
45         NTSTATUS nt_status;
46
47         ZERO_STRUCT(pac_info);
48
49         nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
50         if (!NT_STATUS_IS_OK(nt_status)) {
51                 DEBUG(1, ("Getting Samba info failed: %s\n",
52                           nt_errstr(nt_status)));
53                 return nt_status;
54         }
55
56         pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
57         if (!pac_info.logon_info.info) {
58                 return NT_STATUS_NO_MEMORY;
59         }
60
61         pac_info.logon_info.info->info3 = *info3;
62
63         ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
64                                       PAC_TYPE_LOGON_INFO,
65                                       (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
66         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
67                 nt_status = ndr_map_error2ntstatus(ndr_err);
68                 DEBUG(1, ("PAC (presig) push failed: %s\n",
69                           nt_errstr(nt_status)));
70                 return nt_status;
71         }
72
73         return NT_STATUS_OK;
74 }
75
76 krb5_error_code samba_make_krb5_pac(krb5_context context,
77                                     DATA_BLOB *pac_blob,
78                                     DATA_BLOB *deleg_blob,
79                                     krb5_pac *pac)
80 {
81         krb5_data pac_data;
82         krb5_data deleg_data;
83         krb5_error_code ret;
84
85         /* The user account may be set not to want the PAC */
86         if (!pac_blob) {
87                 return 0;
88         }
89
90         ret = krb5_data_copy(&pac_data, pac_blob->data, pac_blob->length);
91         if (ret != 0) {
92                 return ret;
93         }
94
95         ZERO_STRUCT(deleg_data);
96         if (deleg_blob) {
97                 ret = krb5_data_copy(&deleg_data,
98                                      deleg_blob->data,
99                                      deleg_blob->length);
100                 if (ret != 0) {
101                         krb5_data_free(&pac_data);
102                         return ret;
103                 }
104         }
105
106         ret = krb5_pac_init(context, pac);
107         if (ret != 0) {
108                 krb5_data_free(&pac_data);
109                 krb5_data_free(&deleg_data);
110                 return ret;
111         }
112
113         ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &pac_data);
114         krb5_data_free(&pac_data);
115         if (ret != 0) {
116                 krb5_data_free(&deleg_data);
117                 return ret;
118         }
119
120         if (deleg_blob) {
121                 ret = krb5_pac_add_buffer(context, *pac,
122                                           PAC_TYPE_CONSTRAINED_DELEGATION,
123                                           &deleg_data);
124                 krb5_data_free(&deleg_data);
125                 if (ret != 0) {
126                         return ret;
127                 }
128         }
129
130         return ret;
131 }
132
133 bool samba_princ_needs_pac(struct hdb_entry_ex *princ)
134 {
135
136         struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry);
137         uint32_t userAccountControl;
138
139
140         /* The service account may be set not to want the PAC */
141         userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0);
142         if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
143                 return false;
144         }
145
146         return true;
147 }
148
149 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
150 int samba_krbtgt_is_in_db(struct hdb_entry_ex *princ, bool *is_in_db, bool *is_untrusted)
151 {
152         NTSTATUS status;
153         struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry);
154         int rodc_krbtgt_number, trust_direction;
155         uint32_t rid;
156
157         TALLOC_CTX *mem_ctx = talloc_new(NULL);
158         if (!mem_ctx) {
159                 return ENOMEM;
160         }
161         
162         trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
163
164         if (trust_direction != 0) {
165                 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
166                    
167                    This is exactly where we should flag for SID
168                    validation when we do inter-foreest trusts
169                  */
170                 talloc_free(mem_ctx);
171                 *is_untrusted = false;
172                 *is_in_db = false;
173                 return 0;
174         }
175
176         /* The lack of password controls etc applies to krbtgt by
177          * virtue of being that particular RID */
178         status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
179
180         if (!NT_STATUS_IS_OK(status)) {
181                 talloc_free(mem_ctx);
182                 return EINVAL;
183         }
184
185         rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
186
187         if (p->kdc_db_ctx->my_krbtgt_number == 0) {
188                 if (rid == DOMAIN_RID_KRBTGT) {
189                         *is_untrusted = false;
190                         *is_in_db = true;
191                         talloc_free(mem_ctx);
192                         return 0;
193                 } else if (rodc_krbtgt_number != -1) {
194                         *is_in_db = true;
195                         *is_untrusted = true;
196                         talloc_free(mem_ctx);
197                         return 0;
198                 }
199         } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
200                 talloc_free(mem_ctx);
201                 *is_untrusted = false;
202                 *is_in_db = true;
203                 return 0;
204         } else if (rid == DOMAIN_RID_KRBTGT) {
205                 /* krbtgt viewed from an RODC */
206                 talloc_free(mem_ctx);
207                 *is_untrusted = false;
208                 *is_in_db = false;
209                 return 0;
210         }
211
212         /* Another RODC */
213         talloc_free(mem_ctx);
214         *is_untrusted = true;
215         *is_in_db = false;
216         return 0;
217 }
218
219 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
220                                 struct hdb_entry_ex *client,
221                                 DATA_BLOB **_pac_blob)
222 {
223         struct samba_kdc_entry *p = talloc_get_type(client->ctx, struct samba_kdc_entry);
224         struct auth_user_info_dc *user_info_dc;
225         DATA_BLOB *pac_blob;
226         NTSTATUS nt_status;
227
228         /* The user account may be set not to want the PAC */
229         if ( ! samba_princ_needs_pac(client)) {
230                 *_pac_blob = NULL;
231                 return NT_STATUS_OK;
232         }
233
234         pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
235         if (!pac_blob) {
236                 return NT_STATUS_NO_MEMORY;
237         }
238
239         nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb,
240                                              lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx),
241                                              lpcfg_sam_name(p->kdc_db_ctx->lp_ctx),
242                                              p->realm_dn,
243                                              p->msg,
244                                              data_blob(NULL, 0),
245                                              data_blob(NULL, 0),
246                                              &user_info_dc);
247         if (!NT_STATUS_IS_OK(nt_status)) {
248                 DEBUG(0, ("Getting user info for PAC failed: %s\n",
249                           nt_errstr(nt_status)));
250                 return nt_status;
251         }
252
253         nt_status = samba_get_logon_info_pac_blob(mem_ctx, user_info_dc, pac_blob);
254         if (!NT_STATUS_IS_OK(nt_status)) {
255                 DEBUG(0, ("Building PAC failed: %s\n",
256                           nt_errstr(nt_status)));
257                 return nt_status;
258         }
259
260         *_pac_blob = pac_blob;
261         return NT_STATUS_OK;
262 }
263
264 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
265                                    krb5_context context,
266                                    const krb5_pac pac, DATA_BLOB *pac_blob,
267                                    struct PAC_SIGNATURE_DATA *pac_srv_sig,
268                                    struct PAC_SIGNATURE_DATA *pac_kdc_sig)
269 {
270         struct auth_user_info_dc *user_info_dc;
271         krb5_error_code ret;
272         NTSTATUS nt_status;
273
274         ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
275                                            context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
276         if (ret) {
277                 return NT_STATUS_UNSUCCESSFUL;
278         }
279
280         nt_status = samba_get_logon_info_pac_blob(mem_ctx, 
281                                                   user_info_dc, pac_blob);
282
283         return nt_status;
284 }
285
286 NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
287                                 krb5_context context,
288                                 const krb5_pac pac,
289                                 const krb5_principal server_principal,
290                                 const krb5_principal proxy_principal,
291                                 DATA_BLOB *new_blob)
292 {
293         krb5_data old_data;
294         DATA_BLOB old_blob;
295         krb5_error_code ret;
296         NTSTATUS nt_status;
297         enum ndr_err_code ndr_err;
298         union PAC_INFO info;
299         struct PAC_CONSTRAINED_DELEGATION _d;
300         struct PAC_CONSTRAINED_DELEGATION *d = NULL;
301         char *server = NULL;
302         char *proxy = NULL;
303         uint32_t i;
304         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
305
306         if (tmp_ctx == NULL) {
307                 return NT_STATUS_NO_MEMORY;
308         }
309
310         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
311         if (ret == ENOENT) {
312                 ZERO_STRUCT(old_data);
313         } else if (ret) {
314                 talloc_free(tmp_ctx);
315                 return NT_STATUS_UNSUCCESSFUL;
316         }
317
318         old_blob.length = old_data.length;
319         old_blob.data = (uint8_t *)old_data.data;
320
321         ZERO_STRUCT(info);
322         if (old_blob.length > 0) {
323                 ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
324                                 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
325                                 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
326                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
327                         krb5_data_free(&old_data);
328                         nt_status = ndr_map_error2ntstatus(ndr_err);
329                         DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
330                         talloc_free(tmp_ctx);
331                         return nt_status;
332                 }
333         } else {
334                 ZERO_STRUCT(_d);
335                 info.constrained_delegation.info = &_d;
336         }
337         krb5_data_free(&old_data);
338
339         ret = krb5_unparse_name(context, server_principal, &server);
340         if (ret) {
341                 talloc_free(tmp_ctx);
342                 return NT_STATUS_INTERNAL_ERROR;
343         }
344
345         ret = krb5_unparse_name_flags(context, proxy_principal,
346                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &proxy);
347         if (ret) {
348                 SAFE_FREE(server);
349                 talloc_free(tmp_ctx);
350                 return NT_STATUS_INTERNAL_ERROR;
351         }
352
353         d = info.constrained_delegation.info;
354         i = d->num_transited_services;
355         d->proxy_target.string = server;
356         d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
357                                                struct lsa_String, i + 1);
358         d->transited_services[i].string = proxy;
359         d->num_transited_services = i + 1;
360
361         ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
362                                 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
363                                 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
364         SAFE_FREE(server);
365         SAFE_FREE(proxy);
366         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
367                 krb5_data_free(&old_data);
368                 nt_status = ndr_map_error2ntstatus(ndr_err);
369                 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
370                 talloc_free(tmp_ctx);
371                 return nt_status;
372         }
373
374         talloc_free(tmp_ctx);
375         return NT_STATUS_OK;
376 }
377
378 /* this function allocates 'data' using malloc.
379  * The caller is responsible for freeing it */
380 void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
381 {
382         PA_DATA pa;
383         unsigned char *buf;
384         size_t len;
385         krb5_error_code ret = 0;
386
387         if (!e_data)
388                 return;
389
390         pa.padata_type          = KRB5_PADATA_PW_SALT;
391         pa.padata_value.length  = 12;
392         pa.padata_value.data    = malloc(pa.padata_value.length);
393         if (!pa.padata_value.data) {
394                 e_data->length = 0;
395                 e_data->data = NULL;
396                 return;
397         }
398
399         SIVAL(pa.padata_value.data, 0, NT_STATUS_V(nt_status));
400         SIVAL(pa.padata_value.data, 4, 0);
401         SIVAL(pa.padata_value.data, 8, 1);
402
403         ASN1_MALLOC_ENCODE(PA_DATA, buf, len, &pa, &len, ret);
404         free(pa.padata_value.data);
405
406         e_data->data   = buf;
407         e_data->length = len;
408
409         return;
410 }
411
412 /* function to map policy errors */
413 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
414 {
415         krb5_error_code ret;
416
417         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
418                 ret = KRB5KDC_ERR_KEY_EXPIRED;
419         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
420                 ret = KRB5KDC_ERR_KEY_EXPIRED;
421         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
422                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
423         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
424                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
425         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
426                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
427         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
428                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
429         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
430                 ret = KRB5KDC_ERR_POLICY;
431         else
432                 ret = KRB5KDC_ERR_POLICY;
433
434         return ret;
435 }
436
437 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
438  * for consistency */
439 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
440                                        const char *client_name,
441                                        const char *workstation,
442                                        bool password_change)
443 {
444         TALLOC_CTX *tmp_ctx;
445         NTSTATUS nt_status;
446
447         tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
448         if (!tmp_ctx) {
449                 return NT_STATUS_NO_MEMORY;
450         }
451
452         /* we allow all kinds of trusts here */
453         nt_status = authsam_account_ok(tmp_ctx,
454                                        kdc_entry->kdc_db_ctx->samdb,
455                                        MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
456                                        MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
457                                        kdc_entry->realm_dn, kdc_entry->msg,
458                                        workstation, client_name,
459                                        true, password_change);
460
461         talloc_free(tmp_ctx);
462         return nt_status;
463 }
464
465 int kdc_check_pac(krb5_context context,
466                   DATA_BLOB srv_sig,
467                   struct PAC_SIGNATURE_DATA *kdc_sig,
468                   hdb_entry_ex *ent)
469 {
470         krb5_enctype etype;
471         int ret;
472         krb5_keyblock keyblock;
473         Key *key;
474         if (kdc_sig->type == CKSUMTYPE_HMAC_MD5) {
475                 etype = ETYPE_ARCFOUR_HMAC_MD5;
476         } else {
477                 ret = krb5_cksumtype_to_enctype(context, 
478                                                 kdc_sig->type,
479                                                 &etype);
480                 if (ret != 0) {
481                         return ret;
482                 }
483         }
484
485 #if HDB_ENCTYPE2KEY_TAKES_KEYSET
486         ret = hdb_enctype2key(context, &ent->entry, NULL, etype, &key);
487 #else
488         ret = hdb_enctype2key(context, &ent->entry, etype, &key);
489 #endif
490
491         if (ret != 0) {
492                 return ret;
493         }
494
495         keyblock = key->key;
496
497         return check_pac_checksum(srv_sig, kdc_sig,
498                                  context, &keyblock);
499 }
500
501
502