summaryrefslogtreecommitdiffstats
path: root/source/libads
diff options
context:
space:
mode:
Diffstat (limited to 'source/libads')
-rw-r--r--source/libads/cldap.c9
-rw-r--r--source/libads/kerberos_keytab.c30
-rw-r--r--source/libads/kerberos_verify.c103
-rw-r--r--source/libads/krb5_errs.c2
-rw-r--r--source/libads/ldap.c11
-rw-r--r--source/libads/ldap_user.c12
-rw-r--r--source/libads/sasl.c32
-rw-r--r--source/libads/smb_krb5_locator.c386
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