r7994: This adds support in Winbindd's "security = ads"-mode to retrieve the POSIX
authorGünther Deschner <gd@samba.org>
Wed, 29 Jun 2005 14:03:53 +0000 (14:03 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:58:07 +0000 (10:58 -0500)
homedirectory and the loginshell from Active Directory's "Services for Unix".

Enable it with:

        winbind sfu support = yes

User-Accounts without SFU-Unix-Attributes will be assigned template-based
Shells and Homedirs as before.

Note that it doesn't matter which version of Services for Unix you use (2.0,
2.2, 3.0 or 3.5). Samba should detect the correct attributes (msSFULoginShell,
msSFU30LoginShell, etc.) automatically.

If you also want to share the same uid/gid-space as SFU then also use PADL's
ad-idmap-Plugin:

        idmap backend = ad

When using the idmap-plugin only those accounts will appear in Name Service
Switch that have those UNIX-attributes which avoids potential uid/gid-space
clashes between SFU-ids and automatically assigned idmap-ids.

Guenther
(This used to be commit 28b59699425b1c954d191fc0e3bd357e4a4e4cd8)

12 files changed:
source3/include/ads.h
source3/libads/ads_struct.c
source3/libads/ldap.c
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_ads.c
source3/nsswitch/winbindd_async.c
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_nss.h
source3/nsswitch/winbindd_rpc.c
source3/nsswitch/winbindd_user.c
source3/param/loadparm.c
source3/sam/idmap_ad.c

index 27f9384d5d00106bf3e3d33a758761dcc3bb8893..8f6cc6e582b4b8e2cbe3b41bce20ca27c197974e 100644 (file)
@@ -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
index e8546f86f50c7f51efb65c0d76c0a922cc71649f..d8676d050dd18b761e114369e434759e32d30a6b 100644 (file)
@@ -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);
 
index 04754f4e9e1f34e230c5324a961733b1001c45ee..12890154647431b948df8444b0b3488b63670c01 100644 (file)
@@ -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, ':');
@@ -2475,6 +2525,50 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
        return ADS_SUCCESS;
 }
 
+/**
+ * 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
index 378120c80b8c96ccd5c86f1017afe21014ee41a9..3a7728e4a2c82fb3fff2f037ddb99d13820aed71 100644 (file)
@@ -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;
index c807ec59a544f9c4dea817f43b11c8d1703371bf..868a7bc2ac6d56288826d590e9d687b9c546f764 100644 (file)
@@ -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",
index d227177ec1ccdd454e1c831aeb6fcb3f218ea81d..acae7e7f37144c188979fb0242d5dd3e7dff2037 100644 (file)
@@ -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)
 {
index 90ccb43a6ec1cea78b43396dc553b8ca95234273..730da7a9b52496c5e1ac36ff0acec9651324e2bc 100644 (file)
@@ -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;
index b249b62d69eed3dd14252ed12fe7b2e350ea1acc..cf0fae74a069210524ba5f1f02531d7fd440c0aa 100644 (file)
@@ -322,6 +322,8 @@ struct winbindd_response {
                struct {
                        fstring acct_name;
                        fstring full_name;
+                       fstring homedir;
+                       fstring shell;
                        uint32 group_rid;
                } user_info;
        } data;
index 2b4c020d889a54e82245a8b52735fb3268738259..63e24877008d2e8bdfc27acb3f31968d455bbda1 100644 (file)
@@ -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;
 }                                   
index 576ceaea235335be5abac7fc832b3db6dd30a5e1..f849bff42d21f7857f82e33cbfb6cf90ab202e7d 100644 (file)
 
 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++;
index 15eee5313c6e7396c2892ef845e17388dab37f4d..d584997f8132fb3907048510efa860314e86fea0 100644 (file)
@@ -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)
index b3b9b7ad47b1ad0abd3702842c3075525c2aa2e4..840dff025e70bfa690289d32b26a590f39fd04d7 100644 (file)
@@ -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
 #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;
 }