r10686: Fix the build
[jelmer/samba4-debian.git] / source / winbind / wb_samba3_cmd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main winbindd samba3 server routines
4
5    Copyright (C) Stefan Metzmacher      2005
6    Copyright (C) Volker Lendecke        2005
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "smbd/service_stream.h"
25 #include "nsswitch/winbind_nss_config.h"
26 #include "nsswitch/winbindd_nss.h"
27 #include "winbind/wb_server.h"
28 #include "winbind/wb_samba3_protocol.h"
29 #include "winbind/wb_async_helpers.h"
30 #include "librpc/gen_ndr/nbt.h"
31 #include "libcli/raw/libcliraw.h"
32 #include "libcli/composite/composite.h"
33 #include "libcli/smb_composite/smb_composite.h"
34 #include "include/version.h"
35 #include "lib/events/events.h"
36
37 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
38 {
39         s3call->response.result                 = WINBINDD_OK;
40         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
41         return NT_STATUS_OK;
42 }
43
44 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
45 {
46         s3call->response.result                 = WINBINDD_OK;
47         s3call->response.data.info.winbind_separator = *lp_winbind_separator();
48         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version, SAMBA_VERSION_STRING);
49         return NT_STATUS_OK;
50 }
51
52 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
53 {
54         s3call->response.result                 = WINBINDD_OK;
55         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name, lp_workgroup());
56         return NT_STATUS_OK;
57 }
58
59 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
60 {
61         s3call->response.result                 = WINBINDD_OK;
62         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name, lp_netbios_name());
63         return NT_STATUS_OK;
64 }
65
66 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
67 {
68         s3call->response.result                 = WINBINDD_OK;
69         s3call->response.extra_data             = smbd_tmp_path(s3call,
70                                                   WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
71         NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
72         return NT_STATUS_OK;
73 }
74
75 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
76 {
77         s3call->response.result                 = WINBINDD_OK;
78         return NT_STATUS_OK;
79 }
80
81 #define null_no_memory_done(x) do { \
82         if ((x) == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } \
83         } while (0)
84
85 struct check_machacc_state {
86         struct wb_finddcs *io;
87         struct smb_composite_connect *conn;
88         struct wb_get_schannel_creds *getcreds;
89 };
90
91 static void wbsrv_samba3_check_machacc_receive_creds(struct composite_context *action);
92 static void wbsrv_samba3_check_machacc_receive_tree(struct composite_context *action);
93 static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *action);
94
95 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
96 {
97         struct composite_context *resolve_req;
98         struct check_machacc_state *state;
99         struct wbsrv_service *service =
100                 s3call->call->wbconn->listen_socket->service;
101
102         DEBUG(5, ("check_machacc called\n"));
103
104         if (service->netlogon != NULL) {
105                 talloc_free(service->netlogon);
106         }
107
108         state = talloc(s3call, struct check_machacc_state);
109         NT_STATUS_HAVE_NO_MEMORY(state);
110
111         state->io = talloc(s3call, struct wb_finddcs);
112         NT_STATUS_HAVE_NO_MEMORY(state->io);
113         s3call->private_data = state;
114
115         state->io->in.msg_ctx = s3call->call->wbconn->conn->msg_ctx;
116         state->io->in.domain = lp_workgroup();
117
118         resolve_req = wb_finddcs_send(state->io, s3call->call->event_ctx);
119         NT_STATUS_HAVE_NO_MEMORY(resolve_req);
120
121         /* setup the callbacks */
122         resolve_req->async.fn = wbsrv_samba3_check_machacc_receive_dcs;
123         resolve_req->async.private_data = s3call;
124
125         /* tell the caller we reply later */
126         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
127         return NT_STATUS_OK;
128 }
129
130 static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *action)
131 {
132         struct wbsrv_samba3_call *s3call =
133                 talloc_get_type(action->async.private_data,
134                                 struct wbsrv_samba3_call);
135         struct check_machacc_state *state =
136                 talloc_get_type(s3call->private_data,
137                                 struct check_machacc_state);
138         struct composite_context *ctx;
139         NTSTATUS status;
140
141         status = wb_finddcs_recv(action, s3call);
142
143         s3call->response.data.auth.nt_status = NT_STATUS_V(status);
144         WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
145                                 nt_errstr(status));
146         WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
147                                 nt_errstr(status));
148         s3call->response.data.auth.pam_error = nt_status_to_pam(status);
149
150         if (!NT_STATUS_IS_OK(status)) {
151                 goto done;
152         }
153
154         state->conn = talloc(state, struct smb_composite_connect);
155         if (state->conn == NULL) {
156                 status = NT_STATUS_NO_MEMORY;
157                 goto done;
158         }
159
160         state->conn->in.dest_host = state->io->out.dcs[0].address;
161         state->conn->in.port = 0;
162         state->conn->in.called_name = state->io->out.dcs[0].name;
163         state->conn->in.service = "IPC$";
164         state->conn->in.service_type = "IPC";
165         state->conn->in.workgroup = lp_workgroup();
166
167         state->conn->in.credentials = cli_credentials_init(state->conn);
168         if (state->conn->in.credentials == NULL) {
169                 status = NT_STATUS_NO_MEMORY;
170                 goto done;
171         }
172         cli_credentials_set_conf(state->conn->in.credentials);
173         cli_credentials_set_anonymous(state->conn->in.credentials);
174
175         ctx = smb_composite_connect_send(state->conn, state,
176                                          s3call->call->event_ctx);
177         if (ctx == NULL) {
178                 status = NT_STATUS_NO_MEMORY;
179                 goto done;
180         }
181
182         ctx->async.fn = wbsrv_samba3_check_machacc_receive_tree;
183         ctx->async.private_data = s3call;
184         return;
185
186  done:
187         if (!NT_STATUS_IS_OK(status)) {
188                 s3call->response.result = WINBINDD_ERROR;
189         }
190
191         status = wbsrv_send_reply(s3call->call);
192         if (!NT_STATUS_IS_OK(status)) {
193                 wbsrv_terminate_connection(s3call->call->wbconn,
194                                            "wbsrv_queue_reply() failed");
195                 return;
196         }
197 }
198
199 static void wbsrv_samba3_check_machacc_receive_tree(struct composite_context *action)
200 {
201         struct wbsrv_samba3_call *s3call =
202                 talloc_get_type(action->async.private_data,
203                                 struct wbsrv_samba3_call);
204         struct check_machacc_state *state =
205                 talloc_get_type(s3call->private_data,
206                                 struct check_machacc_state);
207         struct composite_context *ctx;
208         NTSTATUS status;
209         struct cli_credentials *creds;
210
211         status = smb_composite_connect_recv(action, state);
212         if (!NT_STATUS_IS_OK(status)) {
213                 DEBUG(5, ("Connect failed: %s\n", nt_errstr(status)));
214                 goto done;
215         }
216
217         state->getcreds = talloc(state, struct wb_get_schannel_creds);
218         null_no_memory_done(state->getcreds);
219
220         creds = cli_credentials_init(state);
221         null_no_memory_done(creds);
222         cli_credentials_set_conf(creds);
223         status = cli_credentials_set_machine_account(creds);
224         if (!NT_STATUS_IS_OK(status)) goto done;
225
226         state->getcreds->in.tree = state->conn->out.tree;
227         state->getcreds->in.creds = creds;
228
229         ctx = wb_get_schannel_creds_send(state->getcreds,
230                                          s3call->call->event_ctx);
231         null_no_memory_done(ctx);
232
233         ctx->async.fn = wbsrv_samba3_check_machacc_receive_creds;
234         ctx->async.private_data = s3call;
235
236         return;
237         
238  done:
239         s3call->response.result = WINBINDD_OK;
240
241         if (!NT_STATUS_IS_OK(status)) {
242                 s3call->response.result = WINBINDD_ERROR;
243                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
244                                         nt_errstr(status));
245                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
246                                         nt_errstr(status));
247                 s3call->response.data.auth.pam_error = nt_status_to_pam(status);
248
249         }
250
251         status = wbsrv_send_reply(s3call->call);
252         if (!NT_STATUS_IS_OK(status)) {
253                 wbsrv_terminate_connection(s3call->call->wbconn,
254                                            "wbsrv_queue_reply() failed");
255                 return;
256         }
257 }
258
259 static void delete_pipe(struct event_context *ctx, struct timed_event *te,
260                         struct timeval tv, void *p)
261 {
262         talloc_free(p);
263 }
264
265 static void wbsrv_samba3_check_machacc_receive_creds(struct composite_context *action)
266 {
267         struct wbsrv_samba3_call *s3call =
268                 talloc_get_type(action->async.private_data,
269                                 struct wbsrv_samba3_call);
270         struct check_machacc_state *state =
271                 talloc_get_type(s3call->private_data,
272                                 struct check_machacc_state);
273         struct wbsrv_service *service =
274                 s3call->call->wbconn->listen_socket->service;
275         
276         NTSTATUS status;
277         
278         status = wb_get_schannel_creds_recv(action, service);
279
280         talloc_unlink(state, state->conn->out.tree); /* The pipe owns it now */
281         state->conn->out.tree = NULL;
282
283         if (!NT_STATUS_IS_OK(status)) {
284                 /* Nasty hack awaiting a proper fix. So far we can not
285                  * delete a pipe from an async rpc callback which where we are
286                  * in right now, so delete the pipe from an event handler.. */
287                 event_add_timed(s3call->call->event_ctx, service,
288                                 timeval_zero(),
289                                 delete_pipe, state->getcreds->out.netlogon);
290                 service->netlogon = NULL;
291                 goto done;
292         }
293
294         service->netlogon = state->getcreds->out.netlogon;
295         s3call->response.result = WINBINDD_OK;
296  done:
297         if (!NT_STATUS_IS_OK(status)) {
298                 s3call->response.result = WINBINDD_ERROR;
299                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.nt_status_string,
300                                         nt_errstr(status));
301                 WBSRV_SAMBA3_SET_STRING(s3call->response.data.auth.error_string,
302                                         nt_errstr(status));
303                 s3call->response.data.auth.pam_error = nt_status_to_pam(status);
304
305         }
306
307         status = wbsrv_send_reply(s3call->call);
308         if (!NT_STATUS_IS_OK(status)) {
309                 wbsrv_terminate_connection(s3call->call->wbconn,
310                                            "wbsrv_queue_reply() failed");
311                 return;
312         }
313 }