summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/ads.h11
-rw-r--r--source3/libads/ads_struct.c26
-rw-r--r--source3/libads/ldap.c77
-rw-r--r--source3/libads/sasl.c53
-rw-r--r--source3/nsswitch/wbinfo.c6
-rw-r--r--source3/nsswitch/winbindd_ads.c57
-rw-r--r--source3/nsswitch/winbindd_cache.c26
-rw-r--r--source3/nsswitch/winbindd_util.c10
-rw-r--r--source3/script/mkproto.awk2
-rw-r--r--source3/utils/net_ads.c9
10 files changed, 230 insertions, 47 deletions
diff --git a/source3/include/ads.h b/source3/include/ads.h
index 5ae127ff28..4a20d0e79f 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -15,8 +15,19 @@ typedef struct {
time_t last_attempt;
char *password;
char *user_name;
+ char *server_realm;
} ADS_STRUCT;
+typedef struct {
+ /* Type of error returned by ads_connect: */
+ /* True corresponds GSS API, False - LDAP */
+ int error_type;
+ /* For error_type = False rc describes LDAP error */
+ int rc;
+ /* For error_type = True rc and minor_status describe GSS API error */
+ /* Where rc represents major_status of GSS API error */
+ int minor_status;
+} ADS_RETURN_CODE;
/* time between reconnect attempts */
#define ADS_RECONNECT_TIME 5
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
index 4b2ab5b40f..a7c8d1a681 100644
--- a/source3/libads/ads_struct.c
+++ b/source3/libads/ads_struct.c
@@ -157,3 +157,29 @@ void ads_destroy(ADS_STRUCT **ads)
}
}
+
+static void ads_display_status_helper(char *m, OM_uint32 code, int type)
+{
+ int maj_stat, min_stat;
+ gss_buffer_desc msg;
+ int msg_ctx;
+
+ msg_ctx = 0;
+ while (1) {
+ maj_stat = gss_display_status(&min_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ DEBUG(1, ("GSS-API error %s: %s\n", m,
+ (char *)msg.value));
+ (void) gss_release_buffer(&min_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
+
+void ads_display_status(char * msg, int maj_stat,int min_stat)
+{
+ ads_display_status_helper(msg, maj_stat, GSS_C_GSS_CODE);
+ ads_display_status_helper(msg, min_stat, GSS_C_MECH_CODE);
+}
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 09498b4384..b41a864ae2 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -38,20 +38,24 @@ char *ads_errstr(int rc)
/*
connect to the LDAP server
*/
-int ads_connect(ADS_STRUCT *ads)
+ADS_RETURN_CODE ads_connect(ADS_STRUCT *ads)
{
int version = LDAP_VERSION3;
- int rc;
+ ADS_RETURN_CODE rc;
+
+ rc.error_type = False;
ads->last_attempt = time(NULL);
ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
if (!ads->ld) {
- return LDAP_SERVER_DOWN;
+ rc.rc = LDAP_SERVER_DOWN;
+ return rc;
}
if (!ads_server_info(ads)) {
DEBUG(1,("Failed to get ldap server info\n"));
- return LDAP_SERVER_DOWN;
+ rc.rc = LDAP_SERVER_DOWN;
+ return rc;
}
ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
@@ -233,6 +237,19 @@ static void dump_binary(const char *field, struct berval **values)
}
/*
+ dump a sid result from ldap
+*/
+static void dump_sid(const char *field, struct berval **values)
+{
+ int i;
+ for (i=0; values[i]; i++) {
+ DOM_SID sid;
+ sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
+ printf("%s: %s\n", field, sid_string_static(&sid));
+ }
+}
+
+/*
dump a string result from ldap
*/
static void dump_string(const char *field, struct berval **values)
@@ -257,7 +274,7 @@ void ads_dump(ADS_STRUCT *ads, void *res)
void (*handler)(const char *, struct berval **);
} handlers[] = {
{"objectGUID", dump_binary},
- {"objectSid", dump_binary},
+ {"objectSid", dump_sid},
{NULL, NULL}
};
@@ -547,12 +564,16 @@ BOOL ads_server_info(ADS_STRUCT *ads)
*p = 0;
+ SAFE_FREE(ads->server_realm);
+ SAFE_FREE(ads->bind_path);
+
+ ads->server_realm = strdup(p+2);
+ ads->bind_path = ads_build_dn(ads->server_realm);
+
/* in case the realm isn't configured in smb.conf */
if (!ads->realm || !ads->realm[0]) {
SAFE_FREE(ads->realm);
- SAFE_FREE(ads->bind_path);
- ads->realm = strdup(p+2);
- ads->bind_path = ads_build_dn(ads->realm);
+ ads->realm = strdup(ads->server_realm);
}
DEBUG(3,("got ldap server name %s@%s\n",
@@ -561,4 +582,44 @@ BOOL ads_server_info(ADS_STRUCT *ads)
return True;
}
+
+/*
+ find the list of trusted domains
+*/
+BOOL ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ int *num_trusts, char ***names, DOM_SID **sids)
+{
+ const char *attrs[] = {"flatName", "securityIdentifier", NULL};
+ int rc;
+ void *res, *msg;
+ int count, i;
+
+ *num_trusts = 0;
+
+ rc = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
+ if (rc) return False;
+
+ count = ads_count_replies(ads, res);
+ if (count == 0) {
+ ads_msgfree(ads, res);
+ return False;
+ }
+
+ (*names) = talloc(mem_ctx, sizeof(char *) * count);
+ (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
+ if (! *names || ! *sids) return False;
+
+ for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
+ (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
+ ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i]);
+ i++;
+ }
+
+ ads_msgfree(ads, res);
+
+ *num_trusts = i;
+
+ return True;
+}
+
#endif
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index dd948b5d4d..b3610b8fdb 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -53,9 +53,9 @@ static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in)
this routine is much less fragile
see RFC2078 for details
*/
-int ads_sasl_gssapi_bind(ADS_STRUCT *ads)
+ADS_RETURN_CODE ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
- int rc, minor_status;
+ int minor_status;
gss_name_t serv_name;
gss_buffer_desc input_name;
gss_ctx_id_t context_handle;
@@ -69,15 +69,27 @@ int ads_sasl_gssapi_bind(ADS_STRUCT *ads)
uint8 *p;
uint32 max_msg_size;
char *sname;
+ ADS_RETURN_CODE rc;
+ krb5_principal principal;
+ krb5_context ctx;
+ krb5_enctype enc_types[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
+ gss_OID_desc nt_principal =
+ {10, "\052\206\110\206\367\022\001\002\002\002"};
+
+ /* we need to fetch a service ticket as the ldap user in the
+ servers realm, regardless of our realm */
+ asprintf(&sname, "ldap/%s@%s", ads->ldap_server_name, ads->server_realm);
+ krb5_init_context(&ctx);
+ krb5_set_default_tgs_ktypes(ctx, enc_types);
+ krb5_parse_name(ctx, sname, &principal);
+ free(sname);
+ krb5_free_context(ctx);
- asprintf(&sname, "ldap@%s.%s", ads->ldap_server_name, ads->realm);
-
- input_name.value = sname;
- input_name.length = strlen(input_name.value);
-
- rc = gss_import_name(&minor_status,&input_name,gss_nt_service_name, &serv_name);
+ input_name.value = &principal;
+ input_name.length = sizeof(principal);
- free(sname);
+ rc.rc = gss_import_name(&minor_status,&input_name,&nt_principal, &serv_name);
+ rc.error_type = False;
context_handle = GSS_C_NO_CONTEXT;
@@ -103,12 +115,17 @@ int ads_sasl_gssapi_bind(ADS_STRUCT *ads)
gss_release_buffer(&minor_status, &input_token);
}
- if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) goto failed;
+ if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
+ rc.minor_status = minor_status;
+ rc.rc = gss_rc;
+ rc.error_type = True;
+ goto failed;
+ }
cred.bv_val = output_token.value;
cred.bv_len = output_token.length;
- rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ rc.rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
&scred);
if (output_token.value) {
@@ -152,7 +169,7 @@ int ads_sasl_gssapi_bind(ADS_STRUCT *ads)
output_token.length = strlen(ads->bind_path) + 8;
- gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
+ rc.rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
&output_token, &conf_state,
&input_token);
@@ -161,22 +178,24 @@ int ads_sasl_gssapi_bind(ADS_STRUCT *ads)
cred.bv_val = input_token.value;
cred.bv_len = input_token.length;
- rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
+ rc.rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
&scred);
gss_release_buffer(&minor_status, &input_token);
- return rc;
failed:
- return gss_rc;
+ return rc;
}
-int ads_sasl_bind(ADS_STRUCT *ads)
+ADS_RETURN_CODE ads_sasl_bind(ADS_STRUCT *ads)
{
#if USE_CYRUS_SASL
- return ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL,
+ ADS_RETURN_CODE rc;
+ rc.error_type = False;
+ rc.rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL,
LDAP_SASL_QUIET,
sasl_interact, NULL);
+ return rc;
#else
return ads_sasl_gssapi_bind(ads);
#endif
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
index 82d483611f..9c012eb85d 100644
--- a/source3/nsswitch/wbinfo.c
+++ b/source3/nsswitch/wbinfo.c
@@ -486,7 +486,7 @@ int main(int argc, char **argv)
struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-
+ { "help", 'h', POPT_ARG_NONE, 0, 'h' },
{ "domain-users", 'u', POPT_ARG_NONE, 0, 'u' },
{ "domain-groups", 'g', POPT_ARG_NONE, 0, 'g' },
{ "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n' },
@@ -548,6 +548,9 @@ int main(int argc, char **argv)
while((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
+ case 'h':
+ usage();
+ exit(0);
case 'u':
if (!print_domain_users()) {
printf("Error looking up domain users\n");
@@ -644,6 +647,7 @@ int main(int argc, char **argv)
break;
default:
fprintf(stderr, "Invalid option\n");
+ usage();
return 1;
}
}
diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c
index e52f448a63..4ce0894ab3 100644
--- a/source3/nsswitch/winbindd_ads.c
+++ b/source3/nsswitch/winbindd_ads.c
@@ -24,6 +24,9 @@
#ifdef HAVE_ADS
+/* the realm of our primary LDAP server */
+static char *primary_realm;
+
/*
a wrapper around ldap_search_s that retries depending on the error code
@@ -33,7 +36,8 @@ int ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
const char *exp,
const char **attrs, void **res)
{
- int rc = -1, rc2;
+ int rc = -1;
+ ADS_RETURN_CODE rc2;
int count = 3;
if (!ads->ld &&
@@ -59,9 +63,15 @@ int ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
}
ads->ld = NULL;
rc2 = ads_connect(ads);
- if (rc2) {
- DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n", ads_errstr(rc)));
- return rc2;
+ if (rc2.rc) {
+ DEBUG(1,("ads_search_retry: failed to reconnect:\n"));
+ if(rc2.error_type)
+ ads_display_status("", rc2.rc, rc2.minor_status);
+ else
+ DEBUG(1,("LDAP error: %s\n", ads_errstr(rc2.rc)));
+
+ ads_destroy(&ads);
+ return rc2.rc;
}
}
DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(rc)));
@@ -92,8 +102,9 @@ int ads_search_retry_dn(ADS_STRUCT *ads, void **res,
static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
{
ADS_STRUCT *ads;
- int rc;
+ ADS_RETURN_CODE rc;
char *ccache;
+ struct in_addr server_ip;
if (domain->private) {
return (ADS_STRUCT *)domain->private;
@@ -104,7 +115,12 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
SETENV("KRB5CCNAME", ccache, 1);
unlink(ccache);
- ads = ads_init(NULL, NULL, NULL, NULL);
+ if (!resolve_name(domain->name, &server_ip, 0x1b)) {
+ DEBUG(1,("Can't find PDC for domain %s\n", domain->name));
+ return NULL;
+ }
+
+ ads = ads_init(primary_realm, inet_ntoa(server_ip), NULL, NULL);
if (!ads) {
DEBUG(1,("ads_init for domain %s failed\n", domain->name));
return NULL;
@@ -115,12 +131,22 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
ads->password = secrets_fetch_machine_password();
rc = ads_connect(ads);
- if (rc) {
- DEBUG(1,("ads_connect for domain %s failed: %s\n", domain->name, ads_errstr(rc)));
+ if (rc.rc) {
+ DEBUG(1,("ads_connect for domain %s failed:\n", domain->name));
+ if(rc.error_type)
+ ads_display_status("", rc.rc, rc.minor_status);
+ else
+ DEBUG(1,("LDAP error: %s\n", ads_errstr(rc.rc)));
+
ads_destroy(&ads);
return NULL;
}
+ /* remember our primary realm for trusted domain support */
+ if (!primary_realm) {
+ primary_realm = strdup(ads->realm);
+ }
+
domain->private = (void *)ads;
return ads;
}
@@ -546,7 +572,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
}
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group)) {
- DEBUG(1,("No primary group for rid=%d !?\n", user_rid));
+ DEBUG(1,("%s: No primary group for rid=%d !?\n", domain->name, user_rid));
goto done;
}
@@ -666,8 +692,19 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
char ***names,
DOM_SID **dom_sids)
{
+ ADS_STRUCT *ads = NULL;
+
*num_domains = 0;
- return NT_STATUS_NOT_IMPLEMENTED;
+ *names = NULL;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+ if (!ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
}
/* find the domain sid for a domain */
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index 32f9f0d69f..847ec9e541 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -462,8 +462,10 @@ do_cached:
return status;
do_query:
+ *num_entries = 0;
+ *info = NULL;
+
if (wcache_server_down(domain)) {
- *num_entries = 0;
return NT_STATUS_SERVER_DISABLED;
}
@@ -533,8 +535,10 @@ do_cached:
return status;
do_query:
+ *num_entries = 0;
+ *info = NULL;
+
if (wcache_server_down(domain)) {
- *num_entries = 0;
return NT_STATUS_SERVER_DISABLED;
}
@@ -580,6 +584,8 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
return status;
do_query:
+ ZERO_STRUCTP(sid);
+
if (wcache_server_down(domain)) {
return NT_STATUS_SERVER_DISABLED;
}
@@ -619,6 +625,8 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
return status;
do_query:
+ *name = NULL;
+
if (wcache_server_down(domain)) {
return NT_STATUS_SERVER_DISABLED;
}
@@ -656,9 +664,12 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
return status;
do_query:
+ ZERO_STRUCTP(info);
+
if (wcache_server_down(domain)) {
return NT_STATUS_SERVER_DISABLED;
}
+
status = cache->backend->query_user(domain, mem_ctx, user_rid, info);
/* and save it */
@@ -701,8 +712,10 @@ do_cached:
return status;
do_query:
+ (*num_groups) = 0;
+ (*user_gids) = NULL;
+
if (wcache_server_down(domain)) {
- (*num_groups) = 0;
return NT_STATUS_SERVER_DISABLED;
}
status = cache->backend->lookup_usergroups(domain, mem_ctx, user_rid, num_groups, user_gids);
@@ -763,8 +776,13 @@ do_cached:
return status;
do_query:
+ (*num_names) = 0;
+ (*rid_mem) = NULL;
+ (*names) = NULL;
+ (*name_types) = NULL;
+
+
if (wcache_server_down(domain)) {
- (*num_names) = 0;
return NT_STATUS_SERVER_DISABLED;
}
status = cache->backend->lookup_groupmem(domain, mem_ctx, group_rid, num_names,
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index 608749b39d..f760b635d6 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -98,10 +98,7 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,
}
}
- DEBUG(1, ("adding domain %s\n", domain_name));
-
/* Create new domain entry */
-
if ((domain = (struct winbindd_domain *)malloc(sizeof(*domain))) == NULL)
return NULL;
@@ -146,6 +143,10 @@ BOOL get_domain_info(void)
domain->name));
result = cache_methods.domain_sid(domain, &domain->sid);
}
+
+ DEBUG(1,("Added domain %s (%s)\n",
+ domain->name,
+ sid_string_static(&domain->sid)));
DEBUG(1, ("getting trusted domain list\n"));
@@ -160,6 +161,9 @@ BOOL get_domain_info(void)
if (domain) {
sid_copy(&domain->sid, &dom_sids[i]);
}
+ DEBUG(1,("Added domain %s (%s)\n",
+ domain->name,
+ sid_string_static(&domain->sid)));
}
}
diff --git a/source3/script/mkproto.awk b/source3/script/mkproto.awk
index f927d273bd..7c8bc3d6cf 100644
--- a/source3/script/mkproto.awk
+++ b/source3/script/mkproto.awk
@@ -122,7 +122,7 @@ END {
gotstart = 1;
}
- if( $0 ~ /^ADS_STRUCT|^DATA_BLOB|^ASN1_DATA|^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum.*\(|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) {
+ if( $0 ~ /^ADS_STRUCT|^ADS_RETURN_CODE|^DATA_BLOB|^ASN1_DATA|^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum.*\(|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) {
gotstart = 1;
}
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 8d41c09208..0d7b641771 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -68,7 +68,7 @@ static int net_ads_info(int argc, const char **argv)
static ADS_STRUCT *ads_startup(void)
{
ADS_STRUCT *ads;
- int rc;
+ ADS_RETURN_CODE rc;
extern char *opt_password;
extern char *opt_user_name;
@@ -88,8 +88,11 @@ static ADS_STRUCT *ads_startup(void)
ads->user_name = strdup(opt_user_name);
rc = ads_connect(ads);
- if (rc) {
- d_printf("ads_connect: %s\n", ads_errstr(rc));
+ if (rc.rc) {
+ if(rc.error_type)
+ ads_display_status("ads_connect", rc.rc, rc.minor_status);
+ else
+ d_printf("ads_connect: %s\n", ads_errstr(rc.rc));
return NULL;
}
return ads;