0f927dfc3a1396789eb49b5fcbd4dce093b74560
[kai/samba.git] / source4 / 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 #include "librpc/gen_ndr/ndr_netlogon.h"
37
38 static void wbsrv_samba3_async_epilogue(NTSTATUS status,
39                                         struct wbsrv_samba3_call *s3call)
40 {
41         if (!NT_STATUS_IS_OK(status)) {
42                 struct winbindd_response *resp = &s3call->response;
43                 resp->result = WINBINDD_ERROR;
44                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
45                                         nt_errstr(status));
46                 WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
47                                         nt_errstr(status));
48                 resp->data.auth.pam_error = nt_status_to_pam(status);
49         }
50
51         status = wbsrv_send_reply(s3call->call);
52         if (!NT_STATUS_IS_OK(status)) {
53                 wbsrv_terminate_connection(s3call->call->wbconn,
54                                            "wbsrv_queue_reply() failed");
55         }
56 }
57
58 NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
59 {
60         s3call->response.result                 = WINBINDD_OK;
61         s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
62         return NT_STATUS_OK;
63 }
64
65 NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
66 {
67         s3call->response.result                 = WINBINDD_OK;
68         s3call->response.data.info.winbind_separator = *lp_winbind_separator();
69         WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
70                                 SAMBA_VERSION_STRING);
71         return NT_STATUS_OK;
72 }
73
74 NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
75 {
76         s3call->response.result                 = WINBINDD_OK;
77         WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
78                                 lp_workgroup());
79         return NT_STATUS_OK;
80 }
81
82 NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
83 {
84         s3call->response.result                 = WINBINDD_OK;
85         WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
86                                 lp_netbios_name());
87         return NT_STATUS_OK;
88 }
89
90 NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
91 {
92         s3call->response.result                 = WINBINDD_OK;
93         s3call->response.extra_data =
94                 smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
95         NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
96         return NT_STATUS_OK;
97 }
98
99 NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
100 {
101         s3call->response.result                 = WINBINDD_OK;
102         return NT_STATUS_OK;
103 }
104
105 static void checkmachacc_recv_creds(struct composite_context *ctx);
106
107 NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
108 {
109         struct composite_context *ctx;
110
111         DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
112
113         ctx = wb_cmd_checkmachacc_send(s3call->call);
114         NT_STATUS_HAVE_NO_MEMORY(ctx);
115
116         ctx->async.fn = checkmachacc_recv_creds;
117         ctx->async.private_data = s3call;
118         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
119         return NT_STATUS_OK;
120 }
121         
122 static void checkmachacc_recv_creds(struct composite_context *ctx)
123 {
124         struct wbsrv_samba3_call *s3call =
125                 talloc_get_type(ctx->async.private_data,
126                                 struct wbsrv_samba3_call);
127         NTSTATUS status;
128
129         status = wb_cmd_checkmachacc_recv(ctx);
130
131         s3call->response.result = WINBINDD_OK;
132         wbsrv_samba3_async_epilogue(status, s3call);
133 }
134
135 static void getdcname_recv_dc(struct composite_context *ctx);
136
137 NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
138 {
139         struct composite_context *ctx;
140         struct wbsrv_service *service =
141                 s3call->call->wbconn->listen_socket->service;
142
143         DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
144
145         ctx = wb_cmd_getdcname_send(service, service->domains,
146                                     s3call->request.domain_name);
147         NT_STATUS_HAVE_NO_MEMORY(ctx);
148
149         ctx->async.fn = getdcname_recv_dc;
150         ctx->async.private_data = s3call;
151         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
152         return NT_STATUS_OK;
153 }
154
155 static void getdcname_recv_dc(struct composite_context *ctx)
156 {
157         struct wbsrv_samba3_call *s3call =
158                 talloc_get_type(ctx->async.private_data,
159                                 struct wbsrv_samba3_call);
160         const char *dcname;
161         NTSTATUS status;
162
163         status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
164         if (!NT_STATUS_IS_OK(status)) goto done;
165
166         s3call->response.result = WINBINDD_OK;
167         WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
168
169  done:
170         wbsrv_samba3_async_epilogue(status, s3call);
171 }
172
173 static void userdomgroups_recv_groups(struct composite_context *ctx);
174
175 NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
176 {
177         struct composite_context *ctx;
178         struct dom_sid *sid;
179
180         DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
181
182         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
183         if (sid == NULL) {
184                 DEBUG(5, ("Could not parse sid %s\n",
185                           s3call->request.data.sid));
186                 return NT_STATUS_NO_MEMORY;
187         }
188
189         ctx = wb_cmd_userdomgroups_send(
190                 s3call->call->wbconn->listen_socket->service, sid);
191         NT_STATUS_HAVE_NO_MEMORY(ctx);
192
193         ctx->async.fn = userdomgroups_recv_groups;
194         ctx->async.private_data = s3call;
195         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
196         return NT_STATUS_OK;
197 }
198
199 static void userdomgroups_recv_groups(struct composite_context *ctx)
200 {
201         struct wbsrv_samba3_call *s3call =
202                 talloc_get_type(ctx->async.private_data,
203                                 struct wbsrv_samba3_call);
204         int i, num_sids;
205         struct dom_sid **sids;
206         char *sids_string;
207         NTSTATUS status;
208
209         status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
210         if (!NT_STATUS_IS_OK(status)) goto done;
211
212         sids_string = talloc_strdup(s3call, "");
213         if (sids_string == NULL) {
214                 status = NT_STATUS_NO_MEMORY;
215                 goto done;
216         }
217
218         for (i=0; i<num_sids; i++) {
219                 sids_string = talloc_asprintf_append(
220                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
221         }
222
223         if (sids_string == NULL) {
224                 status = NT_STATUS_NO_MEMORY;
225                 goto done;
226         }
227
228         s3call->response.result = WINBINDD_OK;
229         s3call->response.extra_data = sids_string;
230         s3call->response.length += strlen(sids_string)+1;
231         s3call->response.data.num_entries = num_sids;
232
233  done:
234         wbsrv_samba3_async_epilogue(status, s3call);
235 }
236
237 static void usersids_recv_sids(struct composite_context *ctx);
238
239 NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
240 {
241         struct composite_context *ctx;
242         struct dom_sid *sid;
243
244         DEBUG(5, ("wbsrv_samba3_usersids called\n"));
245
246         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
247         if (sid == NULL) {
248                 DEBUG(5, ("Could not parse sid %s\n",
249                           s3call->request.data.sid));
250                 return NT_STATUS_NO_MEMORY;
251         }
252
253         ctx = wb_cmd_usersids_send(
254                 s3call->call->wbconn->listen_socket->service, sid);
255         NT_STATUS_HAVE_NO_MEMORY(ctx);
256
257         ctx->async.fn = usersids_recv_sids;
258         ctx->async.private_data = s3call;
259         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
260         return NT_STATUS_OK;
261 }
262
263 static void usersids_recv_sids(struct composite_context *ctx)
264 {
265         struct wbsrv_samba3_call *s3call =
266                 talloc_get_type(ctx->async.private_data,
267                                 struct wbsrv_samba3_call);
268         int i, num_sids;
269         struct dom_sid **sids;
270         char *sids_string;
271         NTSTATUS status;
272
273         status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
274         if (!NT_STATUS_IS_OK(status)) goto done;
275
276         sids_string = talloc_strdup(s3call, "");
277         if (sids_string == NULL) {
278                 status = NT_STATUS_NO_MEMORY;
279                 goto done;
280         }
281
282         for (i=0; i<num_sids; i++) {
283                 sids_string = talloc_asprintf_append(
284                         sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
285                 if (sids_string == NULL) {
286                         status = NT_STATUS_NO_MEMORY;
287                         goto done;
288                 }
289         }
290
291         s3call->response.result = WINBINDD_OK;
292         s3call->response.extra_data = sids_string;
293         s3call->response.length += strlen(sids_string);
294         s3call->response.data.num_entries = num_sids;
295
296         /* Hmmmm. Nasty protocol -- who invented the zeros between the
297          * SIDs? Hmmm. Could have been me -- vl */
298
299         while (*sids_string != '\0') {
300                 if ((*sids_string) == '\n') {
301                         *sids_string = '\0';
302                 }
303                 sids_string += 1;
304         }
305
306  done:
307         wbsrv_samba3_async_epilogue(status, s3call);
308 }
309
310 static void lookupname_recv_sid(struct composite_context *ctx);
311
312 NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
313 {
314         struct composite_context *ctx;
315         struct wbsrv_service *service =
316                 s3call->call->wbconn->listen_socket->service;
317
318         DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
319
320         ctx = wb_cmd_lookupname_send(service, service->domains,
321                                      s3call->request.data.name.dom_name,
322                                      s3call->request.data.name.name);
323         NT_STATUS_HAVE_NO_MEMORY(ctx);
324
325         /* setup the callbacks */
326         ctx->async.fn = lookupname_recv_sid;
327         ctx->async.private_data = s3call;
328         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
329         return NT_STATUS_OK;
330 }
331
332 static void lookupname_recv_sid(struct composite_context *ctx)
333 {
334         struct wbsrv_samba3_call *s3call =
335                 talloc_get_type(ctx->async.private_data,
336                                 struct wbsrv_samba3_call);
337         struct wb_sid_object *sid;
338         NTSTATUS status;
339
340         status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
341         if (!NT_STATUS_IS_OK(status)) goto done;
342
343         s3call->response.result = WINBINDD_OK;
344         s3call->response.data.sid.type = sid->type;
345         WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
346                                 dom_sid_string(s3call, sid->sid));
347
348  done:
349         wbsrv_samba3_async_epilogue(status, s3call);
350 }
351
352 static void lookupsid_recv_name(struct composite_context *ctx);
353
354 NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
355 {
356         struct composite_context *ctx;
357         struct wbsrv_service *service =
358                 s3call->call->wbconn->listen_socket->service;
359         struct dom_sid *sid;
360
361         DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
362
363         sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
364         if (sid == NULL) {
365                 DEBUG(5, ("Could not parse sid %s\n",
366                           s3call->request.data.sid));
367                 return NT_STATUS_NO_MEMORY;
368         }
369
370         ctx = wb_cmd_lookupsid_send(service, service->domains, sid);
371         NT_STATUS_HAVE_NO_MEMORY(ctx);
372
373         /* setup the callbacks */
374         ctx->async.fn = lookupsid_recv_name;
375         ctx->async.private_data = s3call;
376         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
377         return NT_STATUS_OK;
378 }
379
380 static void lookupsid_recv_name(struct composite_context *ctx)
381 {
382         struct wbsrv_samba3_call *s3call =
383                 talloc_get_type(ctx->async.private_data,
384                                 struct wbsrv_samba3_call);
385         struct wb_sid_object *sid;
386         NTSTATUS status;
387
388         status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
389         if (!NT_STATUS_IS_OK(status)) goto done;
390
391         s3call->response.result = WINBINDD_OK;
392         s3call->response.data.name.type = sid->type;
393         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
394                                 sid->domain);
395         WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
396
397  done:
398         wbsrv_samba3_async_epilogue(status, s3call);
399 }
400
401 NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
402 {
403         s3call->response.result                 = WINBINDD_ERROR;
404         return NT_STATUS_OK;
405 }
406
407 #if 0
408 static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
409                                  char **domain, char **user)
410 {
411         char *p = strchr(domuser, *lp_winbind_separator());
412
413         if (p == NULL) {
414                 *domain = talloc_strdup(mem_ctx, lp_workgroup());
415         } else {
416                 *domain = talloc_strndup(mem_ctx, domuser,
417                                          PTR_DIFF(p, domuser));
418                 domuser = p+1;
419         }
420
421         *user = talloc_strdup(mem_ctx, domuser);
422
423         return ((*domain != NULL) && (*user != NULL));
424 }
425 #endif
426
427 static void pam_auth_crap_recv(struct composite_context *ctx);
428
429 NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
430 {
431         struct composite_context *ctx;
432
433         DATA_BLOB chal, nt_resp, lm_resp;
434
435         DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
436
437         chal.data      = s3call->request.data.auth_crap.chal;
438         chal.length    = sizeof(s3call->request.data.auth_crap.chal);
439         nt_resp.data   = s3call->request.data.auth_crap.nt_resp;
440         nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
441         lm_resp.data   = s3call->request.data.auth_crap.lm_resp;
442         lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
443
444         ctx = wb_cmd_pam_auth_crap_send(
445                 s3call->call, 
446                 s3call->request.data.auth_crap.domain,
447                 s3call->request.data.auth_crap.user,
448                 s3call->request.data.auth_crap.workstation,
449                 chal, nt_resp, lm_resp);
450         NT_STATUS_HAVE_NO_MEMORY(ctx);
451
452         ctx->async.fn = pam_auth_crap_recv;
453         ctx->async.private_data = s3call;
454         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
455         return NT_STATUS_OK;
456 }
457
458 static void pam_auth_crap_recv(struct composite_context *ctx)
459 {
460         struct wbsrv_samba3_call *s3call =
461                 talloc_get_type(ctx->async.private_data,
462                                 struct wbsrv_samba3_call);
463         struct winbindd_response *resp = &s3call->response;
464         NTSTATUS status;
465         DATA_BLOB info3;
466         struct netr_UserSessionKey user_session_key;
467         struct netr_LMSessionKey lm_key;
468
469         status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
470                                            &user_session_key, &lm_key);
471         if (!NT_STATUS_IS_OK(status)) goto done;
472
473         if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
474                 memcpy(s3call->response.data.auth.user_session_key, 
475                        &user_session_key.key,
476                        sizeof(s3call->response.data.auth.user_session_key));
477         }
478
479         if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
480                 s3call->response.extra_data = info3.data;
481                 s3call->response.length += info3.length;
482         }
483
484         if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
485                 memcpy(s3call->response.data.auth.first_8_lm_hash, 
486                        lm_key.key,
487                        sizeof(s3call->response.data.auth.first_8_lm_hash));
488         }
489         
490         resp->result = WINBINDD_OK;
491
492  done:
493         wbsrv_samba3_async_epilogue(status, s3call);
494 }
495
496 static void list_trustdom_recv_doms(struct composite_context *ctx);
497
498 NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
499 {
500         struct composite_context *ctx;
501         struct wbsrv_service *service =
502                 s3call->call->wbconn->listen_socket->service;
503
504         DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
505
506         ctx = wb_cmd_list_trustdoms_send(service);
507         NT_STATUS_HAVE_NO_MEMORY(ctx);
508
509         ctx->async.fn = list_trustdom_recv_doms;
510         ctx->async.private_data = s3call;
511         s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
512         return NT_STATUS_OK;
513 }
514
515 static void list_trustdom_recv_doms(struct composite_context *ctx)
516 {
517         struct wbsrv_samba3_call *s3call =
518                 talloc_get_type(ctx->async.private_data,
519                                 struct wbsrv_samba3_call);
520         int i, num_domains;
521         struct wb_dom_info **domains;
522         NTSTATUS status;
523         char *result;
524
525         status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
526                                             &domains);
527         if (!NT_STATUS_IS_OK(status)) goto done;
528
529         result = talloc_strdup(s3call, "");
530         if (result == NULL) {
531                 status = NT_STATUS_NO_MEMORY;
532                 goto done;
533         }
534
535         for (i=0; i<num_domains; i++) {
536                 result = talloc_asprintf_append(
537                         result, "%s\\%s\\%s",
538                         domains[i]->name, domains[i]->name,
539                         dom_sid_string(s3call, domains[i]->sid));
540         }
541
542         if (result == NULL) {
543                 status = NT_STATUS_NO_MEMORY;
544                 goto done;
545         }
546
547         s3call->response.result = WINBINDD_OK;
548         if (num_domains > 0) {
549                 s3call->response.extra_data = result;
550                 s3call->response.length += strlen(result)+1;
551         }
552
553  done:
554         wbsrv_samba3_async_epilogue(status, s3call);
555 }