s4-pfm_verify: fix usage string
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blobb661fb37e44b4f5b82881b7461a6a254ca3db9c3
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"
29 #include "../libcli/security/security.h"
31 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
33 *r->out.out_data = r->in.in_data;
36 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
38 struct winbindd_domain *domain = wb_child_domain();
39 char *dom_name;
40 char *name;
41 enum lsa_SidType type;
42 NTSTATUS status;
44 if (domain == NULL) {
45 return NT_STATUS_REQUEST_NOT_ACCEPTED;
48 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
49 &dom_name, &name, &type);
50 if (!NT_STATUS_IS_OK(status)) {
51 return status;
54 *r->out.domain = dom_name;
55 *r->out.name = name;
56 *r->out.type = type;
57 return NT_STATUS_OK;
60 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
62 struct winbindd_domain *domain = wb_child_domain();
64 if (domain == NULL) {
65 return NT_STATUS_REQUEST_NOT_ACCEPTED;
68 return domain->methods->name_to_sid(
69 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
70 r->out.sid, r->out.type);
73 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
75 uid_t uid;
76 NTSTATUS status;
78 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
79 r->in.sid, &uid);
80 if (!NT_STATUS_IS_OK(status)) {
81 return status;
83 *r->out.uid = uid;
84 return NT_STATUS_OK;
87 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
89 gid_t gid;
90 NTSTATUS status;
92 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
93 r->in.sid, &gid);
94 if (!NT_STATUS_IS_OK(status)) {
95 return status;
97 *r->out.gid = gid;
98 return NT_STATUS_OK;
101 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
103 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
104 r->out.sid, r->in.uid);
107 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
109 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
110 r->out.sid, r->in.gid);
113 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
115 struct unixid xid;
116 NTSTATUS status;
118 status = idmap_allocate_uid(&xid);
119 if (!NT_STATUS_IS_OK(status)) {
120 return status;
122 *r->out.uid = xid.id;
123 return NT_STATUS_OK;
126 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
128 struct unixid xid;
129 NTSTATUS status;
131 status = idmap_allocate_gid(&xid);
132 if (!NT_STATUS_IS_OK(status)) {
133 return status;
135 *r->out.gid = xid.id;
136 return NT_STATUS_OK;
139 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
141 struct winbindd_domain *domain = wb_child_domain();
143 if (domain == NULL) {
144 return NT_STATUS_REQUEST_NOT_ACCEPTED;
147 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
148 r->out.info);
151 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
152 struct wbint_LookupUserAliases *r)
154 struct winbindd_domain *domain = wb_child_domain();
156 if (domain == NULL) {
157 return NT_STATUS_REQUEST_NOT_ACCEPTED;
160 return domain->methods->lookup_useraliases(
161 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
162 &r->out.rids->num_rids, &r->out.rids->rids);
165 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
166 struct wbint_LookupUserGroups *r)
168 struct winbindd_domain *domain = wb_child_domain();
170 if (domain == NULL) {
171 return NT_STATUS_REQUEST_NOT_ACCEPTED;
174 return domain->methods->lookup_usergroups(
175 domain, p->mem_ctx, r->in.sid,
176 &r->out.sids->num_sids, &r->out.sids->sids);
179 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
180 struct wbint_QuerySequenceNumber *r)
182 struct winbindd_domain *domain = wb_child_domain();
184 if (domain == NULL) {
185 return NT_STATUS_REQUEST_NOT_ACCEPTED;
188 return domain->methods->sequence_number(domain, r->out.sequence);
191 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
192 struct wbint_LookupGroupMembers *r)
194 struct winbindd_domain *domain = wb_child_domain();
195 uint32_t i, num_names;
196 struct dom_sid *sid_mem;
197 char **names;
198 uint32_t *name_types;
199 NTSTATUS status;
201 if (domain == NULL) {
202 return NT_STATUS_REQUEST_NOT_ACCEPTED;
205 status = domain->methods->lookup_groupmem(
206 domain, p->mem_ctx, r->in.sid, r->in.type,
207 &num_names, &sid_mem, &names, &name_types);
208 if (!NT_STATUS_IS_OK(status)) {
209 return status;
212 r->out.members->num_principals = num_names;
213 r->out.members->principals = talloc_array(
214 r->out.members, struct wbint_Principal, num_names);
215 if (r->out.members->principals == NULL) {
216 return NT_STATUS_NO_MEMORY;
219 for (i=0; i<num_names; i++) {
220 struct wbint_Principal *m = &r->out.members->principals[i];
221 sid_copy(&m->sid, &sid_mem[i]);
222 m->name = talloc_move(r->out.members->principals, &names[i]);
223 m->type = (enum lsa_SidType)name_types[i];
226 return NT_STATUS_OK;
229 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
230 struct wbint_QueryUserList *r)
232 struct winbindd_domain *domain = wb_child_domain();
234 if (domain == NULL) {
235 return NT_STATUS_REQUEST_NOT_ACCEPTED;
238 return domain->methods->query_user_list(
239 domain, p->mem_ctx, &r->out.users->num_userinfos,
240 &r->out.users->userinfos);
243 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
244 struct wbint_QueryGroupList *r)
246 struct winbindd_domain *domain = wb_child_domain();
247 uint32_t i, num_groups;
248 struct acct_info *groups;
249 struct wbint_Principal *result;
250 NTSTATUS status;
252 if (domain == NULL) {
253 return NT_STATUS_REQUEST_NOT_ACCEPTED;
256 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
257 &num_groups, &groups);
258 if (!NT_STATUS_IS_OK(status)) {
259 return status;
262 result = talloc_array(r->out.groups, struct wbint_Principal,
263 num_groups);
264 if (result == NULL) {
265 return NT_STATUS_NO_MEMORY;
268 for (i=0; i<num_groups; i++) {
269 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
270 result[i].type = SID_NAME_DOM_GRP;
271 result[i].name = talloc_strdup(result, groups[i].acct_name);
272 if (result[i].name == NULL) {
273 TALLOC_FREE(result);
274 TALLOC_FREE(groups);
275 return NT_STATUS_NO_MEMORY;
279 r->out.groups->num_principals = num_groups;
280 r->out.groups->principals = result;
282 TALLOC_FREE(groups);
283 return NT_STATUS_OK;
286 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
288 struct winbindd_domain *domain = wb_child_domain();
289 struct rpc_pipe_client *netlogon_pipe;
290 struct netr_DsRGetDCNameInfo *dc_info;
291 NTSTATUS status;
292 WERROR werr;
293 unsigned int orig_timeout;
295 if (domain == NULL) {
296 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
297 r->in.domain_name, r->in.domain_guid,
298 r->in.site_name ? r->in.site_name : "",
299 r->in.flags,
300 r->out.dc_info);
303 status = cm_connect_netlogon(domain, &netlogon_pipe);
305 if (!NT_STATUS_IS_OK(status)) {
306 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
307 return status;
310 /* This call can take a long time - allow the server to time out.
311 35 seconds should do it. */
313 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
315 if (domain->active_directory) {
316 status = rpccli_netr_DsRGetDCName(
317 netlogon_pipe, p->mem_ctx, domain->dcname,
318 r->in.domain_name, NULL, r->in.domain_guid,
319 r->in.flags, r->out.dc_info, &werr);
320 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
321 goto done;
326 * Fallback to less capable methods
329 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
330 if (dc_info == NULL) {
331 status = NT_STATUS_NO_MEMORY;
332 goto done;
335 if (r->in.flags & DS_PDC_REQUIRED) {
336 status = rpccli_netr_GetDcName(
337 netlogon_pipe, p->mem_ctx, domain->dcname,
338 r->in.domain_name, &dc_info->dc_unc, &werr);
339 } else {
340 status = rpccli_netr_GetAnyDCName(
341 netlogon_pipe, p->mem_ctx, domain->dcname,
342 r->in.domain_name, &dc_info->dc_unc, &werr);
345 if (!NT_STATUS_IS_OK(status)) {
346 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
347 nt_errstr(status)));
348 goto done;
350 if (!W_ERROR_IS_OK(werr)) {
351 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
352 win_errstr(werr)));
353 status = werror_to_ntstatus(werr);
354 goto done;
357 *r->out.dc_info = dc_info;
358 status = NT_STATUS_OK;
360 done:
361 /* And restore our original timeout. */
362 rpccli_set_timeout(netlogon_pipe, orig_timeout);
364 return status;
367 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
369 struct winbindd_domain *domain = wb_child_domain();
370 char *domain_name;
371 char **names;
372 enum lsa_SidType *types;
373 struct wbint_Principal *result;
374 NTSTATUS status;
375 int i;
377 if (domain == NULL) {
378 return NT_STATUS_REQUEST_NOT_ACCEPTED;
381 status = domain->methods->rids_to_names(
382 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
383 r->in.rids->num_rids, &domain_name, &names, &types);
384 if (!NT_STATUS_IS_OK(status)) {
385 return status;
388 result = talloc_array(p->mem_ctx, struct wbint_Principal,
389 r->in.rids->num_rids);
390 if (result == NULL) {
391 return NT_STATUS_NO_MEMORY;
394 for (i=0; i<r->in.rids->num_rids; i++) {
395 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
396 result[i].type = types[i];
397 result[i].name = talloc_move(result, &names[i]);
399 TALLOC_FREE(types);
400 TALLOC_FREE(names);
402 r->out.names->num_principals = r->in.rids->num_rids;
403 r->out.names->principals = result;
404 return NT_STATUS_OK;
407 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
408 struct wbint_CheckMachineAccount *r)
410 struct winbindd_domain *domain;
411 int num_retries = 0;
412 NTSTATUS status;
414 domain = wb_child_domain();
415 if (domain == NULL) {
416 return NT_STATUS_REQUEST_NOT_ACCEPTED;
419 again:
420 invalidate_cm_connection(&domain->conn);
423 struct rpc_pipe_client *netlogon_pipe;
424 status = cm_connect_netlogon(domain, &netlogon_pipe);
427 /* There is a race condition between fetching the trust account
428 password and the periodic machine password change. So it's
429 possible that the trust account password has been changed on us.
430 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
432 #define MAX_RETRIES 3
434 if ((num_retries < MAX_RETRIES)
435 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
436 num_retries++;
437 goto again;
440 if (!NT_STATUS_IS_OK(status)) {
441 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
442 goto done;
445 /* Pass back result code - zero for success, other values for
446 specific failures. */
448 DEBUG(3,("domain %s secret is %s\n", domain->name,
449 NT_STATUS_IS_OK(status) ? "good" : "bad"));
451 done:
452 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
453 ("Checking the trust account password for domain %s returned %s\n",
454 domain->name, nt_errstr(status)));
456 return status;
459 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
460 struct wbint_ChangeMachineAccount *r)
462 struct winbindd_domain *domain;
463 int num_retries = 0;
464 NTSTATUS status;
465 struct rpc_pipe_client *netlogon_pipe;
466 TALLOC_CTX *tmp_ctx;
468 again:
469 domain = wb_child_domain();
470 if (domain == NULL) {
471 return NT_STATUS_REQUEST_NOT_ACCEPTED;
474 invalidate_cm_connection(&domain->conn);
477 status = cm_connect_netlogon(domain, &netlogon_pipe);
480 /* There is a race condition between fetching the trust account
481 password and the periodic machine password change. So it's
482 possible that the trust account password has been changed on us.
483 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
485 #define MAX_RETRIES 3
487 if ((num_retries < MAX_RETRIES)
488 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
489 num_retries++;
490 goto again;
493 if (!NT_STATUS_IS_OK(status)) {
494 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
495 goto done;
498 tmp_ctx = talloc_new(p->mem_ctx);
500 status = trust_pw_find_change_and_store_it(netlogon_pipe,
501 tmp_ctx,
502 domain->name);
503 talloc_destroy(tmp_ctx);
505 /* Pass back result code - zero for success, other values for
506 specific failures. */
508 DEBUG(3,("domain %s secret %s\n", domain->name,
509 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
511 done:
512 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
513 ("Changing the trust account password for domain %s returned %s\n",
514 domain->name, nt_errstr(status)));
516 return status;
519 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
521 NTSTATUS status;
522 struct winbindd_domain *domain;
523 struct rpc_pipe_client *netlogon_pipe;
524 union netr_CONTROL_QUERY_INFORMATION info;
525 WERROR werr;
526 fstring logon_server;
528 domain = wb_child_domain();
529 if (domain == NULL) {
530 return NT_STATUS_REQUEST_NOT_ACCEPTED;
533 status = cm_connect_netlogon(domain, &netlogon_pipe);
534 if (!NT_STATUS_IS_OK(status)) {
535 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
536 return status;
539 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
542 * This provokes a WERR_NOT_SUPPORTED error message. This is
543 * documented in the wspp docs. I could not get a successful
544 * call to work, but the main point here is testing that the
545 * netlogon pipe works.
547 status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
548 logon_server, NETLOGON_CONTROL_QUERY,
549 2, &info, &werr);
551 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
552 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
553 invalidate_cm_connection(&domain->conn);
554 return status;
557 if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
558 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
559 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
560 nt_errstr(status)));
561 return status;
564 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
565 return NT_STATUS_OK;