Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * NetApi Join Support
4 : * Copyright (C) Guenther Deschner 2007-2008
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "ads.h"
22 : #include "librpc/gen_ndr/libnetapi.h"
23 : #include "libcli/auth/libcli_auth.h"
24 : #include "lib/netapi/netapi.h"
25 : #include "lib/netapi/netapi_private.h"
26 : #include "lib/netapi/libnetapi.h"
27 : #include "librpc/gen_ndr/libnet_join.h"
28 : #include "libnet/libnet_join.h"
29 : #include "../librpc/gen_ndr/ndr_wkssvc_c.h"
30 : #include "rpc_client/cli_pipe.h"
31 : #include "secrets.h"
32 : #include "libsmb/dsgetdcname.h"
33 : #include "../librpc/gen_ndr/ndr_ODJ.h"
34 : #include "lib/util/base64.h"
35 : #include "libnet/libnet_join_offline.h"
36 : #include "libcli/security/dom_sid.h"
37 :
38 : /****************************************************************
39 : ****************************************************************/
40 :
41 2 : WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
42 : struct NetJoinDomain *r)
43 : {
44 2 : struct libnet_JoinCtx *j = NULL;
45 0 : struct libnetapi_private_ctx *priv;
46 0 : WERROR werr;
47 :
48 2 : priv = talloc_get_type_abort(mem_ctx->private_data,
49 : struct libnetapi_private_ctx);
50 :
51 2 : if (!r->in.domain) {
52 0 : return WERR_INVALID_PARAMETER;
53 : }
54 :
55 2 : werr = libnet_init_JoinCtx(mem_ctx, &j);
56 2 : W_ERROR_NOT_OK_RETURN(werr);
57 :
58 2 : j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
59 2 : W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
60 :
61 2 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
62 0 : NTSTATUS status;
63 2 : struct netr_DsRGetDCNameInfo *info = NULL;
64 2 : const char *dc = NULL;
65 2 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
66 : DS_WRITABLE_REQUIRED |
67 : DS_RETURN_DNS_NAME;
68 2 : status = dsgetdcname(mem_ctx, priv->msg_ctx, r->in.domain,
69 : NULL, NULL, flags, &info);
70 2 : if (!NT_STATUS_IS_OK(status)) {
71 2 : libnetapi_set_error_string(mem_ctx,
72 : "%s", get_friendly_nt_error_msg(status));
73 2 : return ntstatus_to_werror(status);
74 : }
75 :
76 0 : dc = strip_hostname(info->dc_unc);
77 0 : j->in.dc_name = talloc_strdup(mem_ctx, dc);
78 0 : W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
79 : }
80 :
81 0 : if (r->in.account_ou) {
82 0 : j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
83 0 : W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
84 : }
85 :
86 0 : if (r->in.account != NULL) {
87 0 : NTSTATUS status;
88 :
89 0 : status = ads_simple_creds(j,
90 : r->in.domain,
91 : r->in.account,
92 : r->in.password,
93 0 : &j->in.admin_credentials);
94 0 : if (!NT_STATUS_IS_OK(status)) {
95 0 : TALLOC_FREE(j);
96 0 : return WERR_NERR_BADUSERNAME;
97 : }
98 : } else {
99 0 : libnetapi_get_creds(mem_ctx, &j->in.admin_credentials);
100 0 : if (j->in.admin_credentials == NULL) {
101 0 : TALLOC_FREE(j);
102 0 : return WERR_NERR_BADUSERNAME;
103 : }
104 : }
105 :
106 0 : j->in.join_flags = r->in.join_flags;
107 0 : j->in.modify_config = true;
108 0 : j->in.debug = true;
109 :
110 0 : werr = libnet_Join(mem_ctx, j);
111 0 : if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
112 0 : libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
113 : }
114 0 : TALLOC_FREE(j);
115 :
116 0 : return werr;
117 : }
118 :
119 : /****************************************************************
120 : ****************************************************************/
121 :
122 0 : WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
123 : struct NetJoinDomain *r)
124 : {
125 0 : struct rpc_pipe_client *pipe_cli = NULL;
126 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
127 0 : NTSTATUS status;
128 0 : WERROR werr;
129 0 : unsigned int old_timeout = 0;
130 0 : struct dcerpc_binding_handle *b;
131 0 : DATA_BLOB session_key;
132 :
133 0 : if (IS_DC) {
134 0 : return WERR_NERR_SETUPDOMAINCONTROLLER;
135 : }
136 :
137 0 : werr = libnetapi_open_pipe(ctx, r->in.server,
138 : &ndr_table_wkssvc,
139 : &pipe_cli);
140 0 : if (!W_ERROR_IS_OK(werr)) {
141 0 : goto done;
142 : }
143 :
144 0 : b = pipe_cli->binding_handle;
145 :
146 0 : if (r->in.password) {
147 :
148 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
149 0 : if (!NT_STATUS_IS_OK(status)) {
150 0 : werr = ntstatus_to_werror(status);
151 0 : goto done;
152 : }
153 :
154 0 : werr = encode_wkssvc_join_password_buffer(ctx,
155 : r->in.password,
156 : &session_key,
157 : &encrypted_password);
158 0 : if (!W_ERROR_IS_OK(werr)) {
159 0 : goto done;
160 : }
161 : }
162 :
163 0 : old_timeout = rpccli_set_timeout(pipe_cli, 600000);
164 :
165 0 : status = dcerpc_wkssvc_NetrJoinDomain2(b, talloc_tos(),
166 : r->in.server,
167 : r->in.domain,
168 : r->in.account_ou,
169 : r->in.account,
170 : encrypted_password,
171 : r->in.join_flags,
172 : &werr);
173 0 : if (!NT_STATUS_IS_OK(status)) {
174 0 : werr = ntstatus_to_werror(status);
175 0 : goto done;
176 : }
177 :
178 0 : done:
179 0 : if (pipe_cli && old_timeout) {
180 0 : rpccli_set_timeout(pipe_cli, old_timeout);
181 : }
182 :
183 0 : return werr;
184 : }
185 : /****************************************************************
186 : ****************************************************************/
187 :
188 0 : WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
189 : struct NetUnjoinDomain *r)
190 : {
191 0 : struct libnet_UnjoinCtx *u = NULL;
192 0 : struct dom_sid domain_sid;
193 0 : const char *domain = NULL;
194 0 : WERROR werr;
195 0 : struct libnetapi_private_ctx *priv;
196 0 : const char *realm = lp_realm();
197 :
198 0 : priv = talloc_get_type_abort(mem_ctx->private_data,
199 : struct libnetapi_private_ctx);
200 :
201 0 : if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
202 0 : return WERR_NERR_SETUPNOTJOINED;
203 : }
204 :
205 0 : werr = libnet_init_UnjoinCtx(mem_ctx, &u);
206 0 : W_ERROR_NOT_OK_RETURN(werr);
207 :
208 0 : if (realm[0] != '\0') {
209 0 : domain = realm;
210 : } else {
211 0 : domain = lp_workgroup();
212 : }
213 :
214 0 : if (r->in.server_name) {
215 0 : u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
216 0 : W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
217 : } else {
218 0 : NTSTATUS status;
219 0 : struct netr_DsRGetDCNameInfo *info = NULL;
220 0 : const char *dc = NULL;
221 0 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
222 : DS_WRITABLE_REQUIRED |
223 : DS_RETURN_DNS_NAME;
224 0 : status = dsgetdcname(mem_ctx, priv->msg_ctx, domain,
225 : NULL, NULL, flags, &info);
226 0 : if (!NT_STATUS_IS_OK(status)) {
227 0 : libnetapi_set_error_string(mem_ctx,
228 : "failed to find DC for domain %s: %s",
229 : domain,
230 : get_friendly_nt_error_msg(status));
231 0 : return ntstatus_to_werror(status);
232 : }
233 :
234 0 : dc = strip_hostname(info->dc_unc);
235 0 : u->in.dc_name = talloc_strdup(mem_ctx, dc);
236 0 : W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
237 :
238 0 : u->in.domain_name = domain;
239 : }
240 :
241 0 : if (r->in.account != NULL) {
242 0 : NTSTATUS status;
243 :
244 0 : status = ads_simple_creds(u,
245 : domain,
246 : r->in.account,
247 : r->in.password,
248 0 : &u->in.admin_credentials);
249 0 : if (!NT_STATUS_IS_OK(status)) {
250 0 : TALLOC_FREE(u);
251 0 : return WERR_NERR_BADUSERNAME;
252 : }
253 : } else {
254 0 : libnetapi_get_creds(mem_ctx, &u->in.admin_credentials);
255 0 : if (u->in.admin_credentials == NULL) {
256 0 : TALLOC_FREE(u);
257 0 : return WERR_NERR_BADUSERNAME;
258 : }
259 : }
260 :
261 0 : u->in.domain_name = domain;
262 0 : u->in.unjoin_flags = r->in.unjoin_flags;
263 0 : u->in.delete_machine_account = false;
264 0 : u->in.modify_config = true;
265 0 : u->in.debug = true;
266 :
267 0 : u->in.domain_sid = &domain_sid;
268 :
269 0 : werr = libnet_Unjoin(mem_ctx, u);
270 0 : if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
271 0 : libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
272 : }
273 0 : TALLOC_FREE(u);
274 :
275 0 : return werr;
276 : }
277 :
278 : /****************************************************************
279 : ****************************************************************/
280 :
281 0 : WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
282 : struct NetUnjoinDomain *r)
283 : {
284 0 : struct rpc_pipe_client *pipe_cli = NULL;
285 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
286 0 : NTSTATUS status;
287 0 : WERROR werr;
288 0 : unsigned int old_timeout = 0;
289 0 : struct dcerpc_binding_handle *b;
290 0 : DATA_BLOB session_key;
291 :
292 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
293 : &ndr_table_wkssvc,
294 : &pipe_cli);
295 0 : if (!W_ERROR_IS_OK(werr)) {
296 0 : goto done;
297 : }
298 :
299 0 : b = pipe_cli->binding_handle;
300 :
301 0 : if (r->in.password) {
302 :
303 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
304 0 : if (!NT_STATUS_IS_OK(status)) {
305 0 : werr = ntstatus_to_werror(status);
306 0 : goto done;
307 : }
308 :
309 0 : werr = encode_wkssvc_join_password_buffer(ctx,
310 : r->in.password,
311 : &session_key,
312 : &encrypted_password);
313 0 : if (!W_ERROR_IS_OK(werr)) {
314 0 : goto done;
315 : }
316 : }
317 :
318 0 : old_timeout = rpccli_set_timeout(pipe_cli, 60000);
319 :
320 0 : status = dcerpc_wkssvc_NetrUnjoinDomain2(b, talloc_tos(),
321 : r->in.server_name,
322 : r->in.account,
323 : encrypted_password,
324 : r->in.unjoin_flags,
325 : &werr);
326 0 : if (!NT_STATUS_IS_OK(status)) {
327 0 : werr = ntstatus_to_werror(status);
328 0 : goto done;
329 : }
330 :
331 0 : done:
332 0 : if (pipe_cli && old_timeout) {
333 0 : rpccli_set_timeout(pipe_cli, old_timeout);
334 : }
335 :
336 0 : return werr;
337 : }
338 :
339 : /****************************************************************
340 : ****************************************************************/
341 :
342 0 : WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
343 : struct NetGetJoinInformation *r)
344 : {
345 0 : struct rpc_pipe_client *pipe_cli = NULL;
346 0 : NTSTATUS status;
347 0 : WERROR werr;
348 0 : const char *buffer = NULL;
349 0 : struct dcerpc_binding_handle *b;
350 :
351 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
352 : &ndr_table_wkssvc,
353 : &pipe_cli);
354 0 : if (!W_ERROR_IS_OK(werr)) {
355 0 : goto done;
356 : }
357 :
358 0 : b = pipe_cli->binding_handle;
359 :
360 0 : status = dcerpc_wkssvc_NetrGetJoinInformation(b, talloc_tos(),
361 : r->in.server_name,
362 : &buffer,
363 0 : (enum wkssvc_NetJoinStatus *)r->out.name_type,
364 : &werr);
365 0 : if (!NT_STATUS_IS_OK(status)) {
366 0 : werr = ntstatus_to_werror(status);
367 0 : goto done;
368 : }
369 :
370 0 : if (!W_ERROR_IS_OK(werr)) {
371 0 : goto done;
372 : }
373 :
374 0 : *r->out.name_buffer = talloc_strdup(ctx, buffer);
375 0 : W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
376 :
377 0 : done:
378 0 : return werr;
379 : }
380 :
381 : /****************************************************************
382 : ****************************************************************/
383 :
384 0 : WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
385 : struct NetGetJoinInformation *r)
386 : {
387 0 : const char *realm = lp_realm();
388 :
389 0 : if ((lp_security() == SEC_ADS) && realm[0] != '\0') {
390 0 : *r->out.name_buffer = talloc_strdup(ctx, realm);
391 : } else {
392 0 : *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
393 : }
394 0 : if (!*r->out.name_buffer) {
395 0 : return WERR_NOT_ENOUGH_MEMORY;
396 : }
397 :
398 0 : switch (lp_server_role()) {
399 0 : case ROLE_DOMAIN_MEMBER:
400 : case ROLE_DOMAIN_PDC:
401 : case ROLE_DOMAIN_BDC:
402 : case ROLE_IPA_DC:
403 0 : *r->out.name_type = NetSetupDomainName;
404 0 : break;
405 0 : case ROLE_STANDALONE:
406 : default:
407 0 : *r->out.name_type = NetSetupWorkgroupName;
408 0 : break;
409 : }
410 :
411 0 : return WERR_OK;
412 : }
413 :
414 : /****************************************************************
415 : ****************************************************************/
416 :
417 0 : WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
418 : struct NetGetJoinableOUs *r)
419 : {
420 : #ifdef HAVE_ADS
421 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
422 0 : WERROR ret;
423 0 : NTSTATUS status;
424 0 : ADS_STATUS ads_status;
425 0 : ADS_STRUCT *ads = NULL;
426 0 : struct cli_credentials *creds = NULL;
427 0 : struct netr_DsRGetDCNameInfo *info = NULL;
428 0 : const char *dc = NULL;
429 0 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
430 : DS_RETURN_DNS_NAME;
431 0 : struct libnetapi_private_ctx *priv;
432 0 : char **p;
433 0 : size_t s;
434 :
435 0 : priv = talloc_get_type_abort(ctx->private_data,
436 : struct libnetapi_private_ctx);
437 :
438 0 : status = dsgetdcname(tmp_ctx, priv->msg_ctx, r->in.domain,
439 : NULL, NULL, flags, &info);
440 0 : if (!NT_STATUS_IS_OK(status)) {
441 0 : libnetapi_set_error_string(ctx, "%s",
442 : get_friendly_nt_error_msg(status));
443 0 : ret = ntstatus_to_werror(status);
444 0 : goto out;
445 : }
446 :
447 0 : dc = strip_hostname(info->dc_unc);
448 :
449 0 : ads = ads_init(tmp_ctx,
450 0 : info->domain_name,
451 0 : info->domain_name,
452 : dc,
453 : ADS_SASL_PLAIN);
454 0 : if (!ads) {
455 0 : ret = WERR_GEN_FAILURE;
456 0 : goto out;
457 : }
458 :
459 0 : if (r->in.account != NULL) {
460 0 : status = ads_simple_creds(ads,
461 : r->in.domain,
462 : r->in.account,
463 : r->in.password,
464 : &creds);
465 0 : if (!NT_STATUS_IS_OK(status)) {
466 0 : ret = WERR_NERR_DEFAULTJOINREQUIRED;
467 0 : goto out;
468 : }
469 : } else {
470 0 : libnetapi_get_creds(ctx, &creds);
471 : }
472 :
473 0 : ads_status = ads_connect_creds(ads, creds);
474 0 : if (!ADS_ERR_OK(ads_status)) {
475 0 : ret = WERR_NERR_DEFAULTJOINREQUIRED;
476 0 : goto out;
477 : }
478 :
479 0 : ads_status = ads_get_joinable_ous(ads, ctx, &p, &s);
480 0 : if (!ADS_ERR_OK(ads_status)) {
481 0 : ret = WERR_NERR_DEFAULTJOINREQUIRED;
482 0 : goto out;
483 : }
484 0 : *r->out.ous = discard_const_p(const char *, p);
485 0 : *r->out.ou_count = s;
486 :
487 0 : ret = WERR_OK;
488 0 : out:
489 0 : TALLOC_FREE(tmp_ctx);
490 :
491 0 : return ret;
492 : #else
493 0 : return WERR_NOT_SUPPORTED;
494 : #endif
495 : }
496 :
497 : /****************************************************************
498 : ****************************************************************/
499 :
500 0 : WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
501 : struct NetGetJoinableOUs *r)
502 : {
503 0 : struct rpc_pipe_client *pipe_cli = NULL;
504 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
505 0 : NTSTATUS status;
506 0 : WERROR werr;
507 0 : struct dcerpc_binding_handle *b;
508 0 : DATA_BLOB session_key;
509 :
510 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
511 : &ndr_table_wkssvc,
512 : &pipe_cli);
513 0 : if (!W_ERROR_IS_OK(werr)) {
514 0 : goto done;
515 : }
516 :
517 0 : b = pipe_cli->binding_handle;
518 :
519 0 : if (r->in.password) {
520 :
521 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
522 0 : if (!NT_STATUS_IS_OK(status)) {
523 0 : werr = ntstatus_to_werror(status);
524 0 : goto done;
525 : }
526 :
527 0 : werr = encode_wkssvc_join_password_buffer(ctx,
528 : r->in.password,
529 : &session_key,
530 : &encrypted_password);
531 0 : if (!W_ERROR_IS_OK(werr)) {
532 0 : goto done;
533 : }
534 : }
535 :
536 0 : status = dcerpc_wkssvc_NetrGetJoinableOus2(b, talloc_tos(),
537 : r->in.server_name,
538 : r->in.domain,
539 : r->in.account,
540 : encrypted_password,
541 : r->out.ou_count,
542 : r->out.ous,
543 : &werr);
544 0 : if (!NT_STATUS_IS_OK(status)) {
545 0 : werr = ntstatus_to_werror(status);
546 0 : goto done;
547 : }
548 :
549 0 : done:
550 0 : return werr;
551 : }
552 :
553 : /****************************************************************
554 : ****************************************************************/
555 :
556 0 : WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
557 : struct NetRenameMachineInDomain *r)
558 : {
559 0 : struct rpc_pipe_client *pipe_cli = NULL;
560 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
561 0 : NTSTATUS status;
562 0 : WERROR werr;
563 0 : struct dcerpc_binding_handle *b;
564 0 : DATA_BLOB session_key;
565 :
566 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
567 : &ndr_table_wkssvc,
568 : &pipe_cli);
569 0 : if (!W_ERROR_IS_OK(werr)) {
570 0 : goto done;
571 : }
572 :
573 0 : b = pipe_cli->binding_handle;
574 :
575 0 : if (r->in.password) {
576 :
577 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
578 0 : if (!NT_STATUS_IS_OK(status)) {
579 0 : werr = ntstatus_to_werror(status);
580 0 : goto done;
581 : }
582 :
583 0 : werr = encode_wkssvc_join_password_buffer(ctx,
584 : r->in.password,
585 : &session_key,
586 : &encrypted_password);
587 0 : if (!W_ERROR_IS_OK(werr)) {
588 0 : goto done;
589 : }
590 : }
591 :
592 0 : status = dcerpc_wkssvc_NetrRenameMachineInDomain2(b, talloc_tos(),
593 : r->in.server_name,
594 : r->in.new_machine_name,
595 : r->in.account,
596 : encrypted_password,
597 : r->in.rename_options,
598 : &werr);
599 0 : if (!NT_STATUS_IS_OK(status)) {
600 0 : werr = ntstatus_to_werror(status);
601 0 : goto done;
602 : }
603 :
604 0 : done:
605 0 : return werr;
606 : }
607 :
608 : /****************************************************************
609 : ****************************************************************/
610 :
611 0 : WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
612 : struct NetRenameMachineInDomain *r)
613 : {
614 0 : LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
615 : }
616 :
617 : /****************************************************************
618 : ****************************************************************/
619 :
620 0 : WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
621 : struct NetProvisionComputerAccount *r)
622 : {
623 0 : return NetProvisionComputerAccount_l(ctx, r);
624 : }
625 :
626 : /****************************************************************
627 : ****************************************************************/
628 :
629 12 : static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
630 : struct NetProvisionComputerAccount *r,
631 : TALLOC_CTX *mem_ctx,
632 : struct ODJ_PROVISION_DATA **p)
633 : {
634 0 : WERROR werr;
635 12 : struct libnet_JoinCtx *j = NULL;
636 :
637 12 : werr = libnet_init_JoinCtx(mem_ctx, &j);
638 12 : if (!W_ERROR_IS_OK(werr)) {
639 0 : return werr;
640 : }
641 :
642 12 : j->in.domain_name = talloc_strdup(j, r->in.domain);
643 12 : if (j->in.domain_name == NULL) {
644 0 : talloc_free(j);
645 0 : return WERR_NOT_ENOUGH_MEMORY;
646 : }
647 :
648 12 : talloc_free(discard_const_p(char *, j->in.machine_name));
649 12 : j->in.machine_name = talloc_strdup(j, r->in.machine_name);
650 12 : if (j->in.machine_name == NULL) {
651 0 : talloc_free(j);
652 0 : return WERR_NOT_ENOUGH_MEMORY;
653 : }
654 :
655 12 : if (r->in.dcname) {
656 4 : j->in.dc_name = talloc_strdup(j, r->in.dcname);
657 4 : if (j->in.dc_name == NULL) {
658 0 : talloc_free(j);
659 0 : return WERR_NOT_ENOUGH_MEMORY;
660 : }
661 : }
662 :
663 12 : if (r->in.machine_account_ou) {
664 0 : j->in.account_ou = talloc_strdup(j, r->in.machine_account_ou);
665 0 : if (j->in.account_ou == NULL) {
666 0 : talloc_free(j);
667 0 : return WERR_NOT_ENOUGH_MEMORY;
668 : }
669 : }
670 :
671 12 : libnetapi_get_creds(ctx, &j->in.admin_credentials);
672 12 : if (j->in.admin_credentials == NULL) {
673 0 : talloc_free(j);
674 0 : return WERR_NERR_BADUSERNAME;
675 : }
676 :
677 12 : j->in.debug = true;
678 12 : j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
679 : WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
680 :
681 12 : if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
682 0 : j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
683 : }
684 :
685 12 : if (r->in.options & NETSETUP_PROVISION_USE_DEFAULT_PASSWORD) {
686 6 : j->in.join_flags |= WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
687 6 : j->in.machine_password = talloc_strdup(j, r->in.machine_name);
688 6 : if (j->in.machine_password == NULL) {
689 0 : talloc_free(j);
690 0 : return WERR_NOT_ENOUGH_MEMORY;
691 : }
692 : }
693 :
694 12 : j->in.provision_computer_account_only = true;
695 :
696 12 : werr = libnet_Join(mem_ctx, j);
697 12 : if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
698 0 : libnetapi_set_error_string(ctx, "%s", j->out.error_string);
699 0 : talloc_free(j);
700 0 : return werr;
701 : }
702 :
703 12 : werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
704 12 : if (!W_ERROR_IS_OK(werr)) {
705 0 : talloc_free(j);
706 0 : return werr;
707 : }
708 :
709 12 : TALLOC_FREE(j);
710 :
711 12 : return WERR_OK;
712 : }
713 :
714 12 : WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
715 : struct NetProvisionComputerAccount *r)
716 : {
717 0 : WERROR werr;
718 0 : enum ndr_err_code ndr_err;
719 0 : const char *b64_bin_data_str;
720 0 : DATA_BLOB blob;
721 0 : struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
722 0 : struct ODJ_PROVISION_DATA *p;
723 12 : TALLOC_CTX *mem_ctx = talloc_new(ctx);
724 :
725 12 : if (r->in.provision_bin_data == NULL &&
726 12 : r->in.provision_text_data == NULL) {
727 0 : return WERR_INVALID_PARAMETER;
728 : }
729 12 : if (r->in.provision_bin_data != NULL &&
730 0 : r->in.provision_text_data != NULL) {
731 0 : return WERR_INVALID_PARAMETER;
732 : }
733 12 : if (r->in.provision_bin_data == NULL &&
734 12 : r->in.provision_bin_data_size != NULL) {
735 0 : return WERR_INVALID_PARAMETER;
736 : }
737 12 : if (r->in.provision_bin_data != NULL &&
738 0 : r->in.provision_bin_data_size == NULL) {
739 0 : return WERR_INVALID_PARAMETER;
740 : }
741 :
742 12 : if (r->in.domain == NULL) {
743 0 : return WERR_INVALID_PARAMETER;
744 : }
745 :
746 12 : if (r->in.machine_name == NULL) {
747 0 : return WERR_INVALID_PARAMETER;
748 : }
749 :
750 12 : werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
751 12 : if (!W_ERROR_IS_OK(werr)) {
752 0 : talloc_free(mem_ctx);
753 0 : return werr;
754 : }
755 :
756 12 : ZERO_STRUCT(odj_provision_data);
757 :
758 12 : odj_provision_data.s.p = p;
759 :
760 12 : ndr_err = ndr_push_struct_blob(&blob, ctx, &odj_provision_data,
761 : (ndr_push_flags_fn_t)ndr_push_ODJ_PROVISION_DATA_serialized_ptr);
762 12 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
763 0 : talloc_free(mem_ctx);
764 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
765 : }
766 :
767 12 : talloc_free(mem_ctx);
768 :
769 12 : if (r->out.provision_text_data != NULL) {
770 12 : b64_bin_data_str = base64_encode_data_blob(ctx, blob);
771 12 : if (b64_bin_data_str == NULL) {
772 0 : return WERR_NOT_ENOUGH_MEMORY;
773 : }
774 12 : *r->out.provision_text_data = b64_bin_data_str;
775 : }
776 :
777 12 : if (r->out.provision_bin_data != NULL &&
778 0 : r->out.provision_bin_data_size != NULL) {
779 0 : *r->out.provision_bin_data = blob.data;
780 0 : *r->out.provision_bin_data_size = blob.length;
781 : }
782 :
783 12 : return werr;
784 : }
785 :
786 : /****************************************************************
787 : ****************************************************************/
788 :
789 0 : WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
790 : struct NetRequestOfflineDomainJoin *r)
791 : {
792 0 : return WERR_NOT_SUPPORTED;
793 : }
794 :
795 : /****************************************************************
796 : ****************************************************************/
797 :
798 18 : static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
799 : const struct ODJ_WIN7BLOB *win7blob,
800 : const struct ODJ_PROVISION_DATA *odj_provision_data)
801 : {
802 18 : struct libnet_JoinCtx *j = NULL;
803 0 : WERROR werr;
804 :
805 18 : werr = libnet_init_JoinCtx(ctx, &j);
806 18 : if (!W_ERROR_IS_OK(werr)) {
807 0 : return werr;
808 : }
809 :
810 18 : j->in.domain_name = talloc_strdup(j, win7blob->lpDomain);
811 18 : if (j->in.domain_name == NULL) {
812 0 : talloc_free(j);
813 0 : return WERR_NOT_ENOUGH_MEMORY;
814 : }
815 :
816 18 : talloc_free(discard_const_p(char *, j->in.machine_name));
817 18 : j->in.machine_name = talloc_strdup(j, win7blob->lpMachineName);
818 18 : if (j->in.machine_name == NULL) {
819 0 : talloc_free(j);
820 0 : return WERR_NOT_ENOUGH_MEMORY;
821 : }
822 :
823 18 : j->in.machine_password = talloc_strdup(j, win7blob->lpMachinePassword);
824 18 : if (j->in.machine_password == NULL) {
825 0 : talloc_free(j);
826 0 : return WERR_NOT_ENOUGH_MEMORY;
827 : }
828 :
829 18 : j->in.request_offline_join = true;
830 18 : j->in.odj_provision_data = discard_const(odj_provision_data);
831 18 : j->in.debug = true;
832 18 : j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
833 : WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
834 :
835 18 : werr = libnet_Join(j, j);
836 18 : if (!W_ERROR_IS_OK(werr)) {
837 0 : if (j->out.error_string != NULL) {
838 0 : libnetapi_set_error_string(ctx, "%s", j->out.error_string);
839 : }
840 0 : talloc_free(j);
841 0 : return werr;
842 : }
843 :
844 18 : TALLOC_FREE(j);
845 :
846 18 : return WERR_OK;
847 : }
848 :
849 18 : WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
850 : struct NetRequestOfflineDomainJoin *r)
851 : {
852 0 : DATA_BLOB blob, blob_base64;
853 0 : enum ndr_err_code ndr_err;
854 0 : struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
855 0 : bool ok;
856 18 : struct ODJ_WIN7BLOB win7blob = { 0 };
857 0 : WERROR werr;
858 :
859 18 : if (r->in.provision_bin_data == NULL ||
860 18 : r->in.provision_bin_data_size == 0) {
861 0 : return W_ERROR(NERR_NoOfflineJoinInfo);
862 : }
863 :
864 18 : if (r->in.provision_bin_data_size < 2) {
865 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
866 : }
867 :
868 : /*
869 : * Windows produces and consumes UTF16/UCS2 encoded blobs. Check for the
870 : * unicode BOM mark and convert back to UNIX charset if necessary.
871 : */
872 18 : if (r->in.provision_bin_data[0] == 0xff &&
873 18 : r->in.provision_bin_data[1] == 0xfe) {
874 18 : ok = convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX,
875 18 : r->in.provision_bin_data+2,
876 18 : r->in.provision_bin_data_size-2,
877 : &blob_base64.data,
878 : &blob_base64.length);
879 18 : if (!ok) {
880 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
881 : }
882 : } else {
883 0 : blob_base64 = data_blob(r->in.provision_bin_data,
884 : r->in.provision_bin_data_size);
885 : }
886 :
887 18 : blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
888 :
889 18 : ndr_err = ndr_pull_struct_blob(&blob, ctx, &odj_provision_data,
890 : (ndr_pull_flags_fn_t)ndr_pull_ODJ_PROVISION_DATA_serialized_ptr);
891 18 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
892 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
893 : }
894 :
895 18 : if (DEBUGLEVEL >= 10) {
896 0 : NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
897 : }
898 :
899 18 : if (odj_provision_data.s.p->ulVersion != 1) {
900 0 : return W_ERROR(NERR_ProvisioningBlobUnsupported);
901 : }
902 :
903 18 : werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
904 18 : if (!W_ERROR_IS_OK(werr)) {
905 0 : return werr;
906 : }
907 :
908 18 : if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
909 0 : return WERR_NERR_SETUPNOTJOINED;
910 : }
911 :
912 18 : werr = NetRequestOfflineDomainJoin_backend(ctx,
913 : &win7blob,
914 18 : odj_provision_data.s.p);
915 18 : if (!W_ERROR_IS_OK(werr)) {
916 0 : return werr;
917 : }
918 :
919 18 : return W_ERROR(NERR_JoinPerformedMustRestart);
920 : }
921 :
922 : /****************************************************************
923 : ****************************************************************/
924 :
925 0 : WERROR NetComposeOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
926 : struct NetComposeOfflineDomainJoin *r)
927 : {
928 0 : return WERR_NOT_SUPPORTED;
929 : }
930 :
931 : /****************************************************************
932 : ****************************************************************/
933 :
934 6 : static WERROR NetComposeOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
935 : struct NetComposeOfflineDomainJoin *r,
936 : TALLOC_CTX *mem_ctx,
937 : struct ODJ_PROVISION_DATA **p)
938 : {
939 6 : struct libnet_JoinCtx *j = NULL;
940 0 : WERROR werr;
941 :
942 6 : werr = libnet_init_JoinCtx(ctx, &j);
943 6 : if (!W_ERROR_IS_OK(werr)) {
944 0 : return werr;
945 : }
946 :
947 6 : j->in.domain_name = talloc_strdup(j, r->in.dns_domain_name);
948 6 : if (j->in.domain_name == NULL) {
949 0 : return WERR_NOT_ENOUGH_MEMORY;
950 : }
951 :
952 6 : j->in.dc_name = talloc_strdup(j, r->in.dc_name);
953 6 : W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
954 :
955 6 : j->in.machine_password = talloc_strdup(j, r->in.machine_account_password);
956 6 : W_ERROR_HAVE_NO_MEMORY(j->in.machine_password);
957 :
958 6 : j->out.account_name = talloc_strdup(j, r->in.machine_account_name);
959 6 : W_ERROR_HAVE_NO_MEMORY(j->out.account_name);
960 :
961 6 : j->out.dns_domain_name = talloc_strdup(j, r->in.dns_domain_name);
962 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dns_domain_name);
963 :
964 6 : j->out.netbios_domain_name = talloc_strdup(j, r->in.netbios_domain_name);
965 6 : W_ERROR_HAVE_NO_MEMORY(j->out.netbios_domain_name);
966 :
967 6 : j->out.domain_sid = dom_sid_dup(j, (struct dom_sid *)r->in.domain_sid);
968 6 : W_ERROR_HAVE_NO_MEMORY(j->out.domain_sid);
969 :
970 6 : j->out.domain_guid = *r->in.domain_guid;
971 :
972 6 : j->out.forest_name = talloc_strdup(j, r->in.forest_name);
973 6 : W_ERROR_HAVE_NO_MEMORY(j->out.forest_name);
974 :
975 6 : j->out.domain_is_ad = r->in.domain_is_ad;
976 :
977 6 : j->out.dcinfo = talloc_zero(j, struct netr_DsRGetDCNameInfo);
978 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dcinfo);
979 :
980 6 : j->out.dcinfo->dc_unc = talloc_asprintf(j->out.dcinfo, "\\\\%s", r->in.dc_name);
981 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dcinfo->dc_unc);
982 :
983 6 : j->out.dcinfo->dc_address = talloc_asprintf(j->out.dcinfo, "\\\\%s", r->in.dc_address);
984 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dcinfo->dc_address);
985 :
986 6 : j->out.dcinfo->dc_address_type = DS_ADDRESS_TYPE_INET;
987 :
988 6 : j->out.dcinfo->domain_guid = *r->in.domain_guid;
989 :
990 6 : j->out.dcinfo->domain_name = talloc_strdup(j->out.dcinfo, r->in.dns_domain_name);
991 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dcinfo->domain_name);
992 :
993 6 : j->out.dcinfo->forest_name = talloc_strdup(j->out.dcinfo, r->in.forest_name);
994 6 : W_ERROR_HAVE_NO_MEMORY(j->out.dcinfo->forest_name);
995 :
996 6 : werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
997 6 : if (!W_ERROR_IS_OK(werr)) {
998 0 : return werr;
999 : }
1000 :
1001 6 : return WERR_OK;
1002 : }
1003 :
1004 6 : WERROR NetComposeOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
1005 : struct NetComposeOfflineDomainJoin *r)
1006 : {
1007 0 : WERROR werr;
1008 0 : enum ndr_err_code ndr_err;
1009 0 : const char *b64_bin_data_str;
1010 0 : DATA_BLOB blob;
1011 0 : struct ODJ_PROVISION_DATA_serialized_ptr odj_compose_data;
1012 0 : struct ODJ_PROVISION_DATA *p;
1013 6 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
1014 :
1015 6 : if (r->in.compose_bin_data == NULL &&
1016 6 : r->in.compose_text_data == NULL) {
1017 0 : werr = WERR_INVALID_PARAMETER;
1018 0 : goto out;
1019 : }
1020 6 : if (r->in.compose_bin_data != NULL &&
1021 0 : r->in.compose_text_data != NULL) {
1022 0 : werr = WERR_INVALID_PARAMETER;
1023 0 : goto out;
1024 : }
1025 6 : if (r->in.compose_bin_data == NULL &&
1026 6 : r->in.compose_bin_data_size != NULL) {
1027 0 : werr = WERR_INVALID_PARAMETER;
1028 0 : goto out;
1029 : }
1030 6 : if (r->in.compose_bin_data != NULL &&
1031 0 : r->in.compose_bin_data_size == NULL) {
1032 0 : werr = WERR_INVALID_PARAMETER;
1033 0 : goto out;
1034 : }
1035 :
1036 6 : if (r->in.dns_domain_name == NULL) {
1037 0 : werr = WERR_INVALID_PARAMETER;
1038 0 : goto out;
1039 : }
1040 :
1041 6 : if (r->in.netbios_domain_name == NULL) {
1042 0 : werr = WERR_INVALID_PARAMETER;
1043 0 : goto out;
1044 : }
1045 :
1046 6 : if (r->in.domain_sid == NULL) {
1047 0 : werr = WERR_INVALID_PARAMETER;
1048 0 : goto out;
1049 : }
1050 :
1051 6 : if (r->in.domain_guid == NULL) {
1052 0 : werr = WERR_INVALID_PARAMETER;
1053 0 : goto out;
1054 : }
1055 :
1056 6 : if (r->in.forest_name == NULL) {
1057 0 : werr = WERR_INVALID_PARAMETER;
1058 0 : goto out;
1059 : }
1060 :
1061 6 : if (r->in.machine_account_name == NULL) {
1062 0 : werr = WERR_INVALID_PARAMETER;
1063 0 : goto out;
1064 : }
1065 :
1066 6 : if (r->in.machine_account_password == NULL) {
1067 0 : werr = WERR_INVALID_PARAMETER;
1068 0 : goto out;
1069 : }
1070 :
1071 6 : if (r->in.dc_name == NULL) {
1072 0 : werr = WERR_INVALID_PARAMETER;
1073 0 : goto out;
1074 : }
1075 :
1076 6 : if (r->in.dc_address == NULL) {
1077 0 : werr = WERR_INVALID_PARAMETER;
1078 0 : goto out;
1079 : }
1080 :
1081 6 : werr = NetComposeOfflineDomainJoin_backend(ctx, r, tmp_ctx, &p);
1082 6 : if (!W_ERROR_IS_OK(werr)) {
1083 0 : goto out;
1084 : }
1085 :
1086 6 : ZERO_STRUCT(odj_compose_data);
1087 :
1088 6 : odj_compose_data.s.p = p;
1089 :
1090 6 : ndr_err = ndr_push_struct_blob(&blob, ctx, &odj_compose_data,
1091 : (ndr_push_flags_fn_t)ndr_push_ODJ_PROVISION_DATA_serialized_ptr);
1092 6 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1093 0 : werr = W_ERROR(NERR_BadOfflineJoinInfo);
1094 0 : goto out;
1095 : }
1096 :
1097 6 : if (r->out.compose_text_data != NULL) {
1098 6 : b64_bin_data_str = base64_encode_data_blob(ctx, blob);
1099 6 : if (b64_bin_data_str == NULL) {
1100 0 : werr = WERR_NOT_ENOUGH_MEMORY;
1101 : }
1102 6 : *r->out.compose_text_data = b64_bin_data_str;
1103 : }
1104 :
1105 6 : if (r->out.compose_bin_data != NULL &&
1106 0 : r->out.compose_bin_data_size != NULL) {
1107 0 : *r->out.compose_bin_data = blob.data;
1108 0 : *r->out.compose_bin_data_size = blob.length;
1109 : }
1110 :
1111 6 : werr = WERR_OK;
1112 6 : out:
1113 6 : talloc_free(tmp_ctx);
1114 6 : return werr;
1115 : }
|