winbind: Make wb_sids2xids_recv work on an array
[sfrench/samba-autobuild/.git] / source3 / winbindd / wb_fill_pwent.c
1 /*
2    Unix SMB/CIFS implementation.
3    async fill_pwent
4    Copyright (C) Volker Lendecke 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "librpc/gen_ndr/ndr_winbind_c.h"
23
24 struct wb_fill_pwent_state {
25         struct tevent_context *ev;
26         struct wbint_userinfo *info;
27         struct winbindd_pw *pw;
28 };
29
30 static bool fillup_pw_field(const char *lp_template,
31                             const char *username,
32                             const char *grpname,
33                             const char *domname,
34                             uid_t uid,
35                             gid_t gid,
36                             const char *in,
37                             fstring out);
38
39 static void wb_fill_pwent_sid2uid_done(struct tevent_req *subreq);
40 static void wb_fill_pwent_getgrsid_done(struct tevent_req *subreq);
41
42 struct tevent_req *wb_fill_pwent_send(TALLOC_CTX *mem_ctx,
43                                       struct tevent_context *ev,
44                                       struct wbint_userinfo *info,
45                                       struct winbindd_pw *pw)
46 {
47         struct tevent_req *req, *subreq;
48         struct wb_fill_pwent_state *state;
49
50         req = tevent_req_create(mem_ctx, &state, struct wb_fill_pwent_state);
51         if (req == NULL) {
52                 return NULL;
53         }
54         state->ev = ev;
55         state->info = info;
56         state->pw = pw;
57
58         subreq = wb_sids2xids_send(state, state->ev, &state->info->user_sid, 1);
59         if (tevent_req_nomem(subreq, req)) {
60                 return tevent_req_post(req, ev);
61         }
62         tevent_req_set_callback(subreq, wb_fill_pwent_sid2uid_done, req);
63         return req;
64 }
65
66 static void wb_fill_pwent_sid2uid_done(struct tevent_req *subreq)
67 {
68         struct tevent_req *req = tevent_req_callback_data(
69                 subreq, struct tevent_req);
70         struct wb_fill_pwent_state *state = tevent_req_data(
71                 req, struct wb_fill_pwent_state);
72         NTSTATUS status;
73         struct unixid xids[1];
74
75         status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
76         TALLOC_FREE(subreq);
77         if (tevent_req_nterror(req, status)) {
78                 return;
79         }
80
81         /*
82          * We are filtering further down in sids2xids, but that filtering
83          * depends on the actual type of the sid handed in (as determined
84          * by lookupsids). Here we need to filter for the type of object
85          * actually requested, in this case uid.
86          */
87         if (!(xids[0].type == ID_TYPE_UID || xids[0].type == ID_TYPE_BOTH)) {
88                 tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
89                 return;
90         }
91
92         state->pw->pw_uid = (uid_t)xids[0].id;
93
94         subreq = wb_getgrsid_send(state, state->ev, &state->info->group_sid, 0);
95         if (tevent_req_nomem(subreq, req)) {
96                 return;
97         }
98         tevent_req_set_callback(subreq, wb_fill_pwent_getgrsid_done, req);
99 }
100
101 static void wb_fill_pwent_getgrsid_done(struct tevent_req *subreq)
102 {
103         struct tevent_req *req = tevent_req_callback_data(
104                 subreq, struct tevent_req);
105         struct wb_fill_pwent_state *state = tevent_req_data(
106                 req, struct wb_fill_pwent_state);
107         struct winbindd_domain *domain;
108         const char *dom_name;
109         const char *grp_name;
110         fstring user_name, output_username;
111         char *mapped_name = NULL;
112         struct talloc_dict *members;
113         TALLOC_CTX *tmp_ctx = talloc_stackframe();
114         NTSTATUS status;
115         bool ok;
116
117         /* xid handling is done in getgrsid() */
118         status = wb_getgrsid_recv(subreq,
119                                   tmp_ctx,
120                                   &dom_name,
121                                   &grp_name,
122                                   &state->pw->pw_gid,
123                                   &members);
124         TALLOC_FREE(subreq);
125         if (tevent_req_nterror(req, status)) {
126                 talloc_free(tmp_ctx);
127                 return;
128         }
129
130         domain = find_domain_from_sid_noinit(&state->info->user_sid);
131         if (domain == NULL) {
132                 talloc_free(tmp_ctx);
133                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
134                 return;
135         }
136         dom_name = domain->name;
137
138         /* Username */
139
140         fstrcpy(user_name, state->info->acct_name);
141         if (!strlower_m(user_name)) {
142                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
143                 return;
144         }
145         status = normalize_name_map(state, domain, user_name, &mapped_name);
146
147         /* Basic removal of whitespace */
148         if (NT_STATUS_IS_OK(status)) {
149                 fill_domain_username(output_username, dom_name, mapped_name,
150                                      true);
151         }
152         /* Complete name replacement */
153         else if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
154                 fstrcpy(output_username, mapped_name);
155         }
156         /* No change at all */
157         else {
158                 fill_domain_username(output_username, dom_name, user_name,
159                                      true);
160         }
161
162         strlcpy(state->pw->pw_name,
163                 output_username,
164                 sizeof(state->pw->pw_name));
165         /* FIXME The full_name can be longer than 255 chars */
166         strlcpy(state->pw->pw_gecos,
167                 state->info->full_name != NULL ? state->info->full_name : "",
168                 sizeof(state->pw->pw_gecos));
169
170         /* Home directory and shell */
171         ok = fillup_pw_field(lp_template_homedir(),
172                              user_name,
173                              grp_name,
174                              dom_name,
175                              state->pw->pw_uid,
176                              state->pw->pw_gid,
177                              state->info->homedir,
178                              state->pw->pw_dir);
179         if (!ok) {
180                 talloc_free(tmp_ctx);
181                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
182                 return;
183         }
184
185         ok = fillup_pw_field(lp_template_shell(),
186                              user_name,
187                              grp_name,
188                              dom_name,
189                              state->pw->pw_uid,
190                              state->pw->pw_gid,
191                              state->info->shell,
192                              state->pw->pw_shell);
193         talloc_free(tmp_ctx);
194         if (!ok) {
195                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
196                 return;
197         }
198
199         /* Password - set to "*" as we can't generate anything useful here.
200            Authentication can be done using the pam_winbind module. */
201
202         fstrcpy(state->pw->pw_passwd, "*");
203         tevent_req_done(req);
204 }
205
206 NTSTATUS wb_fill_pwent_recv(struct tevent_req *req)
207 {
208         return tevent_req_simple_recv_ntstatus(req);
209 }
210
211 static bool fillup_pw_field(const char *lp_template,
212                             const char *username,
213                             const char *grpname,
214                             const char *domname,
215                             uid_t uid,
216                             gid_t gid,
217                             const char *in,
218                             fstring out)
219 {
220         const char *templ;
221         char *result;
222
223         if (out == NULL)
224                 return False;
225
226         templ = lp_template;
227
228         if ((in != NULL) && (in[0] != '\0') && (lp_security() == SEC_ADS)) {
229                 /*
230                  * The backend has already filled in the required value. Use
231                  * that instead of the template.
232                  */
233                 templ = in;
234         }
235
236         result = talloc_sub_specified(talloc_tos(), templ,
237                                       username, grpname, domname,
238                                       uid, gid);
239         if (result == NULL) {
240                 return False;
241         }
242
243         fstrcpy(out, result);
244         TALLOC_FREE(result);
245
246         return True;
247
248 }