libcli/security Provide a common, top level libcli/security/security.h
[sfrench/samba-autobuild/.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/cli_netlogon.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
295         if (domain == NULL) {
296                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
297                                    r->in.domain_name, r->in.domain_guid,
298                                    r->in.site_name ? r->in.site_name : "",
299                                    r->in.flags,
300                                    r->out.dc_info);
301         }
302
303         status = cm_connect_netlogon(domain, &netlogon_pipe);
304
305         if (!NT_STATUS_IS_OK(status)) {
306                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
307                 return status;
308         }
309
310         /* This call can take a long time - allow the server to time out.
311            35 seconds should do it. */
312
313         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
314
315         if (domain->active_directory) {
316                 status = rpccli_netr_DsRGetDCName(
317                         netlogon_pipe, p->mem_ctx, domain->dcname,
318                         r->in.domain_name, NULL, r->in.domain_guid,
319                         r->in.flags, r->out.dc_info, &werr);
320                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
321                         goto done;
322                 }
323         }
324
325         /*
326          * Fallback to less capable methods
327          */
328
329         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
330         if (dc_info == NULL) {
331                 status = NT_STATUS_NO_MEMORY;
332                 goto done;
333         }
334
335         if (r->in.flags & DS_PDC_REQUIRED) {
336                 status = rpccli_netr_GetDcName(
337                         netlogon_pipe, p->mem_ctx, domain->dcname,
338                         r->in.domain_name, &dc_info->dc_unc, &werr);
339         } else {
340                 status = rpccli_netr_GetAnyDCName(
341                         netlogon_pipe, p->mem_ctx, domain->dcname,
342                         r->in.domain_name, &dc_info->dc_unc, &werr);
343         }
344
345         if (!NT_STATUS_IS_OK(status)) {
346                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
347                            nt_errstr(status)));
348                 goto done;
349         }
350         if (!W_ERROR_IS_OK(werr)) {
351                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
352                            win_errstr(werr)));
353                 status = werror_to_ntstatus(werr);
354                 goto done;
355         }
356
357         *r->out.dc_info = dc_info;
358         status = NT_STATUS_OK;
359
360 done:
361         /* And restore our original timeout. */
362         rpccli_set_timeout(netlogon_pipe, orig_timeout);
363
364         return status;
365 }
366
367 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
368 {
369         struct winbindd_domain *domain = wb_child_domain();
370         char *domain_name;
371         char **names;
372         enum lsa_SidType *types;
373         struct wbint_Principal *result;
374         NTSTATUS status;
375         int i;
376
377         if (domain == NULL) {
378                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
379         }
380
381         status = domain->methods->rids_to_names(
382                 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
383                 r->in.rids->num_rids, &domain_name, &names, &types);
384         if (!NT_STATUS_IS_OK(status)) {
385                 return status;
386         }
387
388         result = talloc_array(p->mem_ctx, struct wbint_Principal,
389                               r->in.rids->num_rids);
390         if (result == NULL) {
391                 return NT_STATUS_NO_MEMORY;
392         }
393
394         for (i=0; i<r->in.rids->num_rids; i++) {
395                 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
396                 result[i].type = types[i];
397                 result[i].name = talloc_move(result, &names[i]);
398         }
399         TALLOC_FREE(types);
400         TALLOC_FREE(names);
401
402         r->out.names->num_principals = r->in.rids->num_rids;
403         r->out.names->principals = result;
404         return NT_STATUS_OK;
405 }
406
407 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
408                                     struct wbint_CheckMachineAccount *r)
409 {
410         struct winbindd_domain *domain;
411         int num_retries = 0;
412         NTSTATUS status;
413
414         domain = wb_child_domain();
415         if (domain == NULL) {
416                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
417         }
418
419 again:
420         invalidate_cm_connection(&domain->conn);
421
422         {
423                 struct rpc_pipe_client *netlogon_pipe;
424                 status = cm_connect_netlogon(domain, &netlogon_pipe);
425         }
426
427         /* There is a race condition between fetching the trust account
428            password and the periodic machine password change.  So it's
429            possible that the trust account password has been changed on us.
430            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
431
432 #define MAX_RETRIES 3
433
434         if ((num_retries < MAX_RETRIES)
435             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
436                 num_retries++;
437                 goto again;
438         }
439
440         if (!NT_STATUS_IS_OK(status)) {
441                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
442                 goto done;
443         }
444
445         /* Pass back result code - zero for success, other values for
446            specific failures. */
447
448         DEBUG(3,("domain %s secret is %s\n", domain->name,
449                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
450
451  done:
452         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
453               ("Checking the trust account password for domain %s returned %s\n",
454                domain->name, nt_errstr(status)));
455
456         return status;
457 }
458
459 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
460                                      struct wbint_ChangeMachineAccount *r)
461 {
462         struct winbindd_domain *domain;
463         int num_retries = 0;
464         NTSTATUS status;
465         struct rpc_pipe_client *netlogon_pipe;
466         TALLOC_CTX *tmp_ctx;
467
468 again:
469         domain = wb_child_domain();
470         if (domain == NULL) {
471                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
472         }
473
474         invalidate_cm_connection(&domain->conn);
475
476         {
477                 status = cm_connect_netlogon(domain, &netlogon_pipe);
478         }
479
480         /* There is a race condition between fetching the trust account
481            password and the periodic machine password change.  So it's
482            possible that the trust account password has been changed on us.
483            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
484
485 #define MAX_RETRIES 3
486
487         if ((num_retries < MAX_RETRIES)
488              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
489                 num_retries++;
490                 goto again;
491         }
492
493         if (!NT_STATUS_IS_OK(status)) {
494                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
495                 goto done;
496         }
497
498         tmp_ctx = talloc_new(p->mem_ctx);
499
500         status = trust_pw_find_change_and_store_it(netlogon_pipe,
501                                                    tmp_ctx,
502                                                    domain->name);
503         talloc_destroy(tmp_ctx);
504
505         /* Pass back result code - zero for success, other values for
506            specific failures. */
507
508         DEBUG(3,("domain %s secret %s\n", domain->name,
509                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
510
511  done:
512         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
513               ("Changing the trust account password for domain %s returned %s\n",
514                domain->name, nt_errstr(status)));
515
516         return status;
517 }
518
519 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
520 {
521         NTSTATUS status;
522         struct winbindd_domain *domain;
523         struct rpc_pipe_client *netlogon_pipe;
524         union netr_CONTROL_QUERY_INFORMATION info;
525         WERROR werr;
526         fstring logon_server;
527
528         domain = wb_child_domain();
529         if (domain == NULL) {
530                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
531         }
532
533         status = cm_connect_netlogon(domain, &netlogon_pipe);
534         if (!NT_STATUS_IS_OK(status)) {
535                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
536                 return status;
537         }
538
539         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
540
541         /*
542          * This provokes a WERR_NOT_SUPPORTED error message. This is
543          * documented in the wspp docs. I could not get a successful
544          * call to work, but the main point here is testing that the
545          * netlogon pipe works.
546          */
547         status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
548                                           logon_server, NETLOGON_CONTROL_QUERY,
549                                           2, &info, &werr);
550
551         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
552                 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
553                 invalidate_cm_connection(&domain->conn);
554                 return status;
555         }
556
557         if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
558                 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
559                           "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
560                           nt_errstr(status)));
561                 return status;
562         }
563
564         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
565         return NT_STATUS_OK;
566 }