cecbb61051509960ff6b0990132515a6b28eb9f4
[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
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(), &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         result = talloc_array(p->mem_ctx, struct wbint_Principal,
383                               r->in.rids->num_rids);
384         if (result == NULL) {
385                 return NT_STATUS_NO_MEMORY;
386         }
387
388         for (i=0; i<r->in.rids->num_rids; i++) {
389                 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
390                 result[i].type = types[i];
391                 result[i].name = talloc_move(result, &names[i]);
392         }
393         TALLOC_FREE(types);
394         TALLOC_FREE(names);
395
396         r->out.names->num_principals = r->in.rids->num_rids;
397         r->out.names->principals = result;
398         return NT_STATUS_OK;
399 }
400
401 NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p,
402                                     struct wbint_CheckMachineAccount *r)
403 {
404         struct winbindd_domain *domain;
405         int num_retries = 0;
406         NTSTATUS status;
407
408         domain = wb_child_domain();
409         if (domain == NULL) {
410                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
411         }
412
413 again:
414         invalidate_cm_connection(&domain->conn);
415
416         {
417                 struct rpc_pipe_client *netlogon_pipe;
418                 status = cm_connect_netlogon(domain, &netlogon_pipe);
419         }
420
421         /* There is a race condition between fetching the trust account
422            password and the periodic machine password change.  So it's
423            possible that the trust account password has been changed on us.
424            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
425
426 #define MAX_RETRIES 3
427
428         if ((num_retries < MAX_RETRIES)
429             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
430                 num_retries++;
431                 goto again;
432         }
433
434         if (!NT_STATUS_IS_OK(status)) {
435                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
436                 goto done;
437         }
438
439         /* Pass back result code - zero for success, other values for
440            specific failures. */
441
442         DEBUG(3,("domain %s secret is %s\n", domain->name,
443                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
444
445  done:
446         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
447               ("Checking the trust account password for domain %s returned %s\n",
448                domain->name, nt_errstr(status)));
449
450         return status;
451 }
452
453 NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p,
454                                      struct wbint_ChangeMachineAccount *r)
455 {
456         struct winbindd_domain *domain;
457         int num_retries = 0;
458         NTSTATUS status;
459         struct rpc_pipe_client *netlogon_pipe;
460         TALLOC_CTX *tmp_ctx;
461
462 again:
463         domain = wb_child_domain();
464         if (domain == NULL) {
465                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
466         }
467
468         invalidate_cm_connection(&domain->conn);
469
470         {
471                 status = cm_connect_netlogon(domain, &netlogon_pipe);
472         }
473
474         /* There is a race condition between fetching the trust account
475            password and the periodic machine password change.  So it's
476            possible that the trust account password has been changed on us.
477            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
478
479 #define MAX_RETRIES 3
480
481         if ((num_retries < MAX_RETRIES)
482              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
483                 num_retries++;
484                 goto again;
485         }
486
487         if (!NT_STATUS_IS_OK(status)) {
488                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
489                 goto done;
490         }
491
492         tmp_ctx = talloc_new(p->mem_ctx);
493
494         status = trust_pw_find_change_and_store_it(netlogon_pipe,
495                                                    tmp_ctx,
496                                                    domain->name);
497         talloc_destroy(tmp_ctx);
498
499         /* Pass back result code - zero for success, other values for
500            specific failures. */
501
502         DEBUG(3,("domain %s secret %s\n", domain->name,
503                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
504
505  done:
506         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
507               ("Changing the trust account password for domain %s returned %s\n",
508                domain->name, nt_errstr(status)));
509
510         return status;
511 }
512
513
514 NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r)
515 {
516         struct id_map map;
517
518         map.sid = r->in.sid;
519         map.xid.id = r->in.id;
520         map.status = ID_MAPPED;
521
522         switch (r->in.type) {
523         case WBINT_ID_TYPE_UID:
524                 map.xid.type = ID_TYPE_UID;
525                 break;
526         case WBINT_ID_TYPE_GID:
527                 map.xid.type = ID_TYPE_GID;
528                 break;
529         default:
530                 return NT_STATUS_INVALID_PARAMETER;
531         }
532
533         return idmap_set_mapping(&map);
534 }
535
536 NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r)
537 {
538         struct id_map map;
539
540         map.sid = r->in.sid;
541         map.xid.id = r->in.id;
542         map.status = ID_MAPPED;
543
544         switch (r->in.type) {
545         case WBINT_ID_TYPE_UID:
546                 map.xid.type = ID_TYPE_UID;
547                 break;
548         case WBINT_ID_TYPE_GID:
549                 map.xid.type = ID_TYPE_GID;
550                 break;
551         default:
552                 return NT_STATUS_INVALID_PARAMETER;
553         }
554
555         return idmap_remove_mapping(&map);
556 }
557
558 NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r)
559 {
560         struct unixid id;
561         NTSTATUS status;
562
563         id.id = r->in.id;
564
565         switch (id.type) {
566         case WBINT_ID_TYPE_UID:
567                 id.type = ID_TYPE_UID;
568                 status = idmap_set_uid_hwm(&id);
569                 break;
570         case ID_TYPE_GID:
571                 id.type = ID_TYPE_GID;
572                 status = idmap_set_gid_hwm(&id);
573                 break;
574         default:
575                 status = NT_STATUS_INVALID_PARAMETER;
576                 break;
577         }
578         return status;
579 }