diff options
-rw-r--r-- | source3/include/ads.h | 24 | ||||
-rw-r--r-- | source3/libads/ads_struct.c | 5 | ||||
-rw-r--r-- | source3/libads/ldap.c | 96 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.h | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_ads.c | 24 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_async.c | 9 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 8 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_nss.h | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_rpc.c | 9 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_user.c | 118 | ||||
-rw-r--r-- | source3/param/loadparm.c | 4 | ||||
-rw-r--r-- | source3/sam/idmap_ad.c | 47 |
12 files changed, 291 insertions, 59 deletions
diff --git a/source3/include/ads.h b/source3/include/ads.h index 27f9384d5d..8f6cc6e582 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -36,9 +36,19 @@ typedef struct { struct { char *realm; char *bind_path; + char *schema_path; char *ldap_server_name; time_t current_time; } config; + + /* info derived from the servers schema */ + struct { + char *sfu_homedir_attr; + char *sfu_shell_attr; + char *sfu_uidnumber_attr; + char *sfu_gidnumber_attr; + } schema; + } ADS_STRUCT; /* there are 5 possible types of errors the ads subsystem can produce */ @@ -77,10 +87,16 @@ typedef void **ADS_MODLIST; #define ADS_RECONNECT_TIME 5 /* ldap control oids */ -#define ADS_PAGE_CTL_OID "1.2.840.113556.1.4.319" -#define ADS_NO_REFERRALS_OID "1.2.840.113556.1.4.1339" -#define ADS_SERVER_SORT_OID "1.2.840.113556.1.4.473" -#define ADS_PERMIT_MODIFY_OID "1.2.840.113556.1.4.1413" +#define ADS_PAGE_CTL_OID "1.2.840.113556.1.4.319" +#define ADS_NO_REFERRALS_OID "1.2.840.113556.1.4.1339" +#define ADS_SERVER_SORT_OID "1.2.840.113556.1.4.473" +#define ADS_PERMIT_MODIFY_OID "1.2.840.113556.1.4.1413" + +/* ldap attribute oids (Services for Unix) */ +#define ADS_ATTR_SFU_UIDNUMBER_OID "1.2.840.113556.1.6.18.1.310" +#define ADS_ATTR_SFU_GIDNUMBER_OID "1.2.840.113556.1.6.18.1.311" +#define ADS_ATTR_SFU_HOMEDIR_OID "1.2.840.113556.1.6.18.1.344" +#define ADS_ATTR_SFU_SHELL_OID "1.2.840.113556.1.6.18.1.312" /* UserFlags for userAccountControl */ #define UF_SCRIPT 0x00000001 diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index e8546f86f5..d8676d050d 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -132,8 +132,13 @@ void ads_destroy(ADS_STRUCT **ads) SAFE_FREE((*ads)->config.realm); SAFE_FREE((*ads)->config.bind_path); + SAFE_FREE((*ads)->config.schema_path); SAFE_FREE((*ads)->config.ldap_server_name); + SAFE_FREE((*ads)->schema.sfu_uidnumber_attr); + SAFE_FREE((*ads)->schema.sfu_gidnumber_attr); + SAFE_FREE((*ads)->schema.sfu_shell_attr); + SAFE_FREE((*ads)->schema.sfu_homedir_attr); ZERO_STRUCTP(*ads); diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 04754f4e9e..1289015464 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2388,6 +2388,43 @@ static time_t ads_parse_time(const char *str) } +const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char * oid) +{ + ADS_STATUS rc; + int count = 0; + void *res = NULL; + char *expr = NULL; + const char *attrs[] = { "lDAPDisplayName", NULL }; + + if (ads == NULL || mem_ctx == NULL || oid == NULL) { + goto done; + } + + expr = talloc_asprintf(mem_ctx, "(attributeId=%s)", oid); + if (expr == NULL) { + goto done; + } + + rc = ads_do_search_retry(ads, ads->config.schema_path, + LDAP_SCOPE_SUBTREE, expr, attrs, &res); + if (!ADS_ERR_OK(rc)) { + goto done; + } + + count = ads_count_replies(ads, res); + if (count == 0 || !res) { + goto done; + } + + return ads_pull_string(ads, mem_ctx, res, "lDAPDisplayName"); + +done: + DEBUG(0,("ads_get_attrname_by_oid: failed to retrieve name for oid: %s\n", + oid)); + + return NULL; +} + /** * Find the servers name and realm - this can be done before authentication * The ldapServiceName field on w2k looks like this: @@ -2397,12 +2434,15 @@ static time_t ads_parse_time(const char *str) **/ ADS_STATUS ads_server_info(ADS_STRUCT *ads) { - const char *attrs[] = {"ldapServiceName", "currentTime", NULL}; + const char *attrs[] = {"ldapServiceName", + "currentTime", + "schemaNamingContext", NULL}; ADS_STATUS status; void *res; char *value; char *p; char *timestr; + char *schema_path; TALLOC_CTX *ctx; if (!(ctx = talloc_init("ads_server_info"))) { @@ -2429,6 +2469,16 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); } + schema_path = ads_pull_string(ads, ctx, res, "schemaNamingContext"); + if (!schema_path) { + ads_msgfree(ads, res); + talloc_destroy(ctx); + return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); + } + + SAFE_FREE(ads->config.schema_path); + ads->config.schema_path = SMB_STRDUP(schema_path); + ads_msgfree(ads, res); p = strchr(value, ':'); @@ -2476,6 +2526,50 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads) } /** + * Check for "Services for Unix"-Schema and load some attributes into the ADS_STRUCT + * @param ads connection to ads server + * @return BOOL status of search (False if one or more attributes couldn't be + * found in Active Directory) + **/ +BOOL ads_check_sfu_mapping(ADS_STRUCT *ads) +{ + BOOL ret = False; + TALLOC_CTX *ctx = NULL; + const char *gidnumber, *uidnumber, *homedir, *shell; + + ctx = talloc_init("ads_check_sfu_mapping"); + if (ctx == NULL) + goto done; + + gidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_GIDNUMBER_OID); + if (gidnumber == NULL) + goto done; + ads->schema.sfu_gidnumber_attr = SMB_STRDUP(gidnumber); + + uidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_UIDNUMBER_OID); + if (uidnumber == NULL) + goto done; + ads->schema.sfu_uidnumber_attr = SMB_STRDUP(uidnumber); + + homedir = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_HOMEDIR_OID); + if (homedir == NULL) + goto done; + ads->schema.sfu_homedir_attr = SMB_STRDUP(homedir); + + shell = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_SHELL_OID); + if (shell == NULL) + goto done; + ads->schema.sfu_shell_attr = SMB_STRDUP(shell); + + ret = True; +done: + if (ctx) + talloc_destroy(ctx); + + return ret; +} + +/** * find the domain sid for our domain * @param ads connection to ads server * @param sid Pointer to domain sid diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 378120c80b..3a7728e4a2 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -84,6 +84,8 @@ struct getent_state { struct getpwent_user { fstring name; /* Account name */ fstring gecos; /* User information */ + fstring homedir; /* User Home Directory */ + fstring shell; /* User Login Shell */ DOM_SID user_sid; /* NT user and primary group SIDs */ DOM_SID group_sid; }; @@ -103,6 +105,8 @@ extern struct winbindd_state server_state; /* Server information */ typedef struct { char *acct_name; char *full_name; + char *homedir; + char *shell; DOM_SID user_sid; /* NT user and primary group SIDs */ DOM_SID group_sid; } WINBIND_USERINFO; diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index c807ec59a5..868a7bc2ac 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -95,6 +95,11 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) return NULL; } + if (lp_winbind_sfu_support() && (!ads_check_sfu_mapping(ads))) { + DEBUG(0,("ads_cached_connection: failed to check sfu attributes\n")); + return NULL; + } + /* set the flag that says we don't own the memory even though we do so that ads_destroy() won't destroy the structure we pass back by reference */ @@ -116,7 +121,10 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, const char *attrs[] = {"userPrincipalName", "sAMAccountName", "name", "objectSid", "primaryGroupID", - "sAMAccountType", NULL}; + "sAMAccountType", + ADS_ATTR_SFU_HOMEDIR_OID, + ADS_ATTR_SFU_SHELL_OID, + NULL}; int i, count; ADS_STATUS rc; void *res = NULL; @@ -155,7 +163,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, i = 0; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { - char *name, *gecos; + char *name, *gecos, *homedir, *shell; uint32 group; uint32 atype; @@ -167,6 +175,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, name = ads_pull_username(ads, mem_ctx, msg); gecos = ads_pull_string(ads, mem_ctx, msg, "name"); + homedir = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_homedir_attr); + shell = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_shell_attr); + if (!ads_pull_sid(ads, msg, "objectSid", &(*info)[i].user_sid)) { DEBUG(1,("No sid for %s !?\n", name)); @@ -179,6 +190,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, (*info)[i].acct_name = name; (*info)[i].full_name = gecos; + (*info)[i].homedir = homedir; + (*info)[i].shell = shell; sid_compose(&(*info)[i].group_sid, &domain->sid, group); i++; } @@ -364,7 +377,10 @@ static NTSTATUS query_user(struct winbindd_domain *domain, const char *attrs[] = {"userPrincipalName", "sAMAccountName", "name", - "primaryGroupID", NULL}; + "primaryGroupID", + ADS_ATTR_SFU_HOMEDIR_OID, + ADS_ATTR_SFU_SHELL_OID, + NULL}; ADS_STATUS rc; int count; void *msg = NULL; @@ -402,6 +418,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain, info->acct_name = ads_pull_username(ads, mem_ctx, msg); info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); + info->homedir = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_homedir_attr); + info->shell = ads_pull_string(ads, mem_ctx, msg, ads->schema.sfu_shell_attr); if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { DEBUG(1,("No primary group for %s !?\n", diff --git a/source3/nsswitch/winbindd_async.c b/source3/nsswitch/winbindd_async.c index d227177ec1..acae7e7f37 100644 --- a/source3/nsswitch/winbindd_async.c +++ b/source3/nsswitch/winbindd_async.c @@ -1372,16 +1372,19 @@ static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success, void *c, void *private_data) { void (*cont)(void *priv, BOOL succ, const char *acct_name, - const char *full_name, uint32 group_rid) = c; + const char *full_name, const char *homedir, + const char *shell, uint32 group_rid) = c; if (!success) { DEBUG(5, ("Could not trigger query_user\n")); - cont(private_data, False, NULL, NULL, -1); + cont(private_data, False, NULL, NULL, NULL, NULL, -1); return; } cont(private_data, True, response->data.user_info.acct_name, response->data.user_info.full_name, + response->data.user_info.homedir, + response->data.user_info.shell, response->data.user_info.group_rid); } @@ -1390,6 +1393,8 @@ void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, void (*cont)(void *private_data, BOOL success, const char *acct_name, const char *full_name, + const char *homedir, + const char *shell, uint32 group_rid), void *private_data) { diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 90ccb43a6e..730da7a9b5 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -652,6 +652,8 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI return; centry_put_string(centry, info->acct_name); centry_put_string(centry, info->full_name); + centry_put_string(centry, info->homedir); + centry_put_string(centry, info->shell); centry_put_sid(centry, &info->user_sid); centry_put_sid(centry, &info->group_sid); centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid)); @@ -689,6 +691,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, for (i=0; i<(*num_entries); i++) { (*info)[i].acct_name = centry_string(centry, mem_ctx); (*info)[i].full_name = centry_string(centry, mem_ctx); + (*info)[i].homedir = centry_string(centry, mem_ctx); + (*info)[i].shell = centry_string(centry, mem_ctx); centry_sid(centry, &(*info)[i].user_sid); centry_sid(centry, &(*info)[i].group_sid); } @@ -747,6 +751,8 @@ do_query: for (i=0; i<(*num_entries); i++) { centry_put_string(centry, (*info)[i].acct_name); centry_put_string(centry, (*info)[i].full_name); + centry_put_string(centry, (*info)[i].homedir); + centry_put_string(centry, (*info)[i].shell); centry_put_sid(centry, &(*info)[i].user_sid); centry_put_sid(centry, &(*info)[i].group_sid); if (domain->backend->consistent) { @@ -1082,6 +1088,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain, info->acct_name = centry_string(centry, mem_ctx); info->full_name = centry_string(centry, mem_ctx); + info->homedir = centry_string(centry, mem_ctx); + info->shell = centry_string(centry, mem_ctx); centry_sid(centry, &info->user_sid); centry_sid(centry, &info->group_sid); status = centry->status; diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index b249b62d69..cf0fae74a0 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -322,6 +322,8 @@ struct winbindd_response { struct { fstring acct_name; fstring full_name; + fstring homedir; + fstring shell; uint32 group_rid; } user_info; } data; diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index 2b4c020d88..63e2487700 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/nsswitch/winbindd_rpc.c @@ -101,6 +101,8 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, (*info)[i].acct_name = talloc_strdup(mem_ctx, username ); (*info)[i].full_name = talloc_strdup(mem_ctx, fullname ); + (*info)[i].homedir = NULL; + (*info)[i].shell = NULL; sid_compose(&(*info)[i].user_sid, &domain->sid, rid); /* For the moment we set the primary group for @@ -352,7 +354,10 @@ static NTSTATUS query_user(struct winbindd_domain *domain, &user->uni_user_name); user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name); - + + user_info->homedir = NULL; + user_info->shell = NULL; + SAFE_FREE(user); return NT_STATUS_OK; @@ -388,6 +393,8 @@ static NTSTATUS query_user(struct winbindd_domain *domain, &ctr->info.id21->uni_user_name); user_info->full_name = unistr2_tdup(mem_ctx, &ctr->info.id21->uni_full_name); + user_info->homedir = NULL; + user_info->shell = NULL; return NT_STATUS_OK; } diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 576ceaea23..f849bff42d 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -30,15 +30,50 @@ extern userdom_struct current_user_info; +static BOOL fillup_pw_field(const char *lp_template, + const char *username, + const char *domname, + uid_t uid, + gid_t gid, + const char *in, + fstring out) +{ + char *templ; + + if (out == NULL) + return False; + + if (in && !strequal(in,"") && lp_security() == SEC_ADS && lp_winbind_sfu_support()) { + safe_strcpy(out, in, sizeof(fstring) - 1); + return True; + } + + /* Home directory and shell - use template config parameters. The + defaults are /tmp for the home directory and /bin/false for + shell. */ + + /* The substitution of %U and %D in the 'template homedir' is done + by alloc_sub_specified() below. */ + + templ = alloc_sub_specified(lp_template, username, domname, uid, gid); + + if (!templ) + return False; + + safe_strcpy(out, templ, sizeof(fstring) - 1); + SAFE_FREE(templ); + + return True; + +} /* Fill a pwent structure with information we have obtained */ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, DOM_SID *user_sid, DOM_SID *group_sid, - char *full_name, struct winbindd_pw *pw) + char *full_name, char *homedir, char *shell, + struct winbindd_pw *pw) { fstring output_username; - char *homedir; - char *shell; fstring sid_string; if (!pw || !dom_name || !user_name) @@ -79,25 +114,14 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, fstrcpy(current_user_info.domain, dom_name); - homedir = alloc_sub_specified(lp_template_homedir(), user_name, dom_name, pw->pw_uid, pw->pw_gid); - - if (!homedir) + if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name, + pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir)) return False; - - safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1); - - SAFE_FREE(homedir); - - shell = alloc_sub_specified(lp_template_shell(), user_name, dom_name, pw->pw_uid, pw->pw_gid); - if (!shell) + if (!fillup_pw_field(lp_template_shell(), user_name, dom_name, + pw->pw_uid, pw->pw_gid, shell, pw->pw_shell)) return False; - safe_strcpy(pw->pw_shell, shell, - sizeof(pw->pw_shell) - 1); - - SAFE_FREE(shell); - /* Password - set to "x" as we can't generate anything useful here. Authentication can be done using the pam_winbind module. */ @@ -136,6 +160,8 @@ enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain, fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name); fstrcpy(state->response.data.user_info.full_name, user_info.full_name); + fstrcpy(state->response.data.user_info.homedir, user_info.homedir); + fstrcpy(state->response.data.user_info.shell, user_info.shell); if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid, &state->response.data.user_info.group_rid)) { DEBUG(1, ("Could not extract group rid out of %s\n", @@ -151,6 +177,8 @@ struct getpwsid_state { struct winbindd_domain *domain; char *username; char *fullname; + char *homedir; + char *shell; DOM_SID user_sid; uid_t uid; DOM_SID group_sid; @@ -159,7 +187,10 @@ struct getpwsid_state { static void getpwsid_queryuser_recv(void *private_data, BOOL success, const char *acct_name, - const char *full_name, uint32 group_rid); + const char *full_name, + const char *homedir, + const char *shell, + uint32 group_rid); static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid); static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid); @@ -194,7 +225,10 @@ static void winbindd_getpwsid(struct winbindd_cli_state *state, static void getpwsid_queryuser_recv(void *private_data, BOOL success, const char *acct_name, - const char *full_name, uint32 group_rid) + const char *full_name, + const char *homedir, + const char *shell, + uint32 group_rid) { struct getpwsid_state *s = talloc_get_type_abort(private_data, struct getpwsid_state); @@ -208,6 +242,8 @@ static void getpwsid_queryuser_recv(void *private_data, BOOL success, s->username = talloc_strdup(s->state->mem_ctx, acct_name); s->fullname = talloc_strdup(s->state->mem_ctx, full_name); + s->homedir = talloc_strdup(s->state->mem_ctx, homedir); + s->shell = talloc_strdup(s->state->mem_ctx, shell); sid_copy(&s->group_sid, &s->domain->sid); sid_append_rid(&s->group_sid, group_rid); @@ -238,8 +274,6 @@ static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid) talloc_get_type_abort(private_data, struct getpwsid_state); struct winbindd_pw *pw; fstring output_username; - char *homedir; - char *shell; if (!success) { DEBUG(5, ("Could not query user's %s\\%s\n gid", @@ -256,32 +290,19 @@ static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid) safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1); safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1); - /* Home directory and shell - use template config parameters. The - defaults are /tmp for the home directory and /bin/false for - shell. */ - - /* The substitution of %U and %D in the 'template homedir' is done - by alloc_sub_specified() below. */ - fstrcpy(current_user_info.domain, s->domain->name); - homedir = alloc_sub_specified(lp_template_homedir(), s->username, - s->domain->name, pw->pw_uid, pw->pw_gid); - if (homedir == NULL) { + if (!fillup_pw_field(lp_template_homedir(), s->username, s->domain->name, + pw->pw_uid, pw->pw_gid, s->homedir, pw->pw_dir)) { DEBUG(5, ("Could not compose homedir\n")); goto failed; } - safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1); - SAFE_FREE(homedir); - - shell = alloc_sub_specified(lp_template_shell(), s->username, - s->domain->name, pw->pw_uid, pw->pw_gid); - if (shell == NULL) { + + if (!fillup_pw_field(lp_template_shell(), s->username, s->domain->name, + pw->pw_uid, pw->pw_gid, s->shell, pw->pw_shell)) { DEBUG(5, ("Could not compose shell\n")); goto failed; } - safe_strcpy(pw->pw_shell, shell, sizeof(pw->pw_shell) - 1); - SAFE_FREE(shell); /* Password - set to "x" as we can't generate anything useful here. Authentication can be done using the pam_winbind module. */ @@ -555,7 +576,20 @@ static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx) fstrcpy(name_list[ent->num_sam_entries + i].gecos, info[i].full_name); } - + if (!info[i].homedir) { + fstrcpy(name_list[ent->num_sam_entries + i].homedir, ""); + } else { + fstrcpy(name_list[ent->num_sam_entries + i].homedir, + info[i].homedir); + } + if (!info[i].shell) { + fstrcpy(name_list[ent->num_sam_entries + i].shell, ""); + } else { + fstrcpy(name_list[ent->num_sam_entries + i].shell, + info[i].shell); + } + + /* User and group ids */ sid_copy(&name_list[ent->num_sam_entries+i].user_sid, &info[i].user_sid); @@ -658,6 +692,8 @@ void winbindd_getpwent(struct winbindd_cli_state *state) &name_list[ent->sam_entry_index].user_sid, &name_list[ent->sam_entry_index].group_sid, name_list[ent->sam_entry_index].gecos, + name_list[ent->sam_entry_index].homedir, + name_list[ent->sam_entry_index].shell, &user_list[user_list_ndx]); ent->sam_entry_index++; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 15eee5313c..d584997f81 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -226,6 +226,7 @@ typedef struct int oplock_break_wait_time; int winbind_cache_time; int winbind_max_idle_children; + BOOL bWinbindSFUSupport; int iLockSpinCount; int iLockSpinTime; char *szLdapMachineSuffix; @@ -1237,6 +1238,7 @@ static struct parm_struct parm_table[] = { {"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED}, {"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED}, {"winbind max idle children", P_INTEGER, P_GLOBAL, &Globals.winbind_max_idle_children, NULL, NULL, FLAG_ADVANCED}, + {"winbind sfu support", P_BOOL, P_GLOBAL, &Globals.bWinbindSFUSupport, NULL, NULL, FLAG_ADVANCED}, {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0} }; @@ -1582,6 +1584,7 @@ static void init_globals(void) Globals.bWinbindTrustedDomainsOnly = False; Globals.bWinbindNestedGroups = False; Globals.winbind_max_idle_children = 3; + Globals.bWinbindSFUSupport = False; Globals.bEnableRidAlgorithm = True; @@ -2006,6 +2009,7 @@ FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize); FN_LOCAL_CHAR(lp_magicchar, magic_char) FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time) FN_GLOBAL_INTEGER(lp_winbind_max_idle_children, &Globals.winbind_max_idle_children) +FN_GLOBAL_BOOL(lp_winbind_sfu_support, &Globals.bWinbindSFUSupport) FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase) FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout) FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing) diff --git a/source3/sam/idmap_ad.c b/source3/sam/idmap_ad.c index b3b9b7ad47..840dff025e 100644 --- a/source3/sam/idmap_ad.c +++ b/source3/sam/idmap_ad.c @@ -1,5 +1,5 @@ /* - * idmap_ad: map between Active Directory and RFC 2307 accounts + * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts * Copyright (C) 2001-2004 PADL Software Pty Ltd. All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -37,13 +37,11 @@ #define DBGC_CLASS DBGC_IDMAP #ifndef ATTR_UIDNUMBER -/* #define ATTR_UIDNUMBER "msSFU30UidNumber" */ -#define ATTR_UIDNUMBER "uidNumber" +#define ATTR_UIDNUMBER ADS_ATTR_SFU_UIDNUMBER_OID #endif #ifndef ATTR_GIDNUMBER -/* #define ATTR_GIDNUMBER "msSFU30GidNumber" */ -#define ATTR_GIDNUMBER "gidNumber" +#define ATTR_GIDNUMBER ADS_ATTR_SFU_GIDNUMBER_OID #endif #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" @@ -53,6 +51,33 @@ NTSTATUS init_module(void); static ADS_STRUCT *ad_idmap_ads = NULL; static char *ad_idmap_uri = NULL; +static char *attr_uidnumber = NULL; +static char *attr_gidnumber = NULL; + +static BOOL ad_idmap_check_attr_mapping(ADS_STRUCT *ads) +{ + if (attr_uidnumber != NULL && attr_gidnumber != NULL) { + return True; + } + + if (lp_winbind_sfu_support()) { + + if (!ads_check_sfu_mapping(ads)) { + DEBUG(0,("ad_idmap_check_attr_mapping: failed to check for SFU schema\n")); + return False; + } + + attr_uidnumber = SMB_STRDUP(ads->schema.sfu_uidnumber_attr); + attr_gidnumber = SMB_STRDUP(ads->schema.sfu_gidnumber_attr); + + } else { + attr_uidnumber = SMB_STRDUP("uidNumber"); + attr_gidnumber = SMB_STRDUP("gidNumber"); + } + + return True; +} + static ADS_STRUCT *ad_idmap_cached_connection(void) { ADS_STRUCT *ads; @@ -130,6 +155,11 @@ static ADS_STRUCT *ad_idmap_cached_connection(void) ads->is_mine = False; + if (!ad_idmap_check_attr_mapping(ads)) { + DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n")); + return NULL; + } + ad_idmap_ads = ads; return ads; } @@ -300,9 +330,9 @@ static NTSTATUS ad_idmap_get_id_from_sid(unid_t *unid, int *id_type, const DOM_S break; } - if (!ads_pull_uint32(ads, msg, (*id_type == ID_GROUPID) ? ATTR_GIDNUMBER : ATTR_UIDNUMBER, &uid)) { + if (!ads_pull_uint32(ads, msg, (*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber, &uid)) { DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read attribute '%s'\n", - (*id_type == ID_GROUPID) ? ATTR_GIDNUMBER : ATTR_UIDNUMBER)); + (*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber)); goto done; } @@ -341,6 +371,9 @@ static NTSTATUS ad_idmap_close(void) ad_idmap_ads = NULL; } + SAFE_FREE(attr_uidnumber); + SAFE_FREE(attr_gidnumber); + return NT_STATUS_OK; } |