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 :
37 : /****************************************************************
38 : ****************************************************************/
39 :
40 2 : WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
41 : struct NetJoinDomain *r)
42 : {
43 2 : struct libnet_JoinCtx *j = NULL;
44 : struct libnetapi_private_ctx *priv;
45 : WERROR werr;
46 :
47 2 : priv = talloc_get_type_abort(mem_ctx->private_data,
48 : struct libnetapi_private_ctx);
49 :
50 2 : if (!r->in.domain) {
51 0 : return WERR_INVALID_PARAMETER;
52 : }
53 :
54 2 : werr = libnet_init_JoinCtx(mem_ctx, &j);
55 2 : W_ERROR_NOT_OK_RETURN(werr);
56 :
57 2 : j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
58 2 : W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
59 :
60 2 : if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
61 : NTSTATUS status;
62 2 : struct netr_DsRGetDCNameInfo *info = NULL;
63 2 : const char *dc = NULL;
64 2 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
65 : DS_WRITABLE_REQUIRED |
66 : DS_RETURN_DNS_NAME;
67 2 : status = dsgetdcname(mem_ctx, priv->msg_ctx, r->in.domain,
68 : NULL, NULL, flags, &info);
69 2 : if (!NT_STATUS_IS_OK(status)) {
70 2 : libnetapi_set_error_string(mem_ctx,
71 : "%s", get_friendly_nt_error_msg(status));
72 4 : return ntstatus_to_werror(status);
73 : }
74 :
75 0 : dc = strip_hostname(info->dc_unc);
76 0 : j->in.dc_name = talloc_strdup(mem_ctx, dc);
77 0 : W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
78 : }
79 :
80 0 : if (r->in.account_ou) {
81 0 : j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
82 0 : W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
83 : }
84 :
85 0 : if (r->in.account) {
86 0 : j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
87 0 : W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
88 : }
89 :
90 0 : if (r->in.password) {
91 0 : j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
92 0 : W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
93 : }
94 :
95 0 : j->in.join_flags = r->in.join_flags;
96 0 : j->in.modify_config = true;
97 0 : j->in.debug = true;
98 :
99 0 : werr = libnet_Join(mem_ctx, j);
100 0 : if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
101 0 : libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
102 : }
103 0 : TALLOC_FREE(j);
104 :
105 0 : return werr;
106 : }
107 :
108 : /****************************************************************
109 : ****************************************************************/
110 :
111 0 : WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
112 : struct NetJoinDomain *r)
113 : {
114 0 : struct rpc_pipe_client *pipe_cli = NULL;
115 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
116 : NTSTATUS status;
117 : WERROR werr;
118 0 : unsigned int old_timeout = 0;
119 : struct dcerpc_binding_handle *b;
120 : DATA_BLOB session_key;
121 :
122 0 : if (IS_DC) {
123 0 : return WERR_NERR_SETUPDOMAINCONTROLLER;
124 : }
125 :
126 0 : werr = libnetapi_open_pipe(ctx, r->in.server,
127 : &ndr_table_wkssvc,
128 : &pipe_cli);
129 0 : if (!W_ERROR_IS_OK(werr)) {
130 0 : goto done;
131 : }
132 :
133 0 : b = pipe_cli->binding_handle;
134 :
135 0 : if (r->in.password) {
136 :
137 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
138 0 : if (!NT_STATUS_IS_OK(status)) {
139 0 : werr = ntstatus_to_werror(status);
140 0 : goto done;
141 : }
142 :
143 0 : werr = encode_wkssvc_join_password_buffer(ctx,
144 : r->in.password,
145 : &session_key,
146 : &encrypted_password);
147 0 : if (!W_ERROR_IS_OK(werr)) {
148 0 : goto done;
149 : }
150 : }
151 :
152 0 : old_timeout = rpccli_set_timeout(pipe_cli, 600000);
153 :
154 0 : status = dcerpc_wkssvc_NetrJoinDomain2(b, talloc_tos(),
155 : r->in.server,
156 : r->in.domain,
157 : r->in.account_ou,
158 : r->in.account,
159 : encrypted_password,
160 : r->in.join_flags,
161 : &werr);
162 0 : if (!NT_STATUS_IS_OK(status)) {
163 0 : werr = ntstatus_to_werror(status);
164 0 : goto done;
165 : }
166 :
167 0 : done:
168 0 : if (pipe_cli && old_timeout) {
169 0 : rpccli_set_timeout(pipe_cli, old_timeout);
170 : }
171 :
172 0 : return werr;
173 : }
174 : /****************************************************************
175 : ****************************************************************/
176 :
177 0 : WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
178 : struct NetUnjoinDomain *r)
179 : {
180 0 : struct libnet_UnjoinCtx *u = NULL;
181 : struct dom_sid domain_sid;
182 0 : const char *domain = NULL;
183 : WERROR werr;
184 : struct libnetapi_private_ctx *priv;
185 0 : const char *realm = lp_realm();
186 :
187 0 : priv = talloc_get_type_abort(mem_ctx->private_data,
188 : struct libnetapi_private_ctx);
189 :
190 0 : if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
191 0 : return WERR_NERR_SETUPNOTJOINED;
192 : }
193 :
194 0 : werr = libnet_init_UnjoinCtx(mem_ctx, &u);
195 0 : W_ERROR_NOT_OK_RETURN(werr);
196 :
197 0 : if (realm[0] != '\0') {
198 0 : domain = realm;
199 : } else {
200 0 : domain = lp_workgroup();
201 : }
202 :
203 0 : if (r->in.server_name) {
204 0 : u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
205 0 : W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
206 : } else {
207 : NTSTATUS status;
208 0 : struct netr_DsRGetDCNameInfo *info = NULL;
209 0 : const char *dc = NULL;
210 0 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
211 : DS_WRITABLE_REQUIRED |
212 : DS_RETURN_DNS_NAME;
213 0 : status = dsgetdcname(mem_ctx, priv->msg_ctx, domain,
214 : NULL, NULL, flags, &info);
215 0 : if (!NT_STATUS_IS_OK(status)) {
216 0 : libnetapi_set_error_string(mem_ctx,
217 : "failed to find DC for domain %s: %s",
218 : domain,
219 : get_friendly_nt_error_msg(status));
220 0 : return ntstatus_to_werror(status);
221 : }
222 :
223 0 : dc = strip_hostname(info->dc_unc);
224 0 : u->in.dc_name = talloc_strdup(mem_ctx, dc);
225 0 : W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
226 :
227 0 : u->in.domain_name = domain;
228 : }
229 :
230 0 : if (r->in.account) {
231 0 : u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
232 0 : W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
233 : }
234 :
235 0 : if (r->in.password) {
236 0 : u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
237 0 : W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
238 : }
239 :
240 0 : u->in.domain_name = domain;
241 0 : u->in.unjoin_flags = r->in.unjoin_flags;
242 0 : u->in.delete_machine_account = false;
243 0 : u->in.modify_config = true;
244 0 : u->in.debug = true;
245 :
246 0 : u->in.domain_sid = &domain_sid;
247 :
248 0 : werr = libnet_Unjoin(mem_ctx, u);
249 0 : if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
250 0 : libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
251 : }
252 0 : TALLOC_FREE(u);
253 :
254 0 : return werr;
255 : }
256 :
257 : /****************************************************************
258 : ****************************************************************/
259 :
260 0 : WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
261 : struct NetUnjoinDomain *r)
262 : {
263 0 : struct rpc_pipe_client *pipe_cli = NULL;
264 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
265 : NTSTATUS status;
266 : WERROR werr;
267 0 : unsigned int old_timeout = 0;
268 : struct dcerpc_binding_handle *b;
269 : DATA_BLOB session_key;
270 :
271 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
272 : &ndr_table_wkssvc,
273 : &pipe_cli);
274 0 : if (!W_ERROR_IS_OK(werr)) {
275 0 : goto done;
276 : }
277 :
278 0 : b = pipe_cli->binding_handle;
279 :
280 0 : if (r->in.password) {
281 :
282 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
283 0 : if (!NT_STATUS_IS_OK(status)) {
284 0 : werr = ntstatus_to_werror(status);
285 0 : goto done;
286 : }
287 :
288 0 : werr = encode_wkssvc_join_password_buffer(ctx,
289 : r->in.password,
290 : &session_key,
291 : &encrypted_password);
292 0 : if (!W_ERROR_IS_OK(werr)) {
293 0 : goto done;
294 : }
295 : }
296 :
297 0 : old_timeout = rpccli_set_timeout(pipe_cli, 60000);
298 :
299 0 : status = dcerpc_wkssvc_NetrUnjoinDomain2(b, talloc_tos(),
300 : r->in.server_name,
301 : r->in.account,
302 : encrypted_password,
303 : r->in.unjoin_flags,
304 : &werr);
305 0 : if (!NT_STATUS_IS_OK(status)) {
306 0 : werr = ntstatus_to_werror(status);
307 0 : goto done;
308 : }
309 :
310 0 : done:
311 0 : if (pipe_cli && old_timeout) {
312 0 : rpccli_set_timeout(pipe_cli, old_timeout);
313 : }
314 :
315 0 : return werr;
316 : }
317 :
318 : /****************************************************************
319 : ****************************************************************/
320 :
321 0 : WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
322 : struct NetGetJoinInformation *r)
323 : {
324 0 : struct rpc_pipe_client *pipe_cli = NULL;
325 : NTSTATUS status;
326 : WERROR werr;
327 0 : const char *buffer = NULL;
328 : struct dcerpc_binding_handle *b;
329 :
330 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
331 : &ndr_table_wkssvc,
332 : &pipe_cli);
333 0 : if (!W_ERROR_IS_OK(werr)) {
334 0 : goto done;
335 : }
336 :
337 0 : b = pipe_cli->binding_handle;
338 :
339 0 : status = dcerpc_wkssvc_NetrGetJoinInformation(b, talloc_tos(),
340 : r->in.server_name,
341 : &buffer,
342 0 : (enum wkssvc_NetJoinStatus *)r->out.name_type,
343 : &werr);
344 0 : if (!NT_STATUS_IS_OK(status)) {
345 0 : werr = ntstatus_to_werror(status);
346 0 : goto done;
347 : }
348 :
349 0 : if (!W_ERROR_IS_OK(werr)) {
350 0 : goto done;
351 : }
352 :
353 0 : *r->out.name_buffer = talloc_strdup(ctx, buffer);
354 0 : W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
355 :
356 0 : done:
357 0 : return werr;
358 : }
359 :
360 : /****************************************************************
361 : ****************************************************************/
362 :
363 0 : WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
364 : struct NetGetJoinInformation *r)
365 : {
366 0 : const char *realm = lp_realm();
367 :
368 0 : if ((lp_security() == SEC_ADS) && realm[0] != '\0') {
369 0 : *r->out.name_buffer = talloc_strdup(ctx, realm);
370 : } else {
371 0 : *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
372 : }
373 0 : if (!*r->out.name_buffer) {
374 0 : return WERR_NOT_ENOUGH_MEMORY;
375 : }
376 :
377 0 : switch (lp_server_role()) {
378 0 : case ROLE_DOMAIN_MEMBER:
379 : case ROLE_DOMAIN_PDC:
380 : case ROLE_DOMAIN_BDC:
381 0 : *r->out.name_type = NetSetupDomainName;
382 0 : break;
383 0 : case ROLE_STANDALONE:
384 : default:
385 0 : *r->out.name_type = NetSetupWorkgroupName;
386 0 : break;
387 : }
388 :
389 0 : return WERR_OK;
390 : }
391 :
392 : /****************************************************************
393 : ****************************************************************/
394 :
395 0 : WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
396 : struct NetGetJoinableOUs *r)
397 : {
398 : #ifdef HAVE_ADS
399 : NTSTATUS status;
400 : ADS_STATUS ads_status;
401 0 : ADS_STRUCT *ads = NULL;
402 0 : struct netr_DsRGetDCNameInfo *info = NULL;
403 0 : const char *dc = NULL;
404 0 : uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
405 : DS_RETURN_DNS_NAME;
406 : struct libnetapi_private_ctx *priv;
407 : char **p;
408 : size_t s;
409 :
410 0 : priv = talloc_get_type_abort(ctx->private_data,
411 : struct libnetapi_private_ctx);
412 :
413 0 : status = dsgetdcname(ctx, priv->msg_ctx, r->in.domain,
414 : NULL, NULL, flags, &info);
415 0 : if (!NT_STATUS_IS_OK(status)) {
416 0 : libnetapi_set_error_string(ctx, "%s",
417 : get_friendly_nt_error_msg(status));
418 0 : return ntstatus_to_werror(status);
419 : }
420 :
421 0 : dc = strip_hostname(info->dc_unc);
422 :
423 0 : ads = ads_init(info->domain_name,
424 0 : info->domain_name,
425 : dc,
426 : ADS_SASL_PLAIN);
427 0 : if (!ads) {
428 0 : return WERR_GEN_FAILURE;
429 : }
430 :
431 0 : SAFE_FREE(ads->auth.user_name);
432 0 : if (r->in.account) {
433 0 : ads->auth.user_name = SMB_STRDUP(r->in.account);
434 : } else {
435 0 : const char *username = NULL;
436 :
437 0 : libnetapi_get_username(ctx, &username);
438 0 : if (username != NULL) {
439 0 : ads->auth.user_name = SMB_STRDUP(username);
440 : }
441 : }
442 :
443 0 : SAFE_FREE(ads->auth.password);
444 0 : if (r->in.password) {
445 0 : ads->auth.password = SMB_STRDUP(r->in.password);
446 : } else {
447 0 : const char *password = NULL;
448 :
449 0 : libnetapi_get_password(ctx, &password);
450 0 : if (password != NULL) {
451 0 : ads->auth.password = SMB_STRDUP(password);
452 : }
453 : }
454 :
455 0 : ads_status = ads_connect_user_creds(ads);
456 0 : if (!ADS_ERR_OK(ads_status)) {
457 0 : ads_destroy(&ads);
458 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
459 : }
460 :
461 0 : ads_status = ads_get_joinable_ous(ads, ctx, &p, &s);
462 0 : if (!ADS_ERR_OK(ads_status)) {
463 0 : ads_destroy(&ads);
464 0 : return WERR_NERR_DEFAULTJOINREQUIRED;
465 : }
466 0 : *r->out.ous = discard_const_p(const char *, p);
467 0 : *r->out.ou_count = s;
468 :
469 0 : ads_destroy(&ads);
470 0 : return WERR_OK;
471 : #else
472 0 : return WERR_NOT_SUPPORTED;
473 : #endif
474 : }
475 :
476 : /****************************************************************
477 : ****************************************************************/
478 :
479 0 : WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
480 : struct NetGetJoinableOUs *r)
481 : {
482 0 : struct rpc_pipe_client *pipe_cli = NULL;
483 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
484 : NTSTATUS status;
485 : WERROR werr;
486 : struct dcerpc_binding_handle *b;
487 : DATA_BLOB session_key;
488 :
489 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
490 : &ndr_table_wkssvc,
491 : &pipe_cli);
492 0 : if (!W_ERROR_IS_OK(werr)) {
493 0 : goto done;
494 : }
495 :
496 0 : b = pipe_cli->binding_handle;
497 :
498 0 : if (r->in.password) {
499 :
500 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
501 0 : if (!NT_STATUS_IS_OK(status)) {
502 0 : werr = ntstatus_to_werror(status);
503 0 : goto done;
504 : }
505 :
506 0 : werr = encode_wkssvc_join_password_buffer(ctx,
507 : r->in.password,
508 : &session_key,
509 : &encrypted_password);
510 0 : if (!W_ERROR_IS_OK(werr)) {
511 0 : goto done;
512 : }
513 : }
514 :
515 0 : status = dcerpc_wkssvc_NetrGetJoinableOus2(b, talloc_tos(),
516 : r->in.server_name,
517 : r->in.domain,
518 : r->in.account,
519 : encrypted_password,
520 : r->out.ou_count,
521 : r->out.ous,
522 : &werr);
523 0 : if (!NT_STATUS_IS_OK(status)) {
524 0 : werr = ntstatus_to_werror(status);
525 0 : goto done;
526 : }
527 :
528 0 : done:
529 0 : return werr;
530 : }
531 :
532 : /****************************************************************
533 : ****************************************************************/
534 :
535 0 : WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
536 : struct NetRenameMachineInDomain *r)
537 : {
538 0 : struct rpc_pipe_client *pipe_cli = NULL;
539 0 : struct wkssvc_PasswordBuffer *encrypted_password = NULL;
540 : NTSTATUS status;
541 : WERROR werr;
542 : struct dcerpc_binding_handle *b;
543 : DATA_BLOB session_key;
544 :
545 0 : werr = libnetapi_open_pipe(ctx, r->in.server_name,
546 : &ndr_table_wkssvc,
547 : &pipe_cli);
548 0 : if (!W_ERROR_IS_OK(werr)) {
549 0 : goto done;
550 : }
551 :
552 0 : b = pipe_cli->binding_handle;
553 :
554 0 : if (r->in.password) {
555 :
556 0 : status = cli_get_session_key(talloc_tos(), pipe_cli, &session_key);
557 0 : if (!NT_STATUS_IS_OK(status)) {
558 0 : werr = ntstatus_to_werror(status);
559 0 : goto done;
560 : }
561 :
562 0 : werr = encode_wkssvc_join_password_buffer(ctx,
563 : r->in.password,
564 : &session_key,
565 : &encrypted_password);
566 0 : if (!W_ERROR_IS_OK(werr)) {
567 0 : goto done;
568 : }
569 : }
570 :
571 0 : status = dcerpc_wkssvc_NetrRenameMachineInDomain2(b, talloc_tos(),
572 : r->in.server_name,
573 : r->in.new_machine_name,
574 : r->in.account,
575 : encrypted_password,
576 : r->in.rename_options,
577 : &werr);
578 0 : if (!NT_STATUS_IS_OK(status)) {
579 0 : werr = ntstatus_to_werror(status);
580 0 : goto done;
581 : }
582 :
583 0 : done:
584 0 : return werr;
585 : }
586 :
587 : /****************************************************************
588 : ****************************************************************/
589 :
590 0 : WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
591 : struct NetRenameMachineInDomain *r)
592 : {
593 0 : LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
594 : }
595 :
596 : /****************************************************************
597 : ****************************************************************/
598 :
599 0 : WERROR NetProvisionComputerAccount_r(struct libnetapi_ctx *ctx,
600 : struct NetProvisionComputerAccount *r)
601 : {
602 0 : return NetProvisionComputerAccount_l(ctx, r);
603 : }
604 :
605 : /****************************************************************
606 : ****************************************************************/
607 :
608 6 : static WERROR NetProvisionComputerAccount_backend(struct libnetapi_ctx *ctx,
609 : struct NetProvisionComputerAccount *r,
610 : TALLOC_CTX *mem_ctx,
611 : struct ODJ_PROVISION_DATA **p)
612 : {
613 : WERROR werr;
614 6 : struct libnet_JoinCtx *j = NULL;
615 6 : int use_kerberos = 0;
616 6 : const char *username = NULL;
617 :
618 6 : werr = libnet_init_JoinCtx(mem_ctx, &j);
619 6 : if (!W_ERROR_IS_OK(werr)) {
620 0 : return werr;
621 : }
622 :
623 6 : j->in.domain_name = talloc_strdup(j, r->in.domain);
624 6 : if (j->in.domain_name == NULL) {
625 0 : talloc_free(j);
626 0 : return WERR_NOT_ENOUGH_MEMORY;
627 : }
628 :
629 6 : talloc_free(discard_const_p(char *, j->in.machine_name));
630 6 : j->in.machine_name = talloc_strdup(j, r->in.machine_name);
631 6 : if (j->in.machine_name == NULL) {
632 0 : talloc_free(j);
633 0 : return WERR_NOT_ENOUGH_MEMORY;
634 : }
635 :
636 6 : if (r->in.dcname) {
637 4 : j->in.dc_name = talloc_strdup(j, r->in.dcname);
638 4 : if (j->in.dc_name == NULL) {
639 0 : talloc_free(j);
640 0 : return WERR_NOT_ENOUGH_MEMORY;
641 : }
642 : }
643 :
644 6 : if (r->in.machine_account_ou) {
645 0 : j->in.account_ou = talloc_strdup(j, r->in.machine_account_ou);
646 0 : if (j->in.account_ou == NULL) {
647 0 : talloc_free(j);
648 0 : return WERR_NOT_ENOUGH_MEMORY;
649 : }
650 : }
651 :
652 6 : libnetapi_get_username(ctx, &username);
653 6 : if (username == NULL) {
654 0 : talloc_free(j);
655 0 : return WERR_NERR_BADUSERNAME;
656 : }
657 :
658 6 : j->in.admin_account = talloc_strdup(j, username);
659 6 : if (j->in.admin_account == NULL) {
660 0 : talloc_free(j);
661 0 : return WERR_NOT_ENOUGH_MEMORY;
662 : }
663 :
664 6 : libnetapi_get_use_kerberos(ctx, &use_kerberos);
665 6 : if (!use_kerberos) {
666 6 : const char *password = NULL;
667 :
668 6 : libnetapi_get_password(ctx, &password);
669 6 : if (password == NULL) {
670 0 : talloc_free(j);
671 0 : return WERR_NERR_BADPASSWORD;
672 : }
673 6 : j->in.admin_password = talloc_strdup(j, password);
674 6 : if (j->in.admin_password == NULL) {
675 0 : talloc_free(j);
676 0 : return WERR_NOT_ENOUGH_MEMORY;
677 : }
678 : }
679 :
680 6 : j->in.use_kerberos = use_kerberos;
681 6 : j->in.debug = true;
682 6 : j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
683 : WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
684 :
685 6 : if (r->in.options & NETSETUP_PROVISION_REUSE_ACCOUNT) {
686 0 : j->in.join_flags |= WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
687 : }
688 :
689 6 : if (r->in.options & NETSETUP_PROVISION_USE_DEFAULT_PASSWORD) {
690 2 : j->in.join_flags |= WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
691 2 : j->in.machine_password = talloc_strdup(j, r->in.machine_name);
692 2 : if (j->in.machine_password == NULL) {
693 0 : talloc_free(j);
694 0 : return WERR_NOT_ENOUGH_MEMORY;
695 : }
696 : }
697 :
698 6 : j->in.provision_computer_account_only = true;
699 :
700 6 : werr = libnet_Join(mem_ctx, j);
701 6 : if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
702 0 : libnetapi_set_error_string(ctx, "%s", j->out.error_string);
703 0 : talloc_free(j);
704 0 : return werr;
705 : }
706 :
707 6 : werr = libnet_odj_compose_ODJ_PROVISION_DATA(mem_ctx, j, p);
708 6 : if (!W_ERROR_IS_OK(werr)) {
709 0 : talloc_free(j);
710 0 : return werr;
711 : }
712 :
713 6 : TALLOC_FREE(j);
714 :
715 6 : return WERR_OK;
716 : }
717 :
718 6 : WERROR NetProvisionComputerAccount_l(struct libnetapi_ctx *ctx,
719 : struct NetProvisionComputerAccount *r)
720 : {
721 : WERROR werr;
722 : enum ndr_err_code ndr_err;
723 : const char *b64_bin_data_str;
724 : DATA_BLOB blob;
725 : struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
726 : struct ODJ_PROVISION_DATA *p;
727 6 : TALLOC_CTX *mem_ctx = talloc_new(ctx);
728 :
729 9 : if (r->in.provision_bin_data == NULL &&
730 6 : r->in.provision_text_data == NULL) {
731 0 : return WERR_INVALID_PARAMETER;
732 : }
733 6 : if (r->in.provision_bin_data != NULL &&
734 0 : r->in.provision_text_data != NULL) {
735 0 : return WERR_INVALID_PARAMETER;
736 : }
737 9 : if (r->in.provision_bin_data == NULL &&
738 6 : r->in.provision_bin_data_size != NULL) {
739 0 : return WERR_INVALID_PARAMETER;
740 : }
741 6 : if (r->in.provision_bin_data != NULL &&
742 0 : r->in.provision_bin_data_size == NULL) {
743 0 : return WERR_INVALID_PARAMETER;
744 : }
745 :
746 6 : if (r->in.domain == NULL) {
747 0 : return WERR_INVALID_PARAMETER;
748 : }
749 :
750 6 : if (r->in.machine_name == NULL) {
751 0 : return WERR_INVALID_PARAMETER;
752 : }
753 :
754 6 : werr = NetProvisionComputerAccount_backend(ctx, r, mem_ctx, &p);
755 6 : if (!W_ERROR_IS_OK(werr)) {
756 0 : talloc_free(mem_ctx);
757 0 : return werr;
758 : }
759 :
760 6 : ZERO_STRUCT(odj_provision_data);
761 :
762 6 : odj_provision_data.s.p = p;
763 :
764 6 : ndr_err = ndr_push_struct_blob(&blob, ctx, &odj_provision_data,
765 : (ndr_push_flags_fn_t)ndr_push_ODJ_PROVISION_DATA_serialized_ptr);
766 6 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
767 0 : talloc_free(mem_ctx);
768 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
769 : }
770 :
771 6 : talloc_free(mem_ctx);
772 :
773 6 : if (r->out.provision_text_data != NULL) {
774 6 : b64_bin_data_str = base64_encode_data_blob(ctx, blob);
775 6 : if (b64_bin_data_str == NULL) {
776 0 : return WERR_NOT_ENOUGH_MEMORY;
777 : }
778 6 : *r->out.provision_text_data = b64_bin_data_str;
779 : }
780 :
781 6 : if (r->out.provision_bin_data != NULL &&
782 0 : r->out.provision_bin_data_size != NULL) {
783 0 : *r->out.provision_bin_data = blob.data;
784 0 : *r->out.provision_bin_data_size = blob.length;
785 : }
786 :
787 6 : return werr;
788 : }
789 :
790 : /****************************************************************
791 : ****************************************************************/
792 :
793 0 : WERROR NetRequestOfflineDomainJoin_r(struct libnetapi_ctx *ctx,
794 : struct NetRequestOfflineDomainJoin *r)
795 : {
796 0 : return WERR_NOT_SUPPORTED;
797 : }
798 :
799 : /****************************************************************
800 : ****************************************************************/
801 :
802 6 : static WERROR NetRequestOfflineDomainJoin_backend(struct libnetapi_ctx *ctx,
803 : const struct ODJ_WIN7BLOB *win7blob,
804 : const struct ODJ_PROVISION_DATA *odj_provision_data)
805 : {
806 6 : struct libnet_JoinCtx *j = NULL;
807 : WERROR werr;
808 :
809 6 : werr = libnet_init_JoinCtx(ctx, &j);
810 6 : if (!W_ERROR_IS_OK(werr)) {
811 0 : return werr;
812 : }
813 :
814 6 : j->in.domain_name = talloc_strdup(j, win7blob->lpDomain);
815 6 : if (j->in.domain_name == NULL) {
816 0 : talloc_free(j);
817 0 : return WERR_NOT_ENOUGH_MEMORY;
818 : }
819 :
820 6 : talloc_free(discard_const_p(char *, j->in.machine_name));
821 6 : j->in.machine_name = talloc_strdup(j, win7blob->lpMachineName);
822 6 : if (j->in.machine_name == NULL) {
823 0 : talloc_free(j);
824 0 : return WERR_NOT_ENOUGH_MEMORY;
825 : }
826 :
827 6 : j->in.machine_password = talloc_strdup(j, win7blob->lpMachinePassword);
828 6 : if (j->in.machine_password == NULL) {
829 0 : talloc_free(j);
830 0 : return WERR_NOT_ENOUGH_MEMORY;
831 : }
832 :
833 6 : j->in.request_offline_join = true;
834 6 : j->in.odj_provision_data = discard_const(odj_provision_data);
835 6 : j->in.debug = true;
836 6 : j->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
837 : WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED;
838 :
839 6 : werr = libnet_Join(j, j);
840 6 : if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
841 0 : libnetapi_set_error_string(ctx, "%s", j->out.error_string);
842 0 : talloc_free(j);
843 0 : return werr;
844 : }
845 :
846 6 : TALLOC_FREE(j);
847 :
848 6 : return WERR_OK;
849 : }
850 :
851 6 : WERROR NetRequestOfflineDomainJoin_l(struct libnetapi_ctx *ctx,
852 : struct NetRequestOfflineDomainJoin *r)
853 : {
854 : DATA_BLOB blob, blob_base64;
855 : enum ndr_err_code ndr_err;
856 : struct ODJ_PROVISION_DATA_serialized_ptr odj_provision_data;
857 : bool ok;
858 6 : struct ODJ_WIN7BLOB win7blob = { 0 };
859 : WERROR werr;
860 :
861 9 : if (r->in.provision_bin_data == NULL ||
862 6 : r->in.provision_bin_data_size == 0) {
863 0 : return W_ERROR(NERR_NoOfflineJoinInfo);
864 : }
865 :
866 6 : if (r->in.provision_bin_data_size < 2) {
867 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
868 : }
869 :
870 9 : if (r->in.provision_bin_data[0] == 0xff &&
871 6 : r->in.provision_bin_data[1] == 0xfe) {
872 9 : ok = convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX,
873 6 : r->in.provision_bin_data+2,
874 6 : r->in.provision_bin_data_size-2,
875 : &blob_base64.data,
876 : &blob_base64.length);
877 9 : if (!ok) {
878 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
879 : }
880 : } else {
881 0 : blob_base64 = data_blob(r->in.provision_bin_data,
882 : r->in.provision_bin_data_size);
883 : }
884 :
885 6 : blob = base64_decode_data_blob_talloc(ctx, (const char *)blob_base64.data);
886 :
887 6 : ndr_err = ndr_pull_struct_blob(&blob, ctx, &odj_provision_data,
888 : (ndr_pull_flags_fn_t)ndr_pull_ODJ_PROVISION_DATA_serialized_ptr);
889 6 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
890 0 : return W_ERROR(NERR_BadOfflineJoinInfo);
891 : }
892 :
893 6 : if (DEBUGLEVEL >= 10) {
894 0 : NDR_PRINT_DEBUG(ODJ_PROVISION_DATA_serialized_ptr, &odj_provision_data);
895 : }
896 :
897 6 : if (odj_provision_data.s.p->ulVersion != 1) {
898 0 : return W_ERROR(NERR_ProvisioningBlobUnsupported);
899 : }
900 :
901 6 : werr = libnet_odj_find_win7blob(odj_provision_data.s.p, &win7blob);
902 6 : if (!W_ERROR_IS_OK(werr)) {
903 0 : return werr;
904 : }
905 :
906 6 : if (!(r->in.options & NETSETUP_PROVISION_ONLINE_CALLER)) {
907 0 : return WERR_NERR_SETUPNOTJOINED;
908 : }
909 :
910 6 : werr = NetRequestOfflineDomainJoin_backend(ctx,
911 : &win7blob,
912 6 : odj_provision_data.s.p);
913 6 : if (!W_ERROR_IS_OK(werr)) {
914 0 : return werr;
915 : }
916 :
917 6 : return W_ERROR(NERR_JoinPerformedMustRestart);
918 : }
|