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