r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[vlendec/samba-autobuild/.git] / source3 / nsswitch / winbindd_user.c
index 55b63a81827a032f1f5b1dcde4340c9f7767646f..8a0ebbafa50ee414def303f804b6f92e8e767e98 100644 (file)
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
-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 && (get_nss_info(domname))) {
+               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 talloc_sub_specified() below. */
 
+       templ = talloc_sub_specified(NULL, lp_template, username, domname,
+                                    uid, gid);
+               
+       if (!templ)
+               return False;
+
+       safe_strcpy(out, templ, sizeof(fstring) - 1);
+       TALLOC_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)
@@ -62,7 +96,7 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
 
        /* Username */
 
-       fill_domain_username(output_username, dom_name, user_name); 
+       fill_domain_username(output_username, dom_name, user_name, True); 
 
        safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
        
@@ -74,34 +108,18 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
           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, 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.
+       /* Password - set to "*" as we can't generate anything useful here.
           Authentication can be done using the pam_winbind module. */
 
-       safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+       safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
 
        return True;
 }
@@ -136,6 +154,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,17 +171,22 @@ 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;
        gid_t gid;
 };
 
-static void getpwsid_queryuser_recv(void *private, BOOL success,
+static void getpwsid_queryuser_recv(void *private_data, BOOL success,
                                    const char *acct_name,
-                                   const char *full_name, uint32 group_rid);
-static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid);
-static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid);
+                                   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);
 
 static void winbindd_getpwsid(struct winbindd_cli_state *state,
                              const DOM_SID *sid)
@@ -192,12 +217,16 @@ static void winbindd_getpwsid(struct winbindd_cli_state *state,
        request_error(state);
 }
        
-static void getpwsid_queryuser_recv(void *private, BOOL success,
+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)
 {
+       fstring username;
        struct getpwsid_state *s =
-               talloc_get_type_abort(private, struct getpwsid_state);
+               talloc_get_type_abort(private_data, struct getpwsid_state);
 
        if (!success) {
                DEBUG(5, ("Could not query user %s\\%s\n", s->domain->name,
@@ -206,8 +235,12 @@ static void getpwsid_queryuser_recv(void *private, BOOL success,
                return;
        }
 
-       s->username = talloc_strdup(s->state->mem_ctx, acct_name);
+       fstrcpy( username, acct_name );
+       strlower_m( username );
+       s->username = talloc_strdup(s->state->mem_ctx, username);
        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);
 
@@ -215,10 +248,10 @@ static void getpwsid_queryuser_recv(void *private, BOOL success,
                               getpwsid_sid2uid_recv, s);
 }
 
-static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid)
+static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid)
 {
        struct getpwsid_state *s =
-               talloc_get_type_abort(private, struct getpwsid_state);
+               talloc_get_type_abort(private_data, struct getpwsid_state);
 
        if (!success) {
                DEBUG(5, ("Could not query user's %s\\%s uid\n",
@@ -232,14 +265,12 @@ static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid)
                               getpwsid_sid2gid_recv, s);
 }
 
-static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
+static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
 {
        struct getpwsid_state *s =
-               talloc_get_type_abort(private, struct getpwsid_state);
+               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",
@@ -252,41 +283,26 @@ static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
        pw = &s->state->response.data.pw;
        pw->pw_uid = s->uid;
        pw->pw_gid = s->gid;
-       fill_domain_username(output_username, s->domain->name, s->username); 
+       fill_domain_username(output_username, s->domain->name, s->username, True); 
        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.
+       /* Password - set to "*" as we can't generate anything useful here.
           Authentication can be done using the pam_winbind module. */
 
-       safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+       safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
 
        request_ok(s->state);
        return;
@@ -297,7 +313,7 @@ static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
 
 /* Return a password structure from a username.  */
 
-static void getpwnam_name2sid_recv(void *private, BOOL success,
+static void getpwnam_name2sid_recv(void *private_data, BOOL success,
                                   const DOM_SID *sid, enum SID_NAME_USE type);
 
 void winbindd_getpwnam(struct winbindd_cli_state *state)
@@ -313,7 +329,7 @@ void winbindd_getpwnam(struct winbindd_cli_state *state)
 
        if (!parse_domain_user(state->request.data.username, domname,
                               username)) {
-               DEBUG(0, ("Could not parse domain user: %s\n",
+               DEBUG(5, ("Could not parse domain user: %s\n",
                          state->request.data.username));
                request_error(state);
                return;
@@ -343,10 +359,10 @@ void winbindd_getpwnam(struct winbindd_cli_state *state)
                                  getpwnam_name2sid_recv, state);
 }
 
-static void getpwnam_name2sid_recv(void *private, BOOL success,
+static void getpwnam_name2sid_recv(void *private_data, BOOL success,
                                   const DOM_SID *sid, enum SID_NAME_USE type)
 {
-       struct winbindd_cli_state *state = private;
+       struct winbindd_cli_state *state = private_data;
 
        if (!success) {
                DEBUG(5, ("Could not lookup name for user %s\n",
@@ -383,7 +399,7 @@ void winbindd_getpwuid(struct winbindd_cli_state *state)
                  (unsigned long)state->request.data.uid));
 
        status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
-                                 ID_QUERY_ONLY | ID_CACHE_ONLY);
+                                 IDMAP_FLAG_QUERY_ONLY | IDMAP_FLAG_CACHE_ONLY);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5, ("Could not find SID for uid %lu\n",
@@ -401,7 +417,7 @@ void winbindd_getpwuid(struct winbindd_cli_state *state)
 
 /* Rewind file pointer for ntdom passwd database */
 
-void winbindd_setpwent(struct winbindd_cli_state *state)
+static BOOL winbindd_setpwent_internal(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
         
@@ -410,8 +426,7 @@ void winbindd_setpwent(struct winbindd_cli_state *state)
        /* Check user has enabled this */
         
        if (!lp_winbind_enum_users()) {
-               request_error(state);
-               return;
+               return False;
        }
 
        /* Free old static data if it exists */
@@ -425,7 +440,7 @@ void winbindd_setpwent(struct winbindd_cli_state *state)
        /* add any local users we have */
                
        if ( (domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL )
-               return WINBINDD_ERROR;
+               return False;
                 
        ZERO_STRUCTP(domain_state);
 
@@ -453,8 +468,7 @@ void winbindd_setpwent(struct winbindd_cli_state *state)
                 
                if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
                        DEBUG(0, ("malloc failed\n"));
-                       request_error(state);
-                       return;
+                       return False;
                }
                 
                ZERO_STRUCTP(domain_state);
@@ -467,7 +481,16 @@ void winbindd_setpwent(struct winbindd_cli_state *state)
        }
         
        state->getpwent_initialized = True;
-       request_ok(state);
+       return True;
+}
+
+void winbindd_setpwent(struct winbindd_cli_state *state)
+{
+       if (winbindd_setpwent_internal(state)) {
+               request_ok(state);
+       } else {
+               request_error(state);
+       }
 }
 
 /* Close file pointer to ntdom passwd database */
@@ -493,7 +516,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
        uint32 num_entries;
        WINBIND_USERINFO *info;
        struct getpwent_user *name_list = NULL;
-       BOOL result = False;
        struct winbindd_domain *domain;
        struct winbindd_methods *methods;
        unsigned int i;
@@ -521,17 +543,19 @@ static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
        status = methods->query_user_list(domain, mem_ctx, &num_entries, 
                                          &info);
                
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10,("get_sam_user_entries: query_user_list failed with %s\n",
+                       nt_errstr(status) ));
+               return False;
+       }
+
        if (num_entries) {
-               struct getpwent_user *tnl;
+               name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user, ent->num_sam_entries + num_entries);
                
-               tnl = SMB_REALLOC_ARRAY(name_list, struct getpwent_user, ent->num_sam_entries + num_entries);
-               
-               if (!tnl) {
+               if (!name_list) {
                        DEBUG(0,("get_sam_user_entries realloc failed.\n"));
-                       SAFE_FREE(name_list);
-                       goto done;
-               } else
-                       name_list = tnl;
+                       return False;
+               }
        }
 
        for (i = 0; i < num_entries; i++) {
@@ -548,7 +572,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);
@@ -562,11 +599,7 @@ static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
        
        ent->sam_entries = name_list;
        ent->sam_entry_index = 0;
-       result = ent->num_sam_entries > 0;
-
- done:
-
-       return result;
+       return ent->num_sam_entries > 0;
 }
 
 /* Fetch next passwd entry from ntdom database */
@@ -592,18 +625,18 @@ void winbindd_getpwent(struct winbindd_cli_state *state)
 
        num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
        
-       if ((state->response.extra_data = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users)) == NULL) {
+       if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users)) == NULL) {
                request_error(state);
                return;
        }
 
-       memset(state->response.extra_data, 0, num_users * 
+       memset(state->response.extra_data.data, 0, num_users * 
               sizeof(struct winbindd_pw));
 
-       user_list = (struct winbindd_pw *)state->response.extra_data;
+       user_list = (struct winbindd_pw *)state->response.extra_data.data;
 
        if (!state->getpwent_initialized)
-               winbindd_setpwent(state);
+               winbindd_setpwent_internal(state);
        
        if (!(ent = state->getpwent_state)) {
                request_error(state);
@@ -651,6 +684,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++;
@@ -685,7 +720,7 @@ void winbindd_list_users(struct winbindd_cli_state *state)
        WINBIND_USERINFO *info;
        const char *which_domain;
        uint32 num_entries = 0, total_entries = 0;
-       char *ted, *extra_data = NULL;
+       char *extra_data = NULL;
        int extra_data_len = 0;
        enum winbindd_result rv = WINBINDD_ERROR;
 
@@ -715,21 +750,23 @@ void winbindd_list_users(struct winbindd_cli_state *state)
                status = methods->query_user_list(domain, state->mem_ctx, 
                                                  &num_entries, &info);
 
+               if (!NT_STATUS_IS_OK(status)) {
+                       continue;
+               }
+
                if (num_entries == 0)
                        continue;
 
                /* Allocate some memory for extra data */
                total_entries += num_entries;
                        
-               ted = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
+               extra_data = SMB_REALLOC(extra_data, sizeof(fstring) * total_entries);
                        
-               if (!ted) {
+               if (!extra_data) {
                        DEBUG(0,("failed to enlarge buffer!\n"));
-                       SAFE_FREE(extra_data);
                        goto done;
-               } else 
-                       extra_data = ted;
-                       
+               }
+
                /* Pack user list into extra data fields */
                        
                for (i = 0; i < num_entries; i++) {
@@ -741,7 +778,7 @@ void winbindd_list_users(struct winbindd_cli_state *state)
                                fstrcpy(acct_name, info[i].acct_name);
                        }
                        
-                       fill_domain_username(name, domain->name, acct_name);
+                       fill_domain_username(name, domain->name, acct_name, True);
                        
                                /* Append to extra data */
                        memcpy(&extra_data[extra_data_len], name, 
@@ -755,7 +792,7 @@ void winbindd_list_users(struct winbindd_cli_state *state)
 
        if (extra_data) {
                extra_data[extra_data_len - 1] = '\0';
-               state->response.extra_data = extra_data;
+               state->response.extra_data.data = extra_data;
                state->response.length += extra_data_len;
        }