source: branches/samba-3.5.x/source3/winbindd/winbindd_dual_srv.c

Last change on this file was 620, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.11

File size: 16.0 KB
Line 
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
29void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r)
30{
31 *r->out.out_data = r->in.in_data;
32}
33
34NTSTATUS _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
58NTSTATUS _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
71NTSTATUS _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
85NTSTATUS _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
99NTSTATUS _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
105NTSTATUS _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
111NTSTATUS _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
124NTSTATUS _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
137NTSTATUS _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
149NTSTATUS _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
163NTSTATUS _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
177NTSTATUS _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
189NTSTATUS _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
227NTSTATUS _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
240NTSTATUS _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
280NTSTATUS _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
354done:
355 /* And restore our original timeout. */
356 rpccli_set_timeout(netlogon_pipe, orig_timeout);
357
358 return status;
359}
360
361NTSTATUS _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
404NTSTATUS _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
416again:
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
456NTSTATUS _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
465again:
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
516NTSTATUS _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
565NTSTATUS _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
587NTSTATUS _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
609NTSTATUS _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}
Note: See TracBrowser for help on using the repository browser.