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