1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-05 04:23:51 +03:00

- added initial support for trusted domains in winbindd_ads

- gss error code patch from a.bokovoy@sam-solutions.net
- better sid dumping in ads_dump
- fixed help in wbinfo
This commit is contained in:
Andrew Tridgell
-
parent 7348a969bc
commit ee1c3e1f04
10 changed files with 230 additions and 47 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
@@ -232,6 +236,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
*/
@@ -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

View File

@@ -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"};
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);
/* 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);
input_name.value = &principal;
input_name.length = sizeof(principal);
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

View File

@@ -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;
}
}

View File

@@ -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 */

View File

@@ -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,

View File

@@ -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;
@@ -147,6 +144,10 @@ BOOL get_domain_info(void)
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"));
result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains,
@@ -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)));
}
}

View File

@@ -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;
}

View File

@@ -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;