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