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