s3:winbind: Log client process name
[samba.git] / source3 / winbindd / winbindd_getgroups.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of WINBINDD_GETGROUPS
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 "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
23
24 struct winbindd_getgroups_state {
25         struct tevent_context *ev;
26         fstring namespace;
27         fstring domname;
28         fstring username;
29         struct dom_sid sid;
30         enum lsa_SidType type;
31         int num_sids;
32         struct dom_sid *sids;
33         int num_gids;
34         gid_t *gids;
35 };
36
37 static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq);
38 static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq);
39 static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq);
40
41 struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
42                                            struct tevent_context *ev,
43                                            struct winbindd_cli_state *cli,
44                                            struct winbindd_request *request)
45 {
46         struct tevent_req *req, *subreq;
47         struct winbindd_getgroups_state *state;
48         char *domuser, *mapped_user;
49         NTSTATUS status;
50         bool ok;
51
52         req = tevent_req_create(mem_ctx, &state,
53                                 struct winbindd_getgroups_state);
54         if (req == NULL) {
55                 return NULL;
56         }
57         state->ev = ev;
58
59         /* Ensure null termination */
60         request->data.username[sizeof(request->data.username)-1]='\0';
61
62         DBG_NOTICE("[%s (%u)] getgroups %s\n",
63                    cli->client_name,
64                    (unsigned int)cli->pid,
65                    request->data.username);
66
67         domuser = request->data.username;
68
69         status = normalize_name_unmap(state, domuser, &mapped_user);
70
71         if (NT_STATUS_IS_OK(status)
72             || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
73                 /* normalize_name_unmapped did something */
74                 domuser = mapped_user;
75         }
76
77         ok = parse_domain_user(domuser,
78                                state->namespace,
79                                state->domname,
80                                state->username);
81         if (!ok) {
82                 DEBUG(5, ("Could not parse domain user: %s\n", domuser));
83                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
84                 return tevent_req_post(req, ev);
85         }
86
87         subreq = wb_lookupname_send(state, ev,
88                                     state->namespace,
89                                     state->domname,
90                                     state->username,
91                                     LOOKUP_NAME_NO_NSS);
92         if (tevent_req_nomem(subreq, req)) {
93                 return tevent_req_post(req, ev);
94         }
95         tevent_req_set_callback(subreq, winbindd_getgroups_lookupname_done,
96                                 req);
97         return req;
98 }
99
100 static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq)
101 {
102         struct tevent_req *req = tevent_req_callback_data(
103                 subreq, struct tevent_req);
104         struct winbindd_getgroups_state *state = tevent_req_data(
105                 req, struct winbindd_getgroups_state);
106         NTSTATUS status;
107
108         status = wb_lookupname_recv(subreq, &state->sid, &state->type);
109         TALLOC_FREE(subreq);
110         if (tevent_req_nterror(req, status)) {
111                 return;
112         }
113
114         subreq = wb_gettoken_send(state, state->ev, &state->sid, true);
115         if (tevent_req_nomem(subreq, req)) {
116                 return;
117         }
118         tevent_req_set_callback(subreq, winbindd_getgroups_gettoken_done, req);
119 }
120
121 static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq)
122 {
123         struct tevent_req *req = tevent_req_callback_data(
124                 subreq, struct tevent_req);
125         struct winbindd_getgroups_state *state = tevent_req_data(
126                 req, struct winbindd_getgroups_state);
127         NTSTATUS status;
128
129         status = wb_gettoken_recv(subreq, state, &state->num_sids,
130                                   &state->sids);
131         TALLOC_FREE(subreq);
132         if (tevent_req_nterror(req, status)) {
133                 return;
134         }
135
136         /*
137          * Convert the group SIDs to gids. state->sids[0] contains the user
138          * sid. If the idmap backend uses ID_TYPE_BOTH, we might need the
139          * the id of the user sid in the list of group sids, so map the
140          * complete token.
141          */
142
143         subreq = wb_sids2xids_send(state, state->ev,
144                                    state->sids, state->num_sids);
145         if (tevent_req_nomem(subreq, req)) {
146                 return;
147         }
148         tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req);
149 }
150
151 static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq)
152 {
153         struct tevent_req *req = tevent_req_callback_data(
154                 subreq, struct tevent_req);
155         struct winbindd_getgroups_state *state = tevent_req_data(
156                 req, struct winbindd_getgroups_state);
157         NTSTATUS status;
158         struct unixid *xids;
159         int i;
160
161         xids = talloc_array(state, struct unixid, state->num_sids);
162         if (tevent_req_nomem(xids, req)) {
163                 return;
164         }
165         for (i=0; i < state->num_sids; i++) {
166                 xids[i].type = ID_TYPE_NOT_SPECIFIED;
167                 xids[i].id = UINT32_MAX;
168         }
169
170         status = wb_sids2xids_recv(subreq, xids, state->num_sids);
171         TALLOC_FREE(subreq);
172         if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) ||
173             NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
174         {
175                 status = NT_STATUS_OK;
176         }
177         if (tevent_req_nterror(req, status)) {
178                 return;
179         }
180
181         state->gids = talloc_array(state, gid_t, state->num_sids);
182         if (tevent_req_nomem(state->gids, req)) {
183                 return;
184         }
185         state->num_gids = 0;
186
187         for (i=0; i < state->num_sids; i++) {
188                 bool include_gid = false;
189                 const char *debug_missing = NULL;
190
191                 switch (xids[i].type) {
192                 case ID_TYPE_NOT_SPECIFIED:
193                         debug_missing = "not specified";
194                         break;
195                 case ID_TYPE_UID:
196                         if (i != 0) {
197                                 debug_missing = "uid";
198                         }
199                         break;
200                 case ID_TYPE_GID:
201                 case ID_TYPE_BOTH:
202                         include_gid = true;
203                         break;
204                 }
205
206                 if (!include_gid) {
207                         if (debug_missing == NULL) {
208                                 continue;
209                         }
210
211                         DEBUG(10, ("WARNING: skipping unix id (%u) for sid %s "
212                                    "from group list because the idmap type "
213                                    "is %s. "
214                                    "This might be a security problem when ACLs "
215                                    "contain DENY ACEs!\n",
216                                    (unsigned)xids[i].id,
217                                    sid_string_tos(&state->sids[i]),
218                                    debug_missing));
219                         continue;
220                 }
221
222                 state->gids[state->num_gids] = (gid_t)xids[i].id;
223                 state->num_gids += 1;
224         }
225
226         /*
227          * This should not fail, as it does not do any reallocation,
228          * just updating the talloc size.
229          */
230         state->gids = talloc_realloc(state, state->gids, gid_t, state->num_gids);
231         if (tevent_req_nomem(state->gids, req)) {
232                 return;
233         }
234
235         tevent_req_done(req);
236 }
237
238 NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
239                                  struct winbindd_response *response)
240 {
241         struct winbindd_getgroups_state *state = tevent_req_data(
242                 req, struct winbindd_getgroups_state);
243         NTSTATUS status;
244
245         if (tevent_req_is_nterror(req, &status)) {
246                 DEBUG(5, ("Could not convert sid %s: %s\n",
247                           sid_string_dbg(&state->sid), nt_errstr(status)));
248                 return status;
249         }
250
251         response->data.num_entries = state->num_gids;
252
253         if (state->num_gids > 0) {
254                 response->extra_data.data = talloc_move(response,
255                                                         &state->gids);
256                 response->length += state->num_gids * sizeof(gid_t);
257         }
258         return NT_STATUS_OK;
259 }