s3-net: let rpccli_winreg_Connect optionally return WERROR
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob4c6fb97e7092852aafeda7a7b42b5cdb1bd22fef
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
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.
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.
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/>.
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 #include "idmap.h"
30 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
32 *r->out.out_data = r->in.in_data;
35 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
37 struct winbindd_domain *domain = wb_child_domain();
38 char *dom_name;
39 char *name;
40 enum lsa_SidType type;
41 NTSTATUS status;
43 if (domain == NULL) {
44 return NT_STATUS_REQUEST_NOT_ACCEPTED;
47 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
48 &dom_name, &name, &type);
49 if (!NT_STATUS_IS_OK(status)) {
50 return status;
53 *r->out.domain = dom_name;
54 *r->out.name = name;
55 *r->out.type = type;
56 return NT_STATUS_OK;
59 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
61 struct winbindd_domain *domain = wb_child_domain();
63 if (domain == NULL) {
64 return NT_STATUS_REQUEST_NOT_ACCEPTED;
67 return domain->methods->name_to_sid(
68 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
69 r->out.sid, r->out.type);
72 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
74 uid_t uid;
75 NTSTATUS status;
77 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
78 r->in.sid, &uid);
79 if (!NT_STATUS_IS_OK(status)) {
80 return status;
82 *r->out.uid = uid;
83 return NT_STATUS_OK;
86 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
88 gid_t gid;
89 NTSTATUS status;
91 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
92 r->in.sid, &gid);
93 if (!NT_STATUS_IS_OK(status)) {
94 return status;
96 *r->out.gid = gid;
97 return NT_STATUS_OK;
100 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
102 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
103 r->out.sid, r->in.uid);
106 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
108 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
109 r->out.sid, r->in.gid);
112 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
114 struct unixid xid;
115 NTSTATUS status;
117 status = idmap_allocate_uid(&xid);
118 if (!NT_STATUS_IS_OK(status)) {
119 return status;
121 *r->out.uid = xid.id;
122 return NT_STATUS_OK;
125 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
127 struct unixid xid;
128 NTSTATUS status;
130 status = idmap_allocate_gid(&xid);
131 if (!NT_STATUS_IS_OK(status)) {
132 return status;
134 *r->out.gid = xid.id;
135 return NT_STATUS_OK;
138 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
140 struct winbindd_domain *domain = wb_child_domain();
142 if (domain == NULL) {
143 return NT_STATUS_REQUEST_NOT_ACCEPTED;
146 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
147 r->out.info);
150 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
151 struct wbint_LookupUserAliases *r)
153 struct winbindd_domain *domain = wb_child_domain();
155 if (domain == NULL) {
156 return NT_STATUS_REQUEST_NOT_ACCEPTED;
159 return domain->methods->lookup_useraliases(
160 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
161 &r->out.rids->num_rids, &r->out.rids->rids);
164 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
165 struct wbint_LookupUserGroups *r)
167 struct winbindd_domain *domain = wb_child_domain();
169 if (domain == NULL) {
170 return NT_STATUS_REQUEST_NOT_ACCEPTED;
173 return domain->methods->lookup_usergroups(
174 domain, p->mem_ctx, r->in.sid,
175 &r->out.sids->num_sids, &r->out.sids->sids);
178 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
179 struct wbint_QuerySequenceNumber *r)
181 struct winbindd_domain *domain = wb_child_domain();
183 if (domain == NULL) {
184 return NT_STATUS_REQUEST_NOT_ACCEPTED;
187 return domain->methods->sequence_number(domain, r->out.sequence);
190 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
191 struct wbint_LookupGroupMembers *r)
193 struct winbindd_domain *domain = wb_child_domain();
194 uint32_t i, num_names;
195 struct dom_sid *sid_mem;
196 char **names;
197 uint32_t *name_types;
198 NTSTATUS status;
200 if (domain == NULL) {
201 return NT_STATUS_REQUEST_NOT_ACCEPTED;
204 status = domain->methods->lookup_groupmem(
205 domain, p->mem_ctx, r->in.sid, r->in.type,
206 &num_names, &sid_mem, &names, &name_types);
207 if (!NT_STATUS_IS_OK(status)) {
208 return status;
211 r->out.members->num_principals = num_names;
212 r->out.members->principals = talloc_array(
213 r->out.members, struct wbint_Principal, num_names);
214 if (r->out.members->principals == NULL) {
215 return NT_STATUS_NO_MEMORY;
218 for (i=0; i<num_names; i++) {
219 struct wbint_Principal *m = &r->out.members->principals[i];
220 sid_copy(&m->sid, &sid_mem[i]);
221 m->name = talloc_move(r->out.members->principals, &names[i]);
222 m->type = (enum lsa_SidType)name_types[i];
225 return NT_STATUS_OK;
228 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
229 struct wbint_QueryUserList *r)
231 struct winbindd_domain *domain = wb_child_domain();
233 if (domain == NULL) {
234 return NT_STATUS_REQUEST_NOT_ACCEPTED;
237 return domain->methods->query_user_list(
238 domain, p->mem_ctx, &r->out.users->num_userinfos,
239 &r->out.users->userinfos);
242 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
243 struct wbint_QueryGroupList *r)
245 struct winbindd_domain *domain = wb_child_domain();
246 uint32_t i, num_groups;
247 struct acct_info *groups;
248 struct wbint_Principal *result;
249 NTSTATUS status;
251 if (domain == NULL) {
252 return NT_STATUS_REQUEST_NOT_ACCEPTED;
255 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
256 &num_groups, &groups);
257 if (!NT_STATUS_IS_OK(status)) {
258 return status;
261 result = talloc_array(r->out.groups, struct wbint_Principal,
262 num_groups);
263 if (result == NULL) {
264 return NT_STATUS_NO_MEMORY;
267 for (i=0; i<num_groups; i++) {
268 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
269 result[i].type = SID_NAME_DOM_GRP;
270 result[i].name = talloc_strdup(result, groups[i].acct_name);
271 if (result[i].name == NULL) {
272 TALLOC_FREE(result);
273 TALLOC_FREE(groups);
274 return NT_STATUS_NO_MEMORY;
278 r->out.groups->num_principals = num_groups;
279 r->out.groups->principals = result;
281 TALLOC_FREE(groups);
282 return NT_STATUS_OK;
285 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
287 struct winbindd_domain *domain = wb_child_domain();
288 struct rpc_pipe_client *netlogon_pipe;
289 struct netr_DsRGetDCNameInfo *dc_info;
290 NTSTATUS status;
291 WERROR werr;
292 unsigned int orig_timeout;
294 if (domain == NULL) {
295 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
296 r->in.domain_name, r->in.domain_guid,
297 r->in.site_name ? r->in.site_name : "",
298 r->in.flags,
299 r->out.dc_info);
302 status = cm_connect_netlogon(domain, &netlogon_pipe);
304 if (!NT_STATUS_IS_OK(status)) {
305 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
306 return status;
309 /* This call can take a long time - allow the server to time out.
310 35 seconds should do it. */
312 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
314 if (domain->active_directory) {
315 status = rpccli_netr_DsRGetDCName(
316 netlogon_pipe, p->mem_ctx, domain->dcname,
317 r->in.domain_name, NULL, r->in.domain_guid,
318 r->in.flags, r->out.dc_info, &werr);
319 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
320 goto done;
325 * Fallback to less capable methods
328 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
329 if (dc_info == NULL) {
330 status = NT_STATUS_NO_MEMORY;
331 goto done;
334 if (r->in.flags & DS_PDC_REQUIRED) {
335 status = rpccli_netr_GetDcName(
336 netlogon_pipe, p->mem_ctx, domain->dcname,
337 r->in.domain_name, &dc_info->dc_unc, &werr);
338 } else {
339 status = rpccli_netr_GetAnyDCName(
340 netlogon_pipe, p->mem_ctx, domain->dcname,
341 r->in.domain_name, &dc_info->dc_unc, &werr);
344 if (!NT_STATUS_IS_OK(status)) {
345 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
346 nt_errstr(status)));
347 goto done;
349 if (!W_ERROR_IS_OK(werr)) {
350 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
351 win_errstr(werr)));
352 status = werror_to_ntstatus(werr);
353 goto done;
356 *r->out.dc_info = dc_info;
357 status = NT_STATUS_OK;
359 done:
360 /* And restore our original timeout. */
361 rpccli_set_timeout(netlogon_pipe, orig_timeout);
363 return status;
366 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
368 struct winbindd_domain *domain = wb_child_domain();
369 char *domain_name;
370 char **names;
371 enum lsa_SidType *types;
372 struct wbint_Principal *result;
373 NTSTATUS status;
374 int i;
376 if (domain == NULL) {
377 return NT_STATUS_REQUEST_NOT_ACCEPTED;
380 status = domain->methods->rids_to_names(
381 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
382 r->in.rids->num_rids, &domain_name, &names, &types);
383 if (!NT_STATUS_IS_OK(status)) {
384 return status;
387 result = talloc_array(p->mem_ctx, struct wbint_Principal,
388 r->in.rids->num_rids);
389 if (result == NULL) {
390 return NT_STATUS_NO_MEMORY;
393 for (i=0; i<r->in.rids->num_rids; i++) {
394 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
395 result[i].type = types[i];
396 result[i].name = talloc_move(result, &names[i]);
398 TALLOC_FREE(types);
399 TALLOC_FREE(names);
401 r->out.names->num_principals = r->in.rids->num_rids;
402 r->out.names->principals = result;
403 return NT_STATUS_OK;
406 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
407 struct wbint_CheckMachineAccount *r)
409 struct winbindd_domain *domain;
410 int num_retries = 0;
411 NTSTATUS status;
413 domain = wb_child_domain();
414 if (domain == NULL) {
415 return NT_STATUS_REQUEST_NOT_ACCEPTED;
418 again:
419 invalidate_cm_connection(&domain->conn);
422 struct rpc_pipe_client *netlogon_pipe;
423 status = cm_connect_netlogon(domain, &netlogon_pipe);
426 /* There is a race condition between fetching the trust account
427 password and the periodic machine password change. So it's
428 possible that the trust account password has been changed on us.
429 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
431 #define MAX_RETRIES 3
433 if ((num_retries < MAX_RETRIES)
434 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
435 num_retries++;
436 goto again;
439 if (!NT_STATUS_IS_OK(status)) {
440 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
441 goto done;
444 /* Pass back result code - zero for success, other values for
445 specific failures. */
447 DEBUG(3,("domain %s secret is %s\n", domain->name,
448 NT_STATUS_IS_OK(status) ? "good" : "bad"));
450 done:
451 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
452 ("Checking the trust account password for domain %s returned %s\n",
453 domain->name, nt_errstr(status)));
455 return status;
458 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
459 struct wbint_ChangeMachineAccount *r)
461 struct winbindd_domain *domain;
462 int num_retries = 0;
463 NTSTATUS status;
464 struct rpc_pipe_client *netlogon_pipe;
465 TALLOC_CTX *tmp_ctx;
467 again:
468 domain = wb_child_domain();
469 if (domain == NULL) {
470 return NT_STATUS_REQUEST_NOT_ACCEPTED;
473 invalidate_cm_connection(&domain->conn);
476 status = cm_connect_netlogon(domain, &netlogon_pipe);
479 /* There is a race condition between fetching the trust account
480 password and the periodic machine password change. So it's
481 possible that the trust account password has been changed on us.
482 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
484 #define MAX_RETRIES 3
486 if ((num_retries < MAX_RETRIES)
487 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
488 num_retries++;
489 goto again;
492 if (!NT_STATUS_IS_OK(status)) {
493 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
494 goto done;
497 tmp_ctx = talloc_new(p->mem_ctx);
499 status = trust_pw_find_change_and_store_it(netlogon_pipe,
500 tmp_ctx,
501 domain->name);
502 talloc_destroy(tmp_ctx);
504 /* Pass back result code - zero for success, other values for
505 specific failures. */
507 DEBUG(3,("domain %s secret %s\n", domain->name,
508 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
510 done:
511 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
512 ("Changing the trust account password for domain %s returned %s\n",
513 domain->name, nt_errstr(status)));
515 return status;
518 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
520 NTSTATUS status;
521 struct winbindd_domain *domain;
522 struct rpc_pipe_client *netlogon_pipe;
523 union netr_CONTROL_QUERY_INFORMATION info;
524 WERROR werr;
525 fstring logon_server;
527 domain = wb_child_domain();
528 if (domain == NULL) {
529 return NT_STATUS_REQUEST_NOT_ACCEPTED;
532 status = cm_connect_netlogon(domain, &netlogon_pipe);
533 if (!NT_STATUS_IS_OK(status)) {
534 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
535 return status;
538 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
541 * This provokes a WERR_NOT_SUPPORTED error message. This is
542 * documented in the wspp docs. I could not get a successful
543 * call to work, but the main point here is testing that the
544 * netlogon pipe works.
546 status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
547 logon_server, NETLOGON_CONTROL_QUERY,
548 2, &info, &werr);
550 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
551 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
552 invalidate_cm_connection(&domain->conn);
553 return status;
556 if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
557 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
558 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
559 nt_errstr(status)));
560 return status;
563 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
564 return NT_STATUS_OK;