s3:winbind: remove the method SET_MAPPING from winbind's API
[amitay/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(struct pipes_struct *p, struct wbint_Ping *r)
30 {
31         *r->out.out_data = r->in.in_data;
32 }
33
34 NTSTATUS _wbint_LookupSid(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct 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(struct pipes_struct *p,
228                               struct wbint_QueryUserList *r)
229 {
230         struct winbindd_domain *domain = wb_child_domain();
231
232         if (domain == NULL) {
233                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
234         }
235
236         return domain->methods->query_user_list(
237                 domain, p->mem_ctx, &r->out.users->num_userinfos,
238                 &r->out.users->userinfos);
239 }
240
241 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
242                                struct wbint_QueryGroupList *r)
243 {
244         struct winbindd_domain *domain = wb_child_domain();
245         uint32_t i, num_groups;
246         struct acct_info *groups;
247         struct wbint_Principal *result;
248         NTSTATUS status;
249
250         if (domain == NULL) {
251                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
252         }
253
254         status = domain->methods->enum_dom_groups(domain, talloc_tos(),
255                                                   &num_groups, &groups);
256         if (!NT_STATUS_IS_OK(status)) {
257                 return status;
258         }
259
260         result = talloc_array(r->out.groups, struct wbint_Principal,
261                               num_groups);
262         if (result == NULL) {
263                 return NT_STATUS_NO_MEMORY;
264         }
265
266         for (i=0; i<num_groups; i++) {
267                 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
268                 result[i].type = SID_NAME_DOM_GRP;
269                 result[i].name = talloc_strdup(result, groups[i].acct_name);
270                 if (result[i].name == NULL) {
271                         TALLOC_FREE(result);
272                         TALLOC_FREE(groups);
273                         return NT_STATUS_NO_MEMORY;
274                 }
275         }
276
277         r->out.groups->num_principals = num_groups;
278         r->out.groups->principals = result;
279
280         TALLOC_FREE(groups);
281         return NT_STATUS_OK;
282 }
283
284 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
285 {
286         struct winbindd_domain *domain = wb_child_domain();
287         struct rpc_pipe_client *netlogon_pipe;
288         struct netr_DsRGetDCNameInfo *dc_info;
289         NTSTATUS status;
290         WERROR werr;
291         unsigned int orig_timeout;
292
293         if (domain == NULL) {
294                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
295                                    r->in.domain_name, r->in.domain_guid,
296                                    r->in.site_name ? r->in.site_name : "",
297                                    r->in.flags,
298                                    r->out.dc_info);
299         }
300
301         status = cm_connect_netlogon(domain, &netlogon_pipe);
302
303         if (!NT_STATUS_IS_OK(status)) {
304                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
305                 return status;
306         }
307
308         /* This call can take a long time - allow the server to time out.
309            35 seconds should do it. */
310
311         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
312
313         if (domain->active_directory) {
314                 status = rpccli_netr_DsRGetDCName(
315                         netlogon_pipe, p->mem_ctx, domain->dcname,
316                         r->in.domain_name, NULL, r->in.domain_guid,
317                         r->in.flags, r->out.dc_info, &werr);
318                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
319                         goto done;
320                 }
321         }
322
323         /*
324          * Fallback to less capable methods
325          */
326
327         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
328         if (dc_info == NULL) {
329                 status = NT_STATUS_NO_MEMORY;
330                 goto done;
331         }
332
333         if (r->in.flags & DS_PDC_REQUIRED) {
334                 status = rpccli_netr_GetDcName(
335                         netlogon_pipe, p->mem_ctx, domain->dcname,
336                         r->in.domain_name, &dc_info->dc_unc, &werr);
337         } else {
338                 status = rpccli_netr_GetAnyDCName(
339                         netlogon_pipe, p->mem_ctx, domain->dcname,
340                         r->in.domain_name, &dc_info->dc_unc, &werr);
341         }
342
343         if (!NT_STATUS_IS_OK(status)) {
344                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
345                            nt_errstr(status)));
346                 goto done;
347         }
348         if (!W_ERROR_IS_OK(werr)) {
349                 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
350                            win_errstr(werr)));
351                 status = werror_to_ntstatus(werr);
352                 goto done;
353         }
354
355         *r->out.dc_info = dc_info;
356         status = NT_STATUS_OK;
357
358 done:
359         /* And restore our original timeout. */
360         rpccli_set_timeout(netlogon_pipe, orig_timeout);
361
362         return status;
363 }
364
365 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
366 {
367         struct winbindd_domain *domain = wb_child_domain();
368         char *domain_name;
369         char **names;
370         enum lsa_SidType *types;
371         struct wbint_Principal *result;
372         NTSTATUS status;
373         int i;
374
375         if (domain == NULL) {
376                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
377         }
378
379         status = domain->methods->rids_to_names(
380                 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
381                 r->in.rids->num_rids, &domain_name, &names, &types);
382         if (!NT_STATUS_IS_OK(status)) {
383                 return status;
384         }
385
386         result = talloc_array(p->mem_ctx, struct wbint_Principal,
387                               r->in.rids->num_rids);
388         if (result == NULL) {
389                 return NT_STATUS_NO_MEMORY;
390         }
391
392         for (i=0; i<r->in.rids->num_rids; i++) {
393                 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
394                 result[i].type = types[i];
395                 result[i].name = talloc_move(result, &names[i]);
396         }
397         TALLOC_FREE(types);
398         TALLOC_FREE(names);
399
400         r->out.names->num_principals = r->in.rids->num_rids;
401         r->out.names->principals = result;
402         return NT_STATUS_OK;
403 }
404
405 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
406                                     struct wbint_CheckMachineAccount *r)
407 {
408         struct winbindd_domain *domain;
409         int num_retries = 0;
410         NTSTATUS status;
411
412         domain = wb_child_domain();
413         if (domain == NULL) {
414                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
415         }
416
417 again:
418         invalidate_cm_connection(&domain->conn);
419
420         {
421                 struct rpc_pipe_client *netlogon_pipe;
422                 status = cm_connect_netlogon(domain, &netlogon_pipe);
423         }
424
425         /* There is a race condition between fetching the trust account
426            password and the periodic machine password change.  So it's
427            possible that the trust account password has been changed on us.
428            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
429
430 #define MAX_RETRIES 3
431
432         if ((num_retries < MAX_RETRIES)
433             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
434                 num_retries++;
435                 goto again;
436         }
437
438         if (!NT_STATUS_IS_OK(status)) {
439                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
440                 goto done;
441         }
442
443         /* Pass back result code - zero for success, other values for
444            specific failures. */
445
446         DEBUG(3,("domain %s secret is %s\n", domain->name,
447                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
448
449  done:
450         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
451               ("Checking the trust account password for domain %s returned %s\n",
452                domain->name, nt_errstr(status)));
453
454         return status;
455 }
456
457 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
458                                      struct wbint_ChangeMachineAccount *r)
459 {
460         struct winbindd_domain *domain;
461         int num_retries = 0;
462         NTSTATUS status;
463         struct rpc_pipe_client *netlogon_pipe;
464         TALLOC_CTX *tmp_ctx;
465
466 again:
467         domain = wb_child_domain();
468         if (domain == NULL) {
469                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
470         }
471
472         invalidate_cm_connection(&domain->conn);
473
474         {
475                 status = cm_connect_netlogon(domain, &netlogon_pipe);
476         }
477
478         /* There is a race condition between fetching the trust account
479            password and the periodic machine password change.  So it's
480            possible that the trust account password has been changed on us.
481            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
482
483 #define MAX_RETRIES 3
484
485         if ((num_retries < MAX_RETRIES)
486              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
487                 num_retries++;
488                 goto again;
489         }
490
491         if (!NT_STATUS_IS_OK(status)) {
492                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
493                 goto done;
494         }
495
496         tmp_ctx = talloc_new(p->mem_ctx);
497
498         status = trust_pw_find_change_and_store_it(netlogon_pipe,
499                                                    tmp_ctx,
500                                                    domain->name);
501         talloc_destroy(tmp_ctx);
502
503         /* Pass back result code - zero for success, other values for
504            specific failures. */
505
506         DEBUG(3,("domain %s secret %s\n", domain->name,
507                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
508
509  done:
510         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
511               ("Changing the trust account password for domain %s returned %s\n",
512                domain->name, nt_errstr(status)));
513
514         return status;
515 }
516
517 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
518 {
519         NTSTATUS status;
520         struct winbindd_domain *domain;
521         struct rpc_pipe_client *netlogon_pipe;
522         union netr_CONTROL_QUERY_INFORMATION info;
523         WERROR werr;
524         fstring logon_server;
525
526         domain = wb_child_domain();
527         if (domain == NULL) {
528                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
529         }
530
531         status = cm_connect_netlogon(domain, &netlogon_pipe);
532         if (!NT_STATUS_IS_OK(status)) {
533                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
534                 return status;
535         }
536
537         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
538
539         /*
540          * This provokes a WERR_NOT_SUPPORTED error message. This is
541          * documented in the wspp docs. I could not get a successful
542          * call to work, but the main point here is testing that the
543          * netlogon pipe works.
544          */
545         status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
546                                           logon_server, NETLOGON_CONTROL_QUERY,
547                                           2, &info, &werr);
548
549         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
550                 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
551                 invalidate_cm_connection(&domain->conn);
552                 return status;
553         }
554
555         if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
556                 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
557                           "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
558                           nt_errstr(status)));
559                 return status;
560         }
561
562         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
563         return NT_STATUS_OK;
564 }
565
566 NTSTATUS _wbint_RemoveMapping(struct pipes_struct *p,
567                               struct wbint_RemoveMapping *r)
568 {
569         struct id_map map;
570
571         map.sid = r->in.sid;
572         map.xid.id = r->in.id;
573         map.status = ID_MAPPED;
574
575         switch (r->in.type) {
576         case WBINT_ID_TYPE_UID:
577                 map.xid.type = ID_TYPE_UID;
578                 break;
579         case WBINT_ID_TYPE_GID:
580                 map.xid.type = ID_TYPE_GID;
581                 break;
582         default:
583                 return NT_STATUS_INVALID_PARAMETER;
584         }
585
586         return idmap_remove_mapping(&map);
587 }