Fix remove_duplicate_addrs2 to do exactly what it says. Previously it could leave...
[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/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         return NT_STATUS_OK;
278 }
279
280 NTSTATUS _wbint_DsGetDcName(pipes_struct *p, struct wbint_DsGetDcName *r)
281 {
282         struct winbindd_domain *domain = wb_child_domain();
283         struct rpc_pipe_client *netlogon_pipe;
284         struct netr_DsRGetDCNameInfo *dc_info;
285         NTSTATUS status;
286         WERROR werr;
287         unsigned int orig_timeout;
288
289         if (domain == NULL) {
290                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
291                                    r->in.domain_name, r->in.domain_guid,
292                                    r->in.site_name ? r->in.site_name : "",
293                                    r->in.flags,
294                                    r->out.dc_info);
295         }
296
297         status = cm_connect_netlogon(domain, &netlogon_pipe);
298
299         if (!NT_STATUS_IS_OK(status)) {
300                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
301                 return status;
302         }
303
304         /* This call can take a long time - allow the server to time out.
305            35 seconds should do it. */
306
307         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
308
309         if (domain->active_directory) {
310                 status = rpccli_netr_DsRGetDCName(
311                         netlogon_pipe, p->mem_ctx, domain->dcname,
312                         r->in.domain_name, NULL, r->in.domain_guid,
313                         r->in.flags, r->out.dc_info, &werr);
314                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
315                         goto done;
316                 }
317         }
318
319         /*
320          * Fallback to less capable methods
321          */
322
323         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
324         if (dc_info == NULL) {
325                 status = NT_STATUS_NO_MEMORY;
326                 goto done;
327         }
328
329         if (r->in.flags & DS_PDC_REQUIRED) {
330                 status = rpccli_netr_GetDcName(
331                         netlogon_pipe, p->mem_ctx, domain->dcname,
332                         r->in.domain_name, &dc_info->dc_unc, &werr);
333         } else {
334                 status = rpccli_netr_GetAnyDCName(
335                         netlogon_pipe, p->mem_ctx, domain->dcname,
336                         r->in.domain_name, &dc_info->dc_unc, &werr);
337         }
338
339         if (!NT_STATUS_IS_OK(status)) {
340                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
341                            nt_errstr(status)));
342                 goto done;
343         }
344         if (!W_ERROR_IS_OK(werr)) {
345                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
346                            win_errstr(werr)));
347                 status = werror_to_ntstatus(werr);
348                 goto done;
349         }
350
351         *r->out.dc_info = dc_info;
352         status = NT_STATUS_OK;
353
354 done:
355         /* And restore our original timeout. */
356         rpccli_set_timeout(netlogon_pipe, orig_timeout);
357
358         return status;
359 }
360
361 NTSTATUS _wbint_LookupRids(pipes_struct *p, struct wbint_LookupRids *r)
362 {
363         struct winbindd_domain *domain = wb_child_domain();
364         char *domain_name;
365         char **names;
366         enum lsa_SidType *types;
367         struct wbint_Principal *result;
368         NTSTATUS status;
369         int i;
370
371         if (domain == NULL) {
372                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
373         }
374
375         status = domain->methods->rids_to_names(
376                 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
377                 r->in.rids->num_rids, &domain_name, &names, &types);
378         if (!NT_STATUS_IS_OK(status)) {
379                 return status;
380         }
381
382         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
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, r->in.domain_sid,
392                             r->in.rids->rids[i]);
393                 result[i].type = types[i];
394                 result[i].name = talloc_move(result, &names[i]);
395         }
396         TALLOC_FREE(types);
397         TALLOC_FREE(names);
398
399         r->out.names->num_principals = r->in.rids->num_rids;
400         r->out.names->principals = result;
401         return NT_STATUS_OK;
402 }
403
404 NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p,
405                                     struct wbint_CheckMachineAccount *r)
406 {
407         struct winbindd_domain *domain;
408         int num_retries = 0;
409         NTSTATUS status;
410
411         domain = wb_child_domain();
412         if (domain == NULL) {
413                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
414         }
415
416 again:
417         invalidate_cm_connection(&domain->conn);
418
419         {
420                 struct rpc_pipe_client *netlogon_pipe;
421                 status = cm_connect_netlogon(domain, &netlogon_pipe);
422         }
423
424         /* There is a race condition between fetching the trust account
425            password and the periodic machine password change.  So it's
426            possible that the trust account password has been changed on us.
427            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
428
429 #define MAX_RETRIES 3
430
431         if ((num_retries < MAX_RETRIES)
432             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
433                 num_retries++;
434                 goto again;
435         }
436
437         if (!NT_STATUS_IS_OK(status)) {
438                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
439                 goto done;
440         }
441
442         /* Pass back result code - zero for success, other values for
443            specific failures. */
444
445         DEBUG(3,("domain %s secret is %s\n", domain->name,
446                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
447
448  done:
449         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
450               ("Checking the trust account password for domain %s returned %s\n",
451                domain->name, nt_errstr(status)));
452
453         return status;
454 }
455
456 NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p,
457                                      struct wbint_ChangeMachineAccount *r)
458 {
459         struct winbindd_domain *domain;
460         int num_retries = 0;
461         NTSTATUS status;
462         struct rpc_pipe_client *netlogon_pipe;
463         TALLOC_CTX *tmp_ctx;
464
465 again:
466         domain = wb_child_domain();
467         if (domain == NULL) {
468                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
469         }
470
471         invalidate_cm_connection(&domain->conn);
472
473         {
474                 status = cm_connect_netlogon(domain, &netlogon_pipe);
475         }
476
477         /* There is a race condition between fetching the trust account
478            password and the periodic machine password change.  So it's
479            possible that the trust account password has been changed on us.
480            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
481
482 #define MAX_RETRIES 3
483
484         if ((num_retries < MAX_RETRIES)
485              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
486                 num_retries++;
487                 goto again;
488         }
489
490         if (!NT_STATUS_IS_OK(status)) {
491                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
492                 goto done;
493         }
494
495         tmp_ctx = talloc_new(p->mem_ctx);
496
497         status = trust_pw_find_change_and_store_it(netlogon_pipe,
498                                                    tmp_ctx,
499                                                    domain->name);
500         talloc_destroy(tmp_ctx);
501
502         /* Pass back result code - zero for success, other values for
503            specific failures. */
504
505         DEBUG(3,("domain %s secret %s\n", domain->name,
506                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
507
508  done:
509         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
510               ("Changing the trust account password for domain %s returned %s\n",
511                domain->name, nt_errstr(status)));
512
513         return status;
514 }
515
516 NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r)
517 {
518         NTSTATUS status;
519         struct winbindd_domain *domain;
520         struct rpc_pipe_client *netlogon_pipe;
521         union netr_CONTROL_QUERY_INFORMATION info;
522         WERROR werr;
523         fstring logon_server;
524
525         domain = wb_child_domain();
526         if (domain == NULL) {
527                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
528         }
529
530         status = cm_connect_netlogon(domain, &netlogon_pipe);
531         if (!NT_STATUS_IS_OK(status)) {
532                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
533                 return status;
534         }
535
536         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
537
538         /*
539          * This provokes a WERR_NOT_SUPPORTED error message. This is
540          * documented in the wspp docs. I could not get a successful
541          * call to work, but the main point here is testing that the
542          * netlogon pipe works.
543          */
544         status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
545                                           logon_server, NETLOGON_CONTROL_QUERY,
546                                           2, &info, &werr);
547
548         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
549                 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
550                 invalidate_cm_connection(&domain->conn);
551                 return status;
552         }
553
554         if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
555                 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
556                           "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
557                           nt_errstr(status)));
558                 return status;
559         }
560
561         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
562         return NT_STATUS_OK;
563 }
564
565 NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r)
566 {
567         struct id_map map;
568
569         map.sid = r->in.sid;
570         map.xid.id = r->in.id;
571         map.status = ID_MAPPED;
572
573         switch (r->in.type) {
574         case WBINT_ID_TYPE_UID:
575                 map.xid.type = ID_TYPE_UID;
576                 break;
577         case WBINT_ID_TYPE_GID:
578                 map.xid.type = ID_TYPE_GID;
579                 break;
580         default:
581                 return NT_STATUS_INVALID_PARAMETER;
582         }
583
584         return idmap_set_mapping(&map);
585 }
586
587 NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r)
588 {
589         struct id_map map;
590
591         map.sid = r->in.sid;
592         map.xid.id = r->in.id;
593         map.status = ID_MAPPED;
594
595         switch (r->in.type) {
596         case WBINT_ID_TYPE_UID:
597                 map.xid.type = ID_TYPE_UID;
598                 break;
599         case WBINT_ID_TYPE_GID:
600                 map.xid.type = ID_TYPE_GID;
601                 break;
602         default:
603                 return NT_STATUS_INVALID_PARAMETER;
604         }
605
606         return idmap_remove_mapping(&map);
607 }
608
609 NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r)
610 {
611         struct unixid id;
612         NTSTATUS status;
613
614         id.id = r->in.id;
615
616         switch (r->in.type) {
617         case WBINT_ID_TYPE_UID:
618                 id.type = ID_TYPE_UID;
619                 status = idmap_set_uid_hwm(&id);
620                 break;
621         case WBINT_ID_TYPE_GID:
622                 id.type = ID_TYPE_GID;
623                 status = idmap_set_gid_hwm(&id);
624                 break;
625         default:
626                 status = NT_STATUS_INVALID_PARAMETER;
627                 break;
628         }
629         return status;
630 }