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