s3compat-only s3:winbind Split wb_process_request() into a new file
[abartlet/samba.git/.git] / source3 / winbindd / winbindd_process.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) by Tim Potter 2000-2002
7    Copyright (C) Andrew Tridgell 2002
8    Copyright (C) Jelmer Vernooij 2003
9    Copyright (C) Volker Lendecke 2004
10    Copyright (C) Andrew Bartlett 2010
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "winbindd.h"
28 #include "../../nsswitch/libwbclient/wbc_async.h"
29 #include "librpc/gen_ndr/messaging.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_WINBIND
33
34 static struct winbindd_dispatch_table {
35         enum winbindd_cmd cmd;
36         void (*fn)(struct winbindd_cli_state *state);
37         const char *winbindd_cmd_name;
38 } dispatch_table[] = {
39
40         /* Enumeration functions */
41
42         { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
43           "LIST_TRUSTDOM" },
44
45         /* Miscellaneous */
46
47         { WINBINDD_INFO, winbindd_info, "INFO" },
48         { WINBINDD_INTERFACE_VERSION, winbindd_interface_version,
49           "INTERFACE_VERSION" },
50         { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
51         { WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
52         { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
53         { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
54           "WINBINDD_PRIV_PIPE_DIR" },
55
56         /* Credential cache access */
57         { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" },
58         { WINBINDD_CCACHE_SAVE, winbindd_ccache_save, "CCACHE_SAVE" },
59
60         /* WINS functions */
61
62         { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" },
63         { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" },
64
65         /* End of list */
66
67         { WINBINDD_NUM_CMDS, NULL, "NONE" }
68 };
69
70 struct winbindd_async_dispatch_table {
71         enum winbindd_cmd cmd;
72         const char *cmd_name;
73         struct tevent_req *(*send_req)(TALLOC_CTX *mem_ctx,
74                                        struct tevent_context *ev,
75                                        struct winbindd_cli_state *cli,
76                                        struct winbindd_request *request);
77         NTSTATUS (*recv_req)(struct tevent_req *req,
78                              struct winbindd_response *presp);
79 };
80
81 static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
82         { WINBINDD_PING, "PING",
83           wb_ping_send, wb_ping_recv },
84         { WINBINDD_LOOKUPSID, "LOOKUPSID",
85           winbindd_lookupsid_send, winbindd_lookupsid_recv },
86         { WINBINDD_LOOKUPNAME, "LOOKUPNAME",
87           winbindd_lookupname_send, winbindd_lookupname_recv },
88         { WINBINDD_SID_TO_UID, "SID_TO_UID",
89           winbindd_sid_to_uid_send, winbindd_sid_to_uid_recv },
90         { WINBINDD_SID_TO_GID, "SID_TO_GID",
91           winbindd_sid_to_gid_send, winbindd_sid_to_gid_recv },
92         { WINBINDD_UID_TO_SID, "UID_TO_SID",
93           winbindd_uid_to_sid_send, winbindd_uid_to_sid_recv },
94         { WINBINDD_GID_TO_SID, "GID_TO_SID",
95           winbindd_gid_to_sid_send, winbindd_gid_to_sid_recv },
96         { WINBINDD_GETPWSID, "GETPWSID",
97           winbindd_getpwsid_send, winbindd_getpwsid_recv },
98         { WINBINDD_GETPWNAM, "GETPWNAM",
99           winbindd_getpwnam_send, winbindd_getpwnam_recv },
100         { WINBINDD_GETPWUID, "GETPWUID",
101           winbindd_getpwuid_send, winbindd_getpwuid_recv },
102         { WINBINDD_GETSIDALIASES, "GETSIDALIASES",
103           winbindd_getsidaliases_send, winbindd_getsidaliases_recv },
104         { WINBINDD_GETUSERDOMGROUPS, "GETUSERDOMGROUPS",
105           winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv },
106         { WINBINDD_GETGROUPS, "GETGROUPS",
107           winbindd_getgroups_send, winbindd_getgroups_recv },
108         { WINBINDD_SHOW_SEQUENCE, "SHOW_SEQUENCE",
109           winbindd_show_sequence_send, winbindd_show_sequence_recv },
110         { WINBINDD_GETGRGID, "GETGRGID",
111           winbindd_getgrgid_send, winbindd_getgrgid_recv },
112         { WINBINDD_GETGRNAM, "GETGRNAM",
113           winbindd_getgrnam_send, winbindd_getgrnam_recv },
114         { WINBINDD_GETUSERSIDS, "GETUSERSIDS",
115           winbindd_getusersids_send, winbindd_getusersids_recv },
116         { WINBINDD_LOOKUPRIDS, "LOOKUPRIDS",
117           winbindd_lookuprids_send, winbindd_lookuprids_recv },
118         { WINBINDD_SETPWENT, "SETPWENT",
119           winbindd_setpwent_send, winbindd_setpwent_recv },
120         { WINBINDD_GETPWENT, "GETPWENT",
121           winbindd_getpwent_send, winbindd_getpwent_recv },
122         { WINBINDD_ENDPWENT, "ENDPWENT",
123           winbindd_endpwent_send, winbindd_endpwent_recv },
124         { WINBINDD_DSGETDCNAME, "DSGETDCNAME",
125           winbindd_dsgetdcname_send, winbindd_dsgetdcname_recv },
126         { WINBINDD_GETDCNAME, "GETDCNAME",
127           winbindd_getdcname_send, winbindd_getdcname_recv },
128         { WINBINDD_SETGRENT, "SETGRENT",
129           winbindd_setgrent_send, winbindd_setgrent_recv },
130         { WINBINDD_GETGRENT, "GETGRENT",
131           winbindd_getgrent_send, winbindd_getgrent_recv },
132         { WINBINDD_ENDGRENT, "ENDGRENT",
133           winbindd_endgrent_send, winbindd_endgrent_recv },
134         { WINBINDD_LIST_USERS, "LIST_USERS",
135           winbindd_list_users_send, winbindd_list_users_recv },
136         { WINBINDD_LIST_GROUPS, "LIST_GROUPS",
137           winbindd_list_groups_send, winbindd_list_groups_recv },
138         { WINBINDD_CHECK_MACHACC, "CHECK_MACHACC",
139           winbindd_check_machine_acct_send, winbindd_check_machine_acct_recv },
140         { WINBINDD_PING_DC, "PING_DC",
141           winbindd_ping_dc_send, winbindd_ping_dc_recv },
142         { WINBINDD_PAM_AUTH, "PAM_AUTH",
143           winbindd_pam_auth_send, winbindd_pam_auth_recv },
144         { WINBINDD_PAM_LOGOFF, "PAM_LOGOFF",
145           winbindd_pam_logoff_send, winbindd_pam_logoff_recv },
146         { WINBINDD_PAM_CHAUTHTOK, "PAM_CHAUTHTOK",
147           winbindd_pam_chauthtok_send, winbindd_pam_chauthtok_recv },
148         { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, "PAM_CHNG_PSWD_AUTH_CRAP",
149           winbindd_pam_chng_pswd_auth_crap_send,
150           winbindd_pam_chng_pswd_auth_crap_recv },
151
152         { 0, NULL, NULL, NULL }
153 };
154
155 static struct winbindd_async_dispatch_table async_priv_table[] = {
156         { WINBINDD_ALLOCATE_UID, "ALLOCATE_UID",
157           winbindd_allocate_uid_send, winbindd_allocate_uid_recv },
158         { WINBINDD_ALLOCATE_GID, "ALLOCATE_GID",
159           winbindd_allocate_gid_send, winbindd_allocate_gid_recv },
160         { WINBINDD_CHANGE_MACHACC, "CHANGE_MACHACC",
161           winbindd_change_machine_acct_send, winbindd_change_machine_acct_recv },
162         { WINBINDD_PAM_AUTH_CRAP, "PAM_AUTH_CRAP",
163           winbindd_pam_auth_crap_send, winbindd_pam_auth_crap_recv },
164
165         { 0, NULL, NULL, NULL }
166 };
167
168 static void wb_request_done(struct tevent_req *req);
169
170 void wb_process_request(struct winbindd_cli_state *state)
171 {
172         struct winbindd_dispatch_table *table = dispatch_table;
173         struct winbindd_async_dispatch_table *atable;
174
175         state->mem_ctx = talloc_named(state, 0, "winbind request");
176         if (state->mem_ctx == NULL)
177                 return;
178
179         /* Remember who asked us. */
180         state->pid = state->request->pid;
181
182         state->cmd_name = "unknown request";
183         state->recv_fn = NULL;
184
185         /* Process command */
186
187         for (atable = async_nonpriv_table; atable->send_req; atable += 1) {
188                 if (state->request->cmd == atable->cmd) {
189                         break;
190                 }
191         }
192
193         if ((atable->send_req == NULL) && state->privileged) {
194                 for (atable = async_priv_table; atable->send_req;
195                      atable += 1) {
196                         if (state->request->cmd == atable->cmd) {
197                                 break;
198                         }
199                 }
200         }
201
202         if (atable->send_req != NULL) {
203                 struct tevent_req *req;
204
205                 state->cmd_name = atable->cmd_name;
206                 state->recv_fn = atable->recv_req;
207
208                 DEBUG(10, ("wb_process_request: Handling async request %d:%s\n",
209                            (int)state->pid, state->cmd_name));
210
211                 req = atable->send_req(state->mem_ctx, winbind_event_context(),
212                                        state, state->request);
213                 if (req == NULL) {
214                         DEBUG(0, ("wb_process_request: atable->send failed for "
215                                   "%s\n", atable->cmd_name));
216                         request_error(state);
217                         return;
218                 }
219                 tevent_req_set_callback(req, wb_request_done, state);
220                 return;
221         }
222
223         state->response = talloc_zero(state->mem_ctx,
224                                       struct winbindd_response);
225         if (state->response == NULL) {
226                 DEBUG(10, ("talloc failed\n"));
227                 winbindd_remove_client(state);
228                 return;
229         }
230         state->response->result = WINBINDD_PENDING;
231         state->response->length = sizeof(struct winbindd_response);
232
233         for (table = dispatch_table; table->fn; table++) {
234                 if (state->request->cmd == table->cmd) {
235                         DEBUG(10,("wb_process_request: request fn %s\n",
236                                   table->winbindd_cmd_name ));
237                         state->cmd_name = table->winbindd_cmd_name;
238                         table->fn(state);
239                         break;
240                 }
241         }
242
243         if (!table->fn) {
244                 DEBUG(10,("wb_process_request: unknown request fn number %d\n",
245                           (int)state->request->cmd ));
246                 request_error(state);
247         }
248 }
249
250 static void wb_request_done(struct tevent_req *req)
251 {
252         struct winbindd_cli_state *state = tevent_req_callback_data(
253                 req, struct winbindd_cli_state);
254         NTSTATUS status;
255
256         state->response = talloc_zero(state->mem_ctx,
257                                       struct winbindd_response);
258         if (state->response == NULL) {
259                 DEBUG(0, ("wb_request_done[%d:%s]: talloc_zero failed - removing client\n",
260                           (int)state->pid, state->cmd_name));
261                 winbindd_remove_client(state);
262                 return;
263         }
264         state->response->result = WINBINDD_PENDING;
265         state->response->length = sizeof(struct winbindd_response);
266
267         status = state->recv_fn(req, state->response);
268         TALLOC_FREE(req);
269
270         DEBUG(10,("wb_request_done[%d:%s]: %s\n",
271                   (int)state->pid, state->cmd_name, nt_errstr(status)));
272
273         if (!NT_STATUS_IS_OK(status)) {
274                 request_error(state);
275                 return;
276         }
277         request_ok(state);
278 }
279
280 void request_error(struct winbindd_cli_state *state)
281 {
282         SMB_ASSERT(state->response->result == WINBINDD_PENDING);
283         state->response->result = WINBINDD_ERROR;
284         request_finished(state);
285 }
286
287 void request_ok(struct winbindd_cli_state *state)
288 {
289         SMB_ASSERT(state->response->result == WINBINDD_PENDING);
290         state->response->result = WINBINDD_OK;
291         request_finished(state);
292 }