diff options
Diffstat (limited to 'source/libads')
-rw-r--r-- | source/libads/cldap.c | 9 | ||||
-rw-r--r-- | source/libads/kerberos_keytab.c | 30 | ||||
-rw-r--r-- | source/libads/kerberos_verify.c | 103 | ||||
-rw-r--r-- | source/libads/krb5_errs.c | 2 | ||||
-rw-r--r-- | source/libads/ldap.c | 11 | ||||
-rw-r--r-- | source/libads/ldap_user.c | 12 | ||||
-rw-r--r-- | source/libads/sasl.c | 32 | ||||
-rw-r--r-- | source/libads/smb_krb5_locator.c | 386 |
8 files changed, 526 insertions, 59 deletions
diff --git a/source/libads/cldap.c b/source/libads/cldap.c index 72018c620d8..3cb98c59c58 100644 --- a/source/libads/cldap.c +++ b/source/libads/cldap.c @@ -187,8 +187,10 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) { int ret; ASN1_DATA data; - DATA_BLOB blob; - DATA_BLOB os1, os2, os3; + DATA_BLOB blob = data_blob(NULL, 0); + DATA_BLOB os1 = data_blob(NULL, 0); + DATA_BLOB os2 = data_blob(NULL, 0); + DATA_BLOB os3 = data_blob(NULL, 0); int i1; /* half the time of a regular ldap timeout, not less than 3 seconds. */ unsigned int al_secs = MAX(3,lp_ldap_timeout()/2); @@ -238,6 +240,9 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) if (data.has_error) { data_blob_free(&blob); + data_blob_free(&os1); + data_blob_free(&os2); + data_blob_free(&os3); asn1_free(&data); DEBUG(1,("Failed to parse cldap reply\n")); return -1; diff --git a/source/libads/kerberos_keytab.c b/source/libads/kerberos_keytab.c index ba1a9165674..0ad225fbebb 100644 --- a/source/libads/kerberos_keytab.c +++ b/source/libads/kerberos_keytab.c @@ -55,20 +55,20 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = smb_krb5_parse_name(context, princ_s, &princ); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); goto out; } /* Seek and delete old keytab entries */ ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret != KRB5_KT_END && ret != ENOENT ) { - DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n")); + DEBUG(3,("smb_krb5_kt_add_entry: Will try to delete old keytab entries\n")); while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { BOOL compare_name_ok = False; ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_unparse_name failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } @@ -89,7 +89,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, #endif if (!compare_name_ok) { - DEBUG(10,("ads_keytab_add_entry: ignoring keytab entry principal %s, kvno = %d\n", + DEBUG(10,("smb_krb5_kt_add_entry: ignoring keytab entry principal %s, kvno = %d\n", ktprinc, kt_entry.vno)); } @@ -97,39 +97,39 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, if (compare_name_ok) { if (kt_entry.vno == kvno - 1) { - DEBUG(5,("ads_keytab_add_entry: Saving previous (kvno %d) entry for principal: %s.\n", + DEBUG(5,("smb_krb5_kt_add_entry: Saving previous (kvno %d) entry for principal: %s.\n", kvno - 1, princ_s)); } else { - DEBUG(5,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", + DEBUG(5,("smb_krb5_kt_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", princ_s, kt_entry.vno)); ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get() failed (%s)\n", error_message(ret))); goto out; } ret = krb5_kt_remove_entry(context, keytab, &kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } - DEBUG(5,("ads_keytab_add_entry: removed old entry for principal: %s (kvno %d).\n", + DEBUG(5,("smb_krb5_kt_add_entry: removed old entry for principal: %s (kvno %d).\n", princ_s, kt_entry.vno)); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_start_seq failed (%s)\n", error_message(ret))); goto out; } ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } @@ -141,7 +141,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); goto out; } } @@ -149,7 +149,7 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { - DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); goto out; } } @@ -180,13 +180,13 @@ static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab, kt_entry.principal = princ; kt_entry.vno = kvno; - DEBUG(3,("ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", + DEBUG(3,("smb_krb5_kt_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", princ_s, enctypes[i], kt_entry.vno)); ret = krb5_kt_add_entry(context, keytab, &kt_entry); krb5_free_keyblock_contents(context, keyp); ZERO_STRUCT(kt_entry); if (ret) { - DEBUG(1,("ads_keytab_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); + DEBUG(1,("smb_krb5_kt_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); goto out; } } diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c index 2c114b1240e..0ec03ef4bf2 100644 --- a/source/libads/kerberos_verify.c +++ b/source/libads/kerberos_verify.c @@ -7,6 +7,7 @@ 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 @@ -37,9 +38,12 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); ads_keytab_add_entry function for details. ***********************************************************************************/ -static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static BOOL ads_keytab_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; @@ -51,6 +55,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut fstring my_name, my_fqdn; int i; int number_matched_principals = 0; + krb5_data packet; + + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file @@ -103,11 +112,11 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut } number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, p_packet, + ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry.principal, keytab, NULL, pp_tkt, keyblock); @@ -125,7 +134,8 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut * entries - Guenther */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED) { + ret == KRB5KRB_AP_ERR_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { @@ -184,6 +194,7 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut if (keytab) { krb5_kt_close(context, keytab); } + *perr = ret; return auth_ok; } @@ -191,32 +202,40 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut Try to verify a ticket using the secrets.tdb. ***********************************************************************************/ -static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, - krb5_principal host_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) +static krb5_error_code ads_secrets_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + krb5_principal host_princ, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) { krb5_error_code ret = 0; BOOL auth_ok = False; char *password_s = NULL; krb5_data password; krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 }; + krb5_data packet; int i; + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; + #if defined(ENCTYPE_ARCFOUR_HMAC) enctypes[2] = ENCTYPE_ARCFOUR_HMAC; #endif - ZERO_STRUCTP(keyblock); - if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); + *perr = KRB5_CONFIG_CANTOPEN; return False; } 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")); + *perr = KRB5_LIBOS_CANTREADPWD; return False; } @@ -225,14 +244,15 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - p_packet->length = ticket->length; - p_packet->data = (char *)ticket->data; + packet.length = ticket->length; + packet.data = (char *)ticket->data; /* We need to setup a auth context with each possible encoding type in turn. */ for (i=0;enctypes[i];i++) { krb5_keyblock *key = NULL; if (!(key = SMB_MALLOC_P(krb5_keyblock))) { + ret = ENOMEM; goto out; } @@ -243,7 +263,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au krb5_auth_con_setuseruserkey(context, auth_context, key); - if (!(ret = krb5_rd_req(context, &auth_context, p_packet, + 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", @@ -260,7 +280,8 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au /* 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_TKT_EXPIRED || + ret == KRB5KRB_AP_ERR_SKEW) { break; } @@ -270,7 +291,7 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au out: SAFE_FREE(password_s); - + *perr = ret; return auth_ok; } @@ -280,9 +301,11 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au ***********************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, - const char *realm, time_t time_offset, - const DATA_BLOB *ticket, - char **principal, PAC_DATA **pac_data, + const char *realm, + time_t time_offset, + const DATA_BLOB *ticket, + char **principal, + PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key) { @@ -296,20 +319,22 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; - int ret; - + krb5_error_code ret = 0; + krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; - BOOL got_replay_mutex = False; - BOOL auth_ok = False; + BOOL got_replay_mutex = False; BOOL got_auth_data = False; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); - ZERO_STRUCTP(ap_rep); - ZERO_STRUCTP(session_key); + + *principal = NULL; + *pac_data = NULL; + *ap_rep = data_blob(NULL,0); + *session_key = data_blob(NULL,0); initialize_krb5_error_table(); ret = krb5_init_context(&context); @@ -339,6 +364,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } asprintf(&host_princ_s, "%s$", global_myname()); + if (!host_princ_s) { + goto out; + } + strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { @@ -353,6 +382,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!grab_server_mutex("replay cache mutex")) { DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); + ret = KRB5_CC_IO; goto out; } @@ -375,11 +405,11 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } if (lp_use_kerberos_keytab()) { - auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt, &keyblock); + auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if (!auth_ok) { auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, - ticket, &packet, &tkt, &keyblock); + ticket, &tkt, &keyblock, &ret); } release_server_mutex(); @@ -395,6 +425,15 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, if (!auth_ok) { DEBUG(3,("ads_verify_ticket: 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)) { + sret = NT_STATUS_LOGON_FAILURE; + } + DEBUG(10,("ads_verify_ticket: returning error %s\n", + nt_errstr(sret) )); goto out; } @@ -409,8 +448,10 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } *ap_rep = data_blob(packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; + if (packet.data) { + kerberos_free_data_contents(context, &packet); + ZERO_STRUCT(packet); + } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); diff --git a/source/libads/krb5_errs.c b/source/libads/krb5_errs.c index 89cfc2d1439..c153bee96e6 100644 --- a/source/libads/krb5_errs.c +++ b/source/libads/krb5_errs.c @@ -59,6 +59,8 @@ static const struct { {KRB5_CC_NOTFOUND, NT_STATUS_NO_SUCH_FILE}, {KRB5_FCC_NOFILE, NT_STATUS_NO_SUCH_FILE}, {KRB5KDC_ERR_NONE, NT_STATUS_OK}, + {KRB5_RC_MALLOC, NT_STATUS_NO_MEMORY}, + {ENOMEM, NT_STATUS_NO_MEMORY}, {0, NT_STATUS_OK} }; diff --git a/source/libads/ldap.c b/source/libads/ldap.c index dfc68fdc2b1..1d08a01a263 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -1635,6 +1635,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, char *samAccountName, *controlstr; TALLOC_CTX *ctx; ADS_MODLIST mods; + char *machine_escaped = NULL; char *new_dn; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", "computer", NULL}; @@ -1647,8 +1648,13 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, return ADS_ERROR(LDAP_NO_MEMORY); ret = ADS_ERROR(LDAP_NO_MEMORY); - - new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_name, org_unit); + + machine_escaped = escape_rdn_val_string_alloc(machine_name); + if (!machine_escaped) { + goto done; + } + + new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit); samAccountName = talloc_asprintf(ctx, "%s$", machine_name); if ( !new_dn || !samAccountName ) { @@ -1675,6 +1681,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, ret = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(machine_escaped); ads_msgfree(ads, res); talloc_destroy(ctx); diff --git a/source/libads/ldap_user.c b/source/libads/ldap_user.c index 66d94d29d3a..afbbc0b421a 100644 --- a/source/libads/ldap_user.c +++ b/source/libads/ldap_user.c @@ -50,6 +50,7 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, ADS_MODLIST mods; ADS_STATUS status; const char *upn, *new_dn, *name, *controlstr; + char *name_escaped = NULL; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", NULL}; @@ -63,7 +64,9 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm))) goto done; - if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name, container, + if (!(name_escaped = escape_rdn_val_string_alloc(name))) + goto done; + if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container, ads->config.bind_path))) goto done; if (!(controlstr = talloc_asprintf(ctx, "%u", (UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE)))) @@ -81,6 +84,7 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, status = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(name_escaped); talloc_destroy(ctx); return status; } @@ -92,6 +96,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, ADS_MODLIST mods; ADS_STATUS status; char *new_dn; + char *name_escaped = NULL; const char *objectClass[] = {"top", "group", NULL}; if (!(ctx = talloc_init("ads_add_group_acct"))) @@ -99,7 +104,9 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, status = ADS_ERROR(LDAP_NO_MEMORY); - if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", group, container, + if (!(name_escaped = escape_rdn_val_string_alloc(group))) + goto done; + if (!(new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", name_escaped, container, ads->config.bind_path))) goto done; if (!(mods = ads_init_mods(ctx))) @@ -114,6 +121,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, status = ads_gen_add(ads, new_dn, mods); done: + SAFE_FREE(name_escaped); talloc_destroy(ctx); return status; } diff --git a/source/libads/sasl.c b/source/libads/sasl.c index 812f3961f19..013985a1215 100644 --- a/source/libads/sasl.c +++ b/source/libads/sasl.c @@ -311,9 +311,9 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) int gss_rc, rc; uint8 *p; uint32 max_msg_size = 0; - char *sname; + char *sname = NULL; ADS_STATUS status; - krb5_principal principal; + krb5_principal principal = NULL; krb5_context ctx = NULL; krb5_enctype enc_types[] = { #ifdef ENCTYPE_ARCFOUR_HMAC @@ -331,25 +331,40 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) initialize_krb5_error_table(); status = ADS_ERROR_KRB5(krb5_init_context(&ctx)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); return status; } status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); + krb5_free_context(ctx); return status; } status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal)); if (!ADS_ERR_OK(status)) { + SAFE_FREE(sname); + krb5_free_context(ctx); return status; } - free(sname); - krb5_free_context(ctx); - input_name.value = &principal; input_name.length = sizeof(principal); gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name); + + /* + * The MIT libraries have a *HORRIBLE* bug - input_value.value needs + * to point to the *address* of the krb5_principal, and the gss libraries + * to a shallow copy of the krb5_principal pointer - so we need to keep + * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* ! + * Just one more way in which MIT engineers screwed me over.... JRA. + */ + + SAFE_FREE(sname); + if (gss_rc) { + krb5_free_principal(ctx, principal); + krb5_free_context(ctx); return ADS_ERROR_GSS(gss_rc, minor_status); } @@ -407,8 +422,6 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) if (gss_rc == 0) break; } - gss_release_name(&minor_status, &serv_name); - gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token, (int *)&conf_state,NULL); if (gss_rc) { @@ -463,6 +476,11 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) gss_release_buffer(&minor_status, &input_token); failed: + + gss_release_name(&minor_status, &serv_name); + krb5_free_principal(ctx, principal); + krb5_free_context(ctx); + if(scred) ber_bvfree(scred); return status; diff --git a/source/libads/smb_krb5_locator.c b/source/libads/smb_krb5_locator.c new file mode 100644 index 00000000000..be14a126974 --- /dev/null +++ b/source/libads/smb_krb5_locator.c @@ -0,0 +1,386 @@ +/* + Unix SMB/CIFS implementation. + kerberos locator plugin + Copyright (C) Guenther Deschner 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H) + +#include <krb5/locate_plugin.h> + +static const char *get_service_from_locate_service_type(enum locate_service_type svc) +{ + switch (svc) { + case locate_service_kdc: + case locate_service_master_kdc: + return "88"; + case locate_service_kadmin: + case locate_service_krb524: + /* not supported */ + return NULL; + case locate_service_kpasswd: + return "464"; + default: + break; + } + return NULL; + +} + +static const char *locate_service_type_name(enum locate_service_type svc) +{ + switch (svc) { + case locate_service_kdc: + return "locate_service_kdc"; + case locate_service_master_kdc: + return "locate_service_master_kdc"; + case locate_service_kadmin: + return "locate_service_kadmin"; + case locate_service_krb524: + return "locate_service_krb524"; + case locate_service_kpasswd: + return "locate_service_kpasswd"; + default: + break; + } + return NULL; +} + +static const char *socktype_name(int socktype) +{ + switch (socktype) { + case SOCK_STREAM: + return "SOCK_STREAM"; + case SOCK_DGRAM: + return "SOCK_DGRAM"; + default: + break; + } + return "unknown"; +} + +static const char *family_name(int family) +{ + switch (family) { + case AF_UNSPEC: + return "AF_UNSPEC"; + case AF_INET: + return "AF_INET"; + case AF_INET6: + return "AF_INET6"; + default: + break; + } + return "unknown"; +} + +/** + * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones + * + * @param svc + * @param realm string + * @param socktype integer + * @param family integer + * + * @return integer. + */ + +static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc, + const char *realm, + int socktype, + int family) +{ + if (!realm || strlen(realm) == 0) { + return EINVAL; + } + + switch (svc) { + case locate_service_kdc: + case locate_service_master_kdc: + case locate_service_kpasswd: + break; + case locate_service_kadmin: + case locate_service_krb524: +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + default: + return EINVAL; + } + + switch (family) { + case AF_UNSPEC: + case AF_INET: + break; + case AF_INET6: /* not yet */ +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + default: + return EINVAL; + } + + switch (socktype) { + case SOCK_STREAM: + case SOCK_DGRAM: + case 0: /* Heimdal uses that */ + break; + default: + return EINVAL; + } + + return 0; +} + +/** + * Try to get addrinfo for a given host and call the krb5 callback + * + * @param name string + * @param service string + * @param in struct addrinfo hint + * @param cbfunc krb5 callback function + * @param cbdata void pointer cbdata + * + * @return krb5_error_code. + */ + +static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name, + const char *service, + struct addrinfo *in, + int (*cbfunc)(void *, int, struct sockaddr *), + void *cbdata) +{ + struct addrinfo *out; + int ret; + int count = 3; + + while (count) { + + ret = getaddrinfo(name, service, in, &out); + if (ret == 0) { + break; + } + + if (ret == EAI_AGAIN) { + count--; + continue; + } + + DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n", + gai_strerror(ret), ret)); +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + } + + ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr); + if (ret) { + DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n", + error_message(ret), ret)); + } + + freeaddrinfo(out); + + return ret; +} + +/** + * PUBLIC INTERFACE: locate init + * + * @param context krb5_context + * @param privata_data pointer to private data pointer + * + * @return krb5_error_code. + */ + +krb5_error_code smb_krb5_locator_init(krb5_context context, + void **private_data) +{ + setup_logging("smb_krb5_locator", True); + load_case_tables(); + lp_load(dyn_CONFIGFILE,True,False,False,True); + + DEBUG(10,("smb_krb5_locator_init: called\n")); + + return 0; +} + +/** + * PUBLIC INTERFACE: close locate + * + * @param private_data pointer to private data + * + * @return void. + */ + +void smb_krb5_locator_close(void *private_data) +{ + DEBUG(10,("smb_krb5_locator_close: called\n")); + + /* gfree_all(); */ +} + +/** + * PUBLIC INTERFACE: locate lookup + * + * @param private_data pointer to private data + * @param svc enum locate_service_type. + * @param realm string + * @param socktype integer + * @param family integer + * @param cbfunc callback function to send back entries + * @param cbdata void pointer to cbdata + * + * @return krb5_error_code. + */ + +krb5_error_code smb_krb5_locator_lookup(void *private_data, + enum locate_service_type svc, + const char *realm, + int socktype, + int family, + int (*cbfunc)(void *, int, struct sockaddr *), + void *cbdata) +{ + NTSTATUS status; + krb5_error_code ret; + char *sitename = NULL; + struct ip_service *ip_list; + int count = 0; + struct addrinfo aihints; + char *saf_name = NULL; + int i; + + DEBUG(10,("smb_krb5_locator_lookup: called for\n")); + DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n", + locate_service_type_name(svc), svc, realm)); + DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n", + socktype_name(socktype), socktype, + family_name(family), family)); + + ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family); + if (ret) { + DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n", + error_message(ret), ret)); + return ret; + } + + /* first try to fetch from SAF cache */ + + saf_name = saf_fetch(realm); + if (!saf_name || strlen(saf_name) == 0) { + DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n", + realm)); + goto find_kdc; + } + + DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n", + saf_name, realm)); + + ZERO_STRUCT(aihints); + + aihints.ai_family = family; + aihints.ai_socktype = socktype; + + ret = smb_krb5_locator_call_cbfunc(saf_name, + get_service_from_locate_service_type(svc), + &aihints, + cbfunc, cbdata); + if (ret) { + return ret; + } + + return 0; + + find_kdc: + + /* now try to find via site-aware DNS SRV query */ + + sitename = sitename_fetch(realm); + status = get_kdc_list(realm, sitename, &ip_list, &count); + + /* if we didn't found any KDCs on our site go to the main list */ + + if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) { + SAFE_FREE(ip_list); + SAFE_FREE(sitename); + status = get_kdc_list(realm, NULL, &ip_list, &count); + } + + SAFE_FREE(sitename); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n", + nt_errstr(status), + error_message(nt_status_to_krb5(status)))); +#ifdef KRB5_PLUGIN_NO_HANDLE + return KRB5_PLUGIN_NO_HANDLE; +#else + return KRB5_KDC_UNREACH; /* Heimdal */ +#endif + } + + for (i=0; i<count; i++) { + + const char *host = NULL; + const char *port = NULL; + + ZERO_STRUCT(aihints); + + aihints.ai_family = family; + aihints.ai_socktype = socktype; + + host = inet_ntoa(ip_list[i].ip); + port = get_service_from_locate_service_type(svc); + + ret = smb_krb5_locator_call_cbfunc(host, + port, + &aihints, + cbfunc, cbdata); + if (ret) { + /* got error */ + break; + } + } + + SAFE_FREE(ip_list); + + return ret; +} + +#ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H +#define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */ +#else +#define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */ +#endif + +const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = { + 0, /* version */ + smb_krb5_locator_init, + smb_krb5_locator_close, + smb_krb5_locator_lookup, +}; + +#endif |