diff options
-rw-r--r-- | source3/libads/kerberos_verify.c | 274 |
1 files changed, 163 insertions, 111 deletions
diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index 10edd076bb..2047f0e3b9 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -1,24 +1,24 @@ -/* +/* Unix SMB/CIFS implementation. kerberos utility library Copyright (C) Andrew Tridgell 2001 Copyright (C) Remus Koos 2001 - Copyright (C) Luke Howard 2003 + Copyright (C) Luke Howard 2003 Copyright (C) Guenther Deschner 2003, 2005 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 Copyright (C) Jeremy Allison 2007 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -113,11 +113,11 @@ static bool ads_dedicated_keytab_verify_ticket(krb5_context context, return auth_ok; } -/********************************************************************************** - Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so - it's more like what microsoft does... see comment in utils/net_ads.c in the - ads_keytab_add_entry function for details. -***********************************************************************************/ +/****************************************************************************** + Try to verify a ticket using the system keytab... the system keytab has + kvno -1 entries, so it's more like what microsoft does... see comment in + utils/net_ads.c in the ads_keytab_add_entry function for details. +******************************************************************************/ static bool ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, @@ -131,12 +131,14 @@ static bool ads_keytab_verify_ticket(krb5_context context, krb5_keytab keytab = NULL; krb5_kt_cursor kt_cursor; krb5_keytab_entry kt_entry; - char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + char *valid_princ_formats[7] = { NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; char *entry_princ_s = NULL; fstring my_name, my_fqdn; int i; int number_matched_principals = 0; krb5_data packet; + int err; *pp_tkt = NULL; *keyblock = NULL; @@ -151,25 +153,39 @@ static bool ads_keytab_verify_ticket(krb5_context context, my_fqdn[0] = '\0'; name_to_fqdn(my_fqdn, global_myname()); - if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[0], + "%s$@%s", my_name, lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[1], + "host/%s@%s", my_name, lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[2], + "host/%s@%s", my_fqdn, lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[3], + "host/%s.%s@%s", my_name, lp_realm(), lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[4], + "cifs/%s@%s", my_name, lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[5], + "cifs/%s@%s", my_fqdn, lp_realm()); + if (err == -1) { goto out; } - if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { + err = asprintf(&valid_princ_formats[6], + "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()); + if (err == -1) { goto out; } @@ -178,7 +194,8 @@ static bool ads_keytab_verify_ticket(krb5_context context, ret = smb_krb5_open_keytab(context, NULL, False, &keytab); if (ret) { - DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": smb_krb5_open_keytab failed (%s)\n", + error_message(ret))); goto out; } @@ -188,15 +205,20 @@ static bool ads_keytab_verify_ticket(krb5_context context, ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); if (ret) { - DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n", + error_message(ret))); goto out; } - while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { - ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &entry_princ_s); + while (!auth_ok && + (krb5_kt_next_entry(context, keytab, + &kt_entry, &kt_cursor) == 0)) { + ret = smb_krb5_unparse_name(talloc_tos(), context, + kt_entry.principal, + &entry_princ_s); if (ret) { - DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n", - error_message(ret))); + DEBUG(1, (__location__ ": smb_krb5_unparse_name " + "failed (%s)\n", error_message(ret))); goto out; } @@ -211,32 +233,35 @@ static bool ads_keytab_verify_ticket(krb5_context context, packet.data = (char *)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, - kt_entry.principal, keytab, - NULL, pp_tkt, keyblock); + ret = krb5_rd_req_return_keyblock_from_keytab(context, + &auth_context, &packet, + kt_entry.principal, keytab, + NULL, pp_tkt, keyblock); if (ret) { - DEBUG(10,("ads_keytab_verify_ticket: " - "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n", - entry_princ_s, error_message(ret))); + DEBUG(10, (__location__ ": krb5_rd_req_return" + "_keyblock_from_keytab(%s) " + "failed: %s\n", entry_princ_s, + error_message(ret))); - /* workaround for MIT: + /* workaround for MIT: * as krb5_ktfile_get_entry will explicitly * close the krb5_keytab as soon as krb5_rd_req * has successfully decrypted the ticket but the * ticket is not valid yet (due to clockskew) * there is no point in querying more keytab * entries - Guenther */ - - if (ret == KRB5KRB_AP_ERR_TKT_NYV || + + if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { - DEBUG(3,("ads_keytab_verify_ticket: " - "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n", - entry_princ_s)); + DEBUG(3, (__location__ ": krb5_rd_req_return" + "_keyblock_from_keytab succeeded " + "for principal %s\n", + entry_princ_s)); auth_ok = True; break; } @@ -253,18 +278,20 @@ static bool ads_keytab_verify_ticket(krb5_context context, ZERO_STRUCT(kt_cursor); - out: - +out: + for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { SAFE_FREE(valid_princ_formats[i]); } - + if (!auth_ok) { if (!number_matched_principals) { - DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n")); + DEBUG(3, (__location__ ": no keytab principals " + "matched expected file service name.\n")); } else { - DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n", - number_matched_principals)); + DEBUG(3, (__location__ ": krb5_rd_req failed for " + "all %d matched keytab principals\n", + number_matched_principals)); } } @@ -273,7 +300,8 @@ static bool ads_keytab_verify_ticket(krb5_context context, { krb5_keytab_entry zero_kt_entry; ZERO_STRUCT(zero_kt_entry); - if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { + if (memcmp(&zero_kt_entry, &kt_entry, + sizeof(krb5_keytab_entry))) { smb_krb5_kt_free_entry(context, &kt_entry); } } @@ -281,7 +309,8 @@ static bool ads_keytab_verify_ticket(krb5_context context, { krb5_kt_cursor zero_csr; ZERO_STRUCT(zero_csr); - if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { + if ((memcmp(&kt_cursor, &zero_csr, + sizeof(krb5_kt_cursor)) != 0) && keytab) { krb5_kt_end_seq_get(context, keytab, &kt_cursor); } } @@ -293,9 +322,9 @@ static bool ads_keytab_verify_ticket(krb5_context context, return auth_ok; } -/********************************************************************************** +/***************************************************************************** Try to verify a ticket using the secrets.tdb. -***********************************************************************************/ +******************************************************************************/ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, @@ -311,12 +340,12 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, char *password_s = NULL; /* Let's make some room for 2 password (old and new)*/ krb5_data passwords[2]; - krb5_enctype enctypes[] = { + krb5_enctype enctypes[] = { #if defined(ENCTYPE_ARCFOUR_HMAC) ENCTYPE_ARCFOUR_HMAC, #endif - ENCTYPE_DES_CBC_CRC, - ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_CRC, + ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL }; krb5_data packet; @@ -334,9 +363,10 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, return False; } - password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + password_s = secrets_fetch_machine_password(lp_workgroup(), + NULL, NULL); if (!password_s) { - DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); + DEBUG(1,(__location__ ": failed to fetch machine password\n")); *perr = KRB5_LIBOS_CANTREADPWD; return False; } @@ -346,7 +376,7 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, password_s = secrets_fetch_prev_machine_password(lp_workgroup()); if (password_s) { - DEBUG(10,("ads_secrets_verify_ticket: found previous password\n")); + DEBUG(10, (__location__ ": found previous password\n")); passwords[1].data = password_s; passwords[1].length = strlen(password_s); } @@ -356,7 +386,8 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, packet.length = ticket->length; packet.data = (char *)ticket->data; - /* We need to setup a auth context with each possible encoding type in turn. */ + /* We need to setup a auth context with each possible encoding type + * in turn. */ for (j=0; j<2 && passwords[j].length; j++) { for (i=0;enctypes[i];i++) { @@ -367,18 +398,22 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, goto out; } - if (create_kerberos_key_from_string(context, host_princ, &passwords[j], key, enctypes[i], false)) { + if (create_kerberos_key_from_string(context, + host_princ, &passwords[j], + key, enctypes[i], false)) { SAFE_FREE(key); continue; } - krb5_auth_con_setuseruserkey(context, auth_context, key); + krb5_auth_con_setuseruserkey(context, + auth_context, key); - if (!(ret = krb5_rd_req(context, &auth_context, &packet, - NULL, - NULL, NULL, pp_tkt))) { - DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", - (unsigned int)enctypes[i] )); + if (!(ret = krb5_rd_req(context, &auth_context, + &packet, NULL, NULL, + NULL, pp_tkt))) { + DEBUG(10, (__location__ ": enc type [%u] " + "decrypted message !\n", + (unsigned int)enctypes[i])); auth_ok = True; cont = false; krb5_copy_keyblock(context, key, keyblock); @@ -387,10 +422,13 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, } DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, - ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", - (unsigned int)enctypes[i], error_message(ret))); + (__location__ ": enc type [%u] failed to " + "decrypt with error %s\n", + (unsigned int)enctypes[i], + error_message(ret))); - /* successfully decrypted but ticket is just not valid at the moment */ + /* successfully decrypted but ticket is just not + * valid at the moment */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { @@ -416,10 +454,10 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context, return auth_ok; } -/********************************************************************************** - Verify an incoming ticket and parse out the principal name and +/***************************************************************************** + Verify an incoming ticket and parse out the principal name and authorization_data if available. -***********************************************************************************/ +******************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const char *realm, @@ -442,7 +480,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_keyblock *keyblock = NULL; time_t authtime; krb5_error_code ret = 0; - int flags = 0; + int flags = 0; krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; @@ -461,7 +499,8 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_init_context failed (%s)\n", + error_message(ret))); return NT_STATUS_LOGON_FAILURE; } @@ -471,7 +510,8 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, ret = krb5_set_default_realm(context, realm); if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_set_default_realm " + "failed (%s)\n", error_message(ret))); goto out; } @@ -481,7 +521,8 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, ret = krb5_auth_con_init(context, &auth_context); if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_auth_con_init failed (%s)\n", + error_message(ret))); goto out; } @@ -499,43 +540,44 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { - DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n", - host_princ_s, error_message(ret))); + DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) " + "failed (%s)\n", host_princ_s, error_message(ret))); goto out; } - if ( use_replay_cache ) { - - /* Lock a mutex surrounding the replay as there is no - locking in the MIT krb5 code surrounding the replay + if (use_replay_cache) { + + /* Lock a mutex surrounding the replay as there is no + locking in the MIT krb5 code surrounding the replay cache... */ - mutex = grab_named_mutex(talloc_tos(), "replay cache mutex", - 10); + mutex = grab_named_mutex(talloc_tos(), + "replay cache mutex", 10); if (mutex == NULL) { - DEBUG(1,("ads_verify_ticket: unable to protect " - "replay cache with mutex.\n")); + DEBUG(1, (__location__ ": unable to protect replay " + "cache with mutex.\n")); ret = KRB5_CC_IO; goto out; } - /* JRA. We must set the rcache here. This will prevent + /* JRA. We must set the rcache here. This will prevent replay attacks. */ - - ret = krb5_get_server_rcache(context, - krb5_princ_component(context, host_princ, 0), - &rcache); + + ret = krb5_get_server_rcache( + context, + krb5_princ_component(context, host_princ, 0), + &rcache); if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache " - "failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_get_server_rcache " + "failed (%s)\n", error_message(ret))); goto out; } ret = krb5_auth_con_setrcache(context, auth_context, rcache); if (ret) { - DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache " - "failed (%s)\n", error_message(ret))); + DEBUG(1, (__location__ ": krb5_auth_con_setrcache " + "failed (%s)\n", error_message(ret))); goto out; } } @@ -574,7 +616,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, break; } - if ( use_replay_cache ) { + if (use_replay_cache) { TALLOC_FREE(mutex); #if 0 /* Heimdal leaks here, if we fix the leak, MIT crashes */ @@ -582,30 +624,31 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_rc_close(context, rcache); } #endif - } + } if (!auth_ok) { - DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", - error_message(ret))); + DEBUG(3, (__location__ ": krb5_rd_req with auth " + "failed (%s)\n", error_message(ret))); /* Try map the error return in case it's something like * a clock skew error. */ sret = krb5_to_nt_status(ret); - if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { + if (NT_STATUS_IS_OK(sret) || + NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { sret = NT_STATUS_LOGON_FAILURE; } - DEBUG(10,("ads_verify_ticket: returning error %s\n", - nt_errstr(sret) )); + DEBUG(10, (__location__ ": returning error %s\n", + nt_errstr(sret) )); goto out; - } - + } + authtime = get_authtime_from_tkt(tkt); client_principal = get_principal_from_tkt(tkt); ret = krb5_mk_rep(context, auth_context, &packet); if (ret) { - DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", - error_message(ret))); + DEBUG(3, (__location__ ": Failed to generate mutual " + "authentication reply (%s)\n", error_message(ret))); goto out; } @@ -617,30 +660,35 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, get_krb5_smb_session_key(mem_ctx, context, auth_context, session_key, true); - dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); + dump_data_pw("SMB session key (from ticket)\n", + session_key->data, session_key->length); #if 0 file_save("/tmp/ticket.dat", ticket->data, ticket->length); #endif - /* continue when no PAC is retrieved or we couldn't decode the PAC + /* continue when no PAC is retrieved or we couldn't decode the PAC (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or Kerberos tickets encrypted using a DES key) - Guenther */ got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); if (!got_auth_data) { - DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); + DEBUG(3, (__location__ ": did not retrieve auth data. " + "continuing without PAC\n")); } if (got_auth_data) { struct PAC_DATA *pac_data; - pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, &pac_data); + pac_ret = decode_pac_data(mem_ctx, &auth_data, context, + keyblock, client_principal, + authtime, &pac_data); data_blob_free(&auth_data); if (!NT_STATUS_IS_OK(pac_ret)) { - DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret))); + DEBUG(3, (__location__ ": failed to decode " + "PAC_DATA: %s\n", nt_errstr(pac_ret))); } else { uint32_t i; - for (i=0; i < pac_data->num_buffers; i++) { + for (i = 0; i < pac_data->num_buffers; i++) { if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) { continue; @@ -650,7 +698,9 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } if (!*logon_info) { - DEBUG(1,("correctly decoded PAC but found no logon_info! This should not happen\n")); + DEBUG(1, ("correctly decoded PAC but found " + "no logon_info! " + "This should not happen\n")); return NT_STATUS_INVALID_USER_BUFFER; } } @@ -674,16 +724,18 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, #endif #endif - if ((ret = smb_krb5_unparse_name(mem_ctx, context, client_principal, principal))) { - DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", - error_message(ret))); + ret = smb_krb5_unparse_name(mem_ctx, context, + client_principal, principal); + if (ret) { + DEBUG(3, (__location__ ": smb_krb5_unparse_name " + "failed (%s)\n", error_message(ret))); sret = NT_STATUS_LOGON_FAILURE; goto out; } sret = NT_STATUS_OK; - out: +out: TALLOC_FREE(mutex); |