0d3736b2b57eb0a15d14fa766fc38f5bb8b73479
[kai/samba.git] / source3 / winbindd / winbindd_dual_srv.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    In-Child server implementation of the routines defined in wbint.idl
5
6    Copyright (C) Volker Lendecke 2009
7    Copyright (C) Guenther Deschner 2009
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/srv_wbint.h"
28 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
29 #include "idmap.h"
30 #include "../libcli/security/security.h"
31
32 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
33 {
34         *r->out.out_data = r->in.in_data;
35 }
36
37 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
38 {
39         struct winbindd_domain *domain = wb_child_domain();
40         char *dom_name;
41         char *name;
42         enum lsa_SidType type;
43         NTSTATUS status;
44
45         if (domain == NULL) {
46                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
47         }
48
49         status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
50                                               &dom_name, &name, &type);
51         if (!NT_STATUS_IS_OK(status)) {
52                 return status;
53         }
54
55         *r->out.domain = dom_name;
56         *r->out.name = name;
57         *r->out.type = type;
58         return NT_STATUS_OK;
59 }
60
61 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
62 {
63         struct winbindd_domain *domain = wb_child_domain();
64
65         if (domain == NULL) {
66                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
67         }
68
69         return domain->methods->name_to_sid(
70                 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
71                 r->out.sid, r->out.type);
72 }
73
74 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
75 {
76         uid_t uid;
77         NTSTATUS status;
78
79         status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
80                                   r->in.sid, &uid);
81         if (!NT_STATUS_IS_OK(status)) {
82                 return status;
83         }
84         *r->out.uid = uid;
85         return NT_STATUS_OK;
86 }
87
88 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
89 {
90         gid_t gid;
91         NTSTATUS status;
92
93         status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
94                                   r->in.sid, &gid);
95         if (!NT_STATUS_IS_OK(status)) {
96                 return status;
97         }
98         *r->out.gid = gid;
99         return NT_STATUS_OK;
100 }
101
102 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
103 {
104         return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
105                                 r->out.sid, r->in.uid);
106 }
107
108 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
109 {
110         return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
111                                 r->out.sid, r->in.gid);
112 }
113
114 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
115 {
116         struct unixid xid;
117         NTSTATUS status;
118
119         status = idmap_allocate_uid(&xid);
120         if (!NT_STATUS_IS_OK(status)) {
121                 return status;
122         }
123         *r->out.uid = xid.id;
124         return NT_STATUS_OK;
125 }
126
127 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
128 {
129         struct unixid xid;
130         NTSTATUS status;
131
132         status = idmap_allocate_gid(&xid);
133         if (!NT_STATUS_IS_OK(status)) {
134                 return status;
135         }
136         *r->out.gid = xid.id;
137         return NT_STATUS_OK;
138 }
139
140 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
141 {
142         struct winbindd_domain *domain = wb_child_domain();
143
144         if (domain == NULL) {
145                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
146         }
147
148         return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
149                                            r->out.info);
150 }
151
152 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
153                                   struct wbint_LookupUserAliases *r)
154 {
155         struct winbindd_domain *domain = wb_child_domain();
156
157         if (domain == NULL) {
158                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
159         }
160
161         return domain->methods->lookup_useraliases(
162                 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
163                 &r->out.rids->num_rids, &r->out.rids->rids);
164 }
165
166 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
167                                  struct wbint_LookupUserGroups *r)
168 {
169         struct winbindd_domain *domain = wb_child_domain();
170
171         if (domain == NULL) {
172                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
173         }
174
175         return domain->methods->lookup_usergroups(
176                 domain, p->mem_ctx, r->in.sid,
177                 &r->out.sids->num_sids, &r->out.sids->sids);
178 }
179
180 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
181                                     struct wbint_QuerySequenceNumber *r)
182 {
183         struct winbindd_domain *domain = wb_child_domain();
184
185         if (domain == NULL) {
186                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
187         }
188
189         return domain->methods->sequence_number(domain, r->out.sequence);
190 }
191
192 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
193                                    struct wbint_LookupGroupMembers *r)
194 {
195         struct winbindd_domain *domain = wb_child_domain();
196         uint32_t i, num_names;
197         struct dom_sid *sid_mem;
198         char **names;
199         uint32_t *name_types;
200         NTSTATUS status;
201
202         if (domain == NULL) {
203                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
204         }
205
206         status = domain->methods->lookup_groupmem(
207                 domain, p->mem_ctx, r->in.sid, r->in.type,
208                 &num_names, &sid_mem, &names, &name_types);
209         if (!NT_STATUS_IS_OK(status)) {
210                 return status;
211         }
212
213         r->out.members->num_principals = num_names;
214         r->out.members->principals = talloc_array(
215                 r->out.members, struct wbint_Principal, num_names);
216         if (r->out.members->principals == NULL) {
217                 return NT_STATUS_NO_MEMORY;
218         }
219
220         for (i=0; i<num_names; i++) {
221                 struct wbint_Principal *m = &r->out.members->principals[i];
222                 sid_copy(&m->sid, &sid_mem[i]);
223                 m->name = talloc_move(r->out.members->principals, &names[i]);
224                 m->type = (enum lsa_SidType)name_types[i];
225         }
226
227         return NT_STATUS_OK;
228 }
229
230 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
231                               struct wbint_QueryUserList *r)
232 {
233         struct winbindd_domain *domain = wb_child_domain();
234
235         if (domain == NULL) {
236                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
237         }
238
239         return domain->methods->query_user_list(
240                 domain, p->mem_ctx, &r->out.users->num_userinfos,
241                 &r->out.users->userinfos);
242 }
243
244 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
245                                struct wbint_QueryGroupList *r)
246 {
247         struct winbindd_domain *domain = wb_child_domain();
248         uint32_t i, num_groups;
249         struct wb_acct_info *groups;
250         struct wbint_Principal *result;
251         NTSTATUS status;
252
253         if (domain == NULL) {
254                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
255         }
256
257         status = domain->methods->enum_dom_groups(domain, talloc_tos(),
258                                                   &num_groups, &groups);
259         if (!NT_STATUS_IS_OK(status)) {
260                 return status;
261         }
262
263         result = talloc_array(r->out.groups, struct wbint_Principal,
264                               num_groups);
265         if (result == NULL) {
266                 return NT_STATUS_NO_MEMORY;
267         }
268
269         for (i=0; i<num_groups; i++) {
270                 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
271                 result[i].type = SID_NAME_DOM_GRP;
272                 result[i].name = talloc_strdup(result, groups[i].acct_name);
273                 if (result[i].name == NULL) {
274                         TALLOC_FREE(result);
275                         TALLOC_FREE(groups);
276                         return NT_STATUS_NO_MEMORY;
277                 }
278         }
279
280         r->out.groups->num_principals = num_groups;
281         r->out.groups->principals = result;
282
283         TALLOC_FREE(groups);
284         return NT_STATUS_OK;
285 }
286
287 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
288 {
289         struct winbindd_domain *domain = wb_child_domain();
290         struct rpc_pipe_client *netlogon_pipe;
291         struct netr_DsRGetDCNameInfo *dc_info;
292         NTSTATUS status;
293         WERROR werr;
294         unsigned int orig_timeout;
295         struct dcerpc_binding_handle *b;
296
297         if (domain == NULL) {
298                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
299                                    r->in.domain_name, r->in.domain_guid,
300                                    r->in.site_name ? r->in.site_name : "",
301                                    r->in.flags,
302                                    r->out.dc_info);
303         }
304
305         status = cm_connect_netlogon(domain, &netlogon_pipe);
306
307         if (!NT_STATUS_IS_OK(status)) {
308                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
309                 return status;
310         }
311
312         b = netlogon_pipe->binding_handle;
313
314         /* This call can take a long time - allow the server to time out.
315            35 seconds should do it. */
316
317         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
318
319         if (domain->active_directory) {
320                 status = dcerpc_netr_DsRGetDCName(b,
321                         p->mem_ctx, domain->dcname,
322                         r->in.domain_name, NULL, r->in.domain_guid,
323                         r->in.flags, r->out.dc_info, &werr);
324                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
325                         goto done;
326                 }
327         }
328
329         /*
330          * Fallback to less capable methods
331          */
332
333         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
334         if (dc_info == NULL) {
335                 status = NT_STATUS_NO_MEMORY;
336                 goto done;
337         }
338
339         if (r->in.flags & DS_PDC_REQUIRED) {
340                 status = dcerpc_netr_GetDcName(b,
341                         p->mem_ctx, domain->dcname,
342                         r->in.domain_name, &dc_info->dc_unc, &werr);
343         } else {
344                 status = dcerpc_netr_GetAnyDCName(b,
345                         p->mem_ctx, domain->dcname,
346                         r->in.domain_name, &dc_info->dc_unc, &werr);
347         }
348
349         if (!NT_STATUS_IS_OK(status)) {
350                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
351                            nt_errstr(status)));
352                 goto done;
353         }
354         if (!W_ERROR_IS_OK(werr)) {
355                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
356                            win_errstr(werr)));
357                 status = werror_to_ntstatus(werr);
358                 goto done;
359         }
360
361         *r->out.dc_info = dc_info;
362         status = NT_STATUS_OK;
363
364 done:
365         /* And restore our original timeout. */
366         rpccli_set_timeout(netlogon_pipe, orig_timeout);
367
368         return status;
369 }
370
371 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
372 {
373         struct winbindd_domain *domain = wb_child_domain();
374         char *domain_name;
375         char **names;
376         enum lsa_SidType *types;
377         struct wbint_Principal *result;
378         NTSTATUS status;
379         int i;
380
381         if (domain == NULL) {
382                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
383         }
384
385         status = domain->methods->rids_to_names(
386                 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
387                 r->in.rids->num_rids, &domain_name, &names, &types);
388         if (!NT_STATUS_IS_OK(status)) {
389                 return status;
390         }
391
392         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
393
394         result = talloc_array(p->mem_ctx, struct wbint_Principal,
395                               r->in.rids->num_rids);
396         if (result == NULL) {
397                 return NT_STATUS_NO_MEMORY;
398         }
399
400         for (i=0; i<r->in.rids->num_rids; i++) {
401                 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
402                 result[i].type = types[i];
403                 result[i].name = talloc_move(result, &names[i]);
404         }
405         TALLOC_FREE(types);
406         TALLOC_FREE(names);
407
408         r->out.names->num_principals = r->in.rids->num_rids;
409         r->out.names->principals = result;
410         return NT_STATUS_OK;
411 }
412
413 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
414                                     struct wbint_CheckMachineAccount *r)
415 {
416         struct winbindd_domain *domain;
417         int num_retries = 0;
418         NTSTATUS status;
419
420         domain = wb_child_domain();
421         if (domain == NULL) {
422                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
423         }
424
425 again:
426         invalidate_cm_connection(&domain->conn);
427
428         {
429                 struct rpc_pipe_client *netlogon_pipe;
430                 status = cm_connect_netlogon(domain, &netlogon_pipe);
431         }
432
433         /* There is a race condition between fetching the trust account
434            password and the periodic machine password change.  So it's
435            possible that the trust account password has been changed on us.
436            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
437
438 #define MAX_RETRIES 3
439
440         if ((num_retries < MAX_RETRIES)
441             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
442                 num_retries++;
443                 goto again;
444         }
445
446         if (!NT_STATUS_IS_OK(status)) {
447                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
448                 goto done;
449         }
450
451         /* Pass back result code - zero for success, other values for
452            specific failures. */
453
454         DEBUG(3,("domain %s secret is %s\n", domain->name,
455                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
456
457  done:
458         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
459               ("Checking the trust account password for domain %s returned %s\n",
460                domain->name, nt_errstr(status)));
461
462         return status;
463 }
464
465 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
466                                      struct wbint_ChangeMachineAccount *r)
467 {
468         struct winbindd_domain *domain;
469         int num_retries = 0;
470         NTSTATUS status;
471         struct rpc_pipe_client *netlogon_pipe;
472         TALLOC_CTX *tmp_ctx;
473
474 again:
475         domain = wb_child_domain();
476         if (domain == NULL) {
477                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
478         }
479
480         invalidate_cm_connection(&domain->conn);
481
482         {
483                 status = cm_connect_netlogon(domain, &netlogon_pipe);
484         }
485
486         /* There is a race condition between fetching the trust account
487            password and the periodic machine password change.  So it's
488            possible that the trust account password has been changed on us.
489            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
490
491 #define MAX_RETRIES 3
492
493         if ((num_retries < MAX_RETRIES)
494              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
495                 num_retries++;
496                 goto again;
497         }
498
499         if (!NT_STATUS_IS_OK(status)) {
500                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
501                 goto done;
502         }
503
504         tmp_ctx = talloc_new(p->mem_ctx);
505
506         status = trust_pw_find_change_and_store_it(netlogon_pipe,
507                                                    tmp_ctx,
508                                                    domain->name);
509         talloc_destroy(tmp_ctx);
510
511         /* Pass back result code - zero for success, other values for
512            specific failures. */
513
514         DEBUG(3,("domain %s secret %s\n", domain->name,
515                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
516
517  done:
518         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
519               ("Changing the trust account password for domain %s returned %s\n",
520                domain->name, nt_errstr(status)));
521
522         return status;
523 }
524
525 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
526 {
527         NTSTATUS status;
528         struct winbindd_domain *domain;
529         struct rpc_pipe_client *netlogon_pipe;
530         union netr_CONTROL_QUERY_INFORMATION info;
531         WERROR werr;
532         fstring logon_server;
533         struct dcerpc_binding_handle *b;
534
535         domain = wb_child_domain();
536         if (domain == NULL) {
537                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
538         }
539
540         status = cm_connect_netlogon(domain, &netlogon_pipe);
541         if (!NT_STATUS_IS_OK(status)) {
542                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
543                 return status;
544         }
545
546         b = netlogon_pipe->binding_handle;
547
548         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
549
550         /*
551          * This provokes a WERR_NOT_SUPPORTED error message. This is
552          * documented in the wspp docs. I could not get a successful
553          * call to work, but the main point here is testing that the
554          * netlogon pipe works.
555          */
556         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
557                                           logon_server, NETLOGON_CONTROL_QUERY,
558                                           2, &info, &werr);
559
560         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
561                 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
562                 invalidate_cm_connection(&domain->conn);
563                 return status;
564         }
565
566         if (!NT_STATUS_IS_OK(status)) {
567                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
568                         nt_errstr(status)));
569                 return status;
570         }
571
572         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
573                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
574                           "WERR_NOT_SUPPORTED\n",
575                           win_errstr(werr)));
576                 return werror_to_ntstatus(werr);
577         }
578
579         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
580         return NT_STATUS_OK;
581 }