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