Line data Source code
1 : /*
2 : Samba Unix/Linux SMB client library
3 : net join commands
4 : Copyright (C) 2021 Guenther Deschner (gd@samba.org)
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 "utils/net.h"
22 : #include <netapi.h>
23 : #include "netapi/netapi_net.h"
24 : #include "libcli/registry/util_reg.h"
25 :
26 0 : int net_offlinejoin_usage(struct net_context *c, int argc, const char **argv)
27 : {
28 0 : d_printf(_("\nnet offlinejoin [misc. options]\n"
29 : "\tjoins a computer to a domain\n"));
30 0 : d_printf(_("Valid commands:\n"));
31 0 : d_printf(_("\tprovision\t\t\tProvision machine account in AD\n"));
32 0 : d_printf(_("\trequestodj\t\t\tRequest offline domain join\n"));
33 0 : net_common_flags_usage(c, argc, argv);
34 0 : return -1;
35 : }
36 :
37 0 : int net_offlinejoin(struct net_context *c, int argc, const char **argv)
38 : {
39 : int ret;
40 : NET_API_STATUS status;
41 :
42 0 : if ((argc > 0) && (strcasecmp_m(argv[0], "HELP") == 0)) {
43 0 : net_offlinejoin_usage(c, argc, argv);
44 0 : return 0;
45 : }
46 :
47 0 : if (argc == 0) {
48 0 : net_offlinejoin_usage(c, argc, argv);
49 0 : return -1;
50 : }
51 :
52 0 : net_warn_member_options();
53 :
54 0 : status = libnetapi_net_init(&c->netapi_ctx);
55 0 : if (status != 0) {
56 0 : return -1;
57 : }
58 :
59 0 : status = libnetapi_set_creds(c->netapi_ctx, c->creds);
60 0 : if (status != 0) {
61 0 : return -1;
62 : }
63 :
64 0 : if (c->opt_kerberos) {
65 0 : libnetapi_set_use_kerberos(c->netapi_ctx);
66 : }
67 :
68 0 : if (strcasecmp_m(argv[0], "provision") == 0) {
69 0 : ret = net_offlinejoin_provision(c, argc, argv);
70 0 : if (ret != 0) {
71 0 : return ret;
72 : }
73 : }
74 :
75 0 : if (strcasecmp_m(argv[0], "requestodj") == 0) {
76 0 : ret = net_offlinejoin_requestodj(c, argc, argv);
77 0 : if (ret != 0) {
78 0 : return ret;
79 : }
80 : }
81 :
82 0 : return 0;
83 : }
84 :
85 0 : static int net_offlinejoin_provision_usage(struct net_context *c, int argc, const char **argv)
86 : {
87 0 : d_printf(_("\nnet offlinejoin provision [misc. options]\n"
88 : "\tProvisions machine account in AD\n"));
89 0 : d_printf(_("Valid options:\n"));
90 0 : d_printf(_("\tdomain=<DOMAIN>\t\t\t\tDefines AD Domain to join\n"));
91 0 : d_printf(_("\tmachine_name=<MACHINE_NAME>\t\tDefines the machine account name\n"));
92 0 : d_printf(_("\tmachine_account_ou=<OU>\t\t\tDefines the machine account organizational unit DN\n"));
93 0 : d_printf(_("\tdcname=<DCNAME>\t\t\t\tSpecifices a Domain Controller to join to\n"));
94 0 : d_printf(_("\tdefpwd\t\t\t\t\tUse default machine account password\n"));
95 0 : d_printf(_("\treuse\t\t\t\t\tReuse existing machine account in AD\n"));
96 0 : d_printf(_("\tsavefile=<FILENAME>\t\t\tFile to store the ODJ data\n"));
97 0 : d_printf(_("\tprintblob\t\t\t\tPrint the base64 encoded ODJ data on stdout\n"));
98 0 : net_common_flags_usage(c, argc, argv);
99 0 : return -1;
100 : }
101 :
102 0 : int net_offlinejoin_provision(struct net_context *c,
103 : int argc, const char **argv)
104 : {
105 : NET_API_STATUS status;
106 0 : const char *dcname = NULL;
107 0 : const char *domain = NULL;
108 0 : const char *machine_name = NULL;
109 0 : const char *machine_account_ou = NULL;
110 0 : const char *provision_text_data = NULL;
111 0 : uint32_t options = 0;
112 0 : const char *savefile = NULL;
113 0 : bool printblob = false;
114 : int i;
115 :
116 0 : if (c->display_usage || argc == 1) {
117 0 : return net_offlinejoin_provision_usage(c, argc, argv);
118 : }
119 :
120 : /* process additional command line args */
121 :
122 0 : for (i = 0; i < argc; i++) {
123 :
124 0 : if (strnequal(argv[i], "domain", strlen("domain"))) {
125 0 : domain = get_string_param(argv[i]);
126 0 : if (domain == NULL) {
127 0 : return -1;
128 : }
129 : }
130 0 : if (strnequal(argv[i], "machine_name", strlen("machine_name"))) {
131 0 : machine_name = get_string_param(argv[i]);
132 0 : if (machine_name == NULL) {
133 0 : return -1;
134 : }
135 : }
136 0 : if (strnequal(argv[i], "machine_account_ou", strlen("machine_account_ou"))) {
137 0 : machine_account_ou = get_string_param(argv[i]);
138 0 : if (machine_account_ou == NULL) {
139 0 : return -1;
140 : }
141 : }
142 0 : if (strnequal(argv[i], "dcname", strlen("dcname"))) {
143 0 : dcname = get_string_param(argv[i]);
144 0 : if (dcname == NULL) {
145 0 : return -1;
146 : }
147 : }
148 0 : if (strnequal(argv[i], "defpwd", strlen("defpwd"))) {
149 0 : options |= NETSETUP_PROVISION_USE_DEFAULT_PASSWORD;
150 : }
151 0 : if (strnequal(argv[i], "reuse", strlen("reuse"))) {
152 0 : options |= NETSETUP_PROVISION_REUSE_ACCOUNT;
153 : }
154 0 : if (strnequal(argv[i], "savefile", strlen("savefile"))) {
155 0 : savefile = get_string_param(argv[i]);
156 0 : if (savefile == NULL) {
157 0 : return -1;
158 : }
159 : }
160 0 : if (strnequal(argv[i], "printblob", strlen("printblob"))) {
161 0 : printblob = true;
162 : }
163 : }
164 :
165 0 : if (domain == NULL) {
166 0 : d_printf("Failed to provision computer account: %s\n",
167 0 : libnetapi_errstr(W_ERROR_V(WERR_INVALID_DOMAINNAME)));
168 0 : return -1;
169 : }
170 :
171 0 : if (machine_name == NULL) {
172 0 : d_printf("Failed to provision computer account: %s\n",
173 0 : libnetapi_errstr(W_ERROR_V(WERR_INVALID_COMPUTERNAME)));
174 0 : return -1;
175 : }
176 :
177 0 : status = NetProvisionComputerAccount(domain,
178 : machine_name,
179 : machine_account_ou,
180 : dcname,
181 : options,
182 : NULL,
183 : 0,
184 : &provision_text_data);
185 0 : if (status != 0) {
186 0 : d_printf("Failed to provision computer account: %s\n",
187 : libnetapi_get_error_string(c->netapi_ctx, status));
188 0 : return status;
189 : }
190 :
191 0 : if (savefile != NULL) {
192 :
193 : DATA_BLOB ucs2_blob, blob;
194 : bool ok;
195 :
196 0 : ok = push_reg_sz(c, &ucs2_blob, provision_text_data);
197 0 : if (!ok) {
198 0 : return -1;
199 : }
200 :
201 0 : blob = data_blob_talloc(c, NULL, ucs2_blob.length + 2);
202 :
203 0 : blob.data[0] = 0xff;
204 0 : blob.data[1] = 0xfe;
205 :
206 0 : memcpy(blob.data + 2, ucs2_blob.data, ucs2_blob.length);
207 :
208 0 : ok = file_save(savefile, blob.data, blob.length);
209 0 : if (!ok) {
210 0 : d_printf("Failed to save %s: %s\n", savefile,
211 0 : strerror(errno));
212 0 : return -1;
213 : }
214 : }
215 :
216 0 : d_printf("Successfully provisioned computer '%s' in domain '%s'\n",
217 : machine_name, domain);
218 :
219 0 : if (printblob) {
220 0 : printf("%s\n", provision_text_data);
221 : }
222 :
223 0 : return 0;
224 : }
225 :
226 0 : static int net_offlinejoin_requestodj_usage(struct net_context *c, int argc, const char **argv)
227 : {
228 0 : d_printf(_("\nnet offlinejoin requestodj [misc. options]\n"
229 : "\tRequests offline domain join\n"));
230 0 : d_printf(_("Valid options:\n"));
231 0 : d_printf(_("\tloadfile=<FILENAME>\t\t\tFile that provides the ODJ data\n"));
232 : /*d_printf(_("\tlocalos\t\t\t\t\tModify the local machine\n"));*/
233 0 : net_common_flags_usage(c, argc, argv);
234 0 : return -1;
235 : }
236 :
237 0 : int net_offlinejoin_requestodj(struct net_context *c,
238 : int argc, const char **argv)
239 : {
240 : NET_API_STATUS status;
241 0 : uint8_t *provision_bin_data = NULL;
242 0 : size_t provision_bin_data_size = 0;
243 0 : uint32_t options = NETSETUP_PROVISION_ONLINE_CALLER;
244 0 : const char *loadfile = NULL;
245 0 : const char *windows_path = NULL;
246 : int i;
247 :
248 0 : if (c->display_usage || argc == 1) {
249 0 : return net_offlinejoin_requestodj_usage(c, argc, argv);
250 : }
251 :
252 : /* process additional command line args */
253 :
254 0 : for (i = 0; i < argc; i++) {
255 :
256 0 : if (strnequal(argv[i], "loadfile", strlen("loadfile"))) {
257 0 : loadfile = get_string_param(argv[i]);
258 0 : if (loadfile == NULL) {
259 0 : return -1;
260 : }
261 : }
262 : #if 0
263 : if (strnequal(argv[i], "localos", strlen("localos"))) {
264 : options |= NETSETUP_PROVISION_ONLINE_CALLER;
265 : }
266 : #endif
267 : }
268 :
269 0 : provision_bin_data =
270 0 : (uint8_t *)file_load(loadfile, &provision_bin_data_size, 0, c);
271 0 : if (provision_bin_data == NULL) {
272 0 : d_printf("Failed to read loadfile: %s\n", loadfile);
273 0 : return -1;
274 : }
275 0 : if (provision_bin_data_size > UINT32_MAX) {
276 0 : d_printf("provision binary data size too big: %zu\n",
277 : provision_bin_data_size);
278 0 : return -1;
279 : }
280 :
281 0 : status = NetRequestOfflineDomainJoin(provision_bin_data,
282 : provision_bin_data_size,
283 : options,
284 : windows_path);
285 0 : if (status != 0 && status != 0x00000a99) {
286 : /* NERR_JoinPerformedMustRestart */
287 0 : printf("Failed to call NetRequestOfflineDomainJoin: %s\n",
288 : libnetapi_get_error_string(c->netapi_ctx, status));
289 0 : return -1;
290 : }
291 :
292 0 : d_printf("Successfully requested Offline Domain Join\n");
293 :
294 0 : return 0;
295 : }
|