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