summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/ads.h24
-rw-r--r--source3/libads/ads_struct.c5
-rw-r--r--source3/libads/ldap.c96
-rw-r--r--source3/nsswitch/winbindd.h4
-rw-r--r--source3/nsswitch/winbindd_ads.c24
-rw-r--r--source3/nsswitch/winbindd_async.c9
-rw-r--r--source3/nsswitch/winbindd_cache.c8
-rw-r--r--source3/nsswitch/winbindd_nss.h2
-rw-r--r--source3/nsswitch/winbindd_rpc.c9
-rw-r--r--source3/nsswitch/winbindd_user.c118
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/sam/idmap_ad.c47
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;
}