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