gp: Fix startup scripts add not always set runonce
[Samba.git] / source3 / libnet / libnet_join_offline.c
blobd1317ddfbeaec84379558b343e6b2b3c9ec5a273
1 /*
2 * Unix SMB/CIFS implementation.
3 * libnet Join offline support
4 * Copyright (C) Guenther Deschner 2021
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.
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.
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/>.
20 #include "includes.h"
21 #include "librpc/gen_ndr/ndr_libnet_join.h"
22 #include "../librpc/gen_ndr/ndr_ODJ.h"
23 #include "libnet/libnet_join_offline.h"
24 #include "libcli/security/dom_sid.h"
25 #include "rpc_client/util_netlogon.h"
27 static WERROR libnet_odj_compose_ODJ_WIN7BLOB(TALLOC_CTX *mem_ctx,
28 const struct libnet_JoinCtx *r,
29 struct ODJ_WIN7BLOB *b)
31 char *samaccount;
32 uint32_t len;
33 struct ODJ_POLICY_DNS_DOMAIN_INFO i = {
34 .Sid = NULL,
37 ZERO_STRUCTP(b);
39 b->lpDomain = talloc_strdup(mem_ctx, r->out.dns_domain_name);
40 if (b->lpDomain == NULL) {
41 return WERR_NOT_ENOUGH_MEMORY;
44 samaccount = talloc_strdup(mem_ctx, r->out.account_name);
45 if (samaccount == NULL) {
46 return WERR_NOT_ENOUGH_MEMORY;
48 len = strlen(samaccount);
49 if (samaccount[len-1] == '$') {
50 samaccount[len-1] = '\0';
52 b->lpMachineName = samaccount;
54 b->lpMachinePassword = talloc_strdup(mem_ctx, r->in.machine_password);
55 if (b->lpMachinePassword == NULL) {
56 return WERR_NOT_ENOUGH_MEMORY;
59 /* fill up ODJ_POLICY_DNS_DOMAIN_INFO */
61 i.Name.string = talloc_strdup(mem_ctx, r->out.netbios_domain_name);
62 if (i.Name.string == NULL) {
63 return WERR_NOT_ENOUGH_MEMORY;
66 i.DnsDomainName.string = talloc_strdup(mem_ctx, r->out.dns_domain_name);
67 if (i.DnsDomainName.string == NULL) {
68 return WERR_NOT_ENOUGH_MEMORY;
71 i.DnsForestName.string = talloc_strdup(mem_ctx, r->out.forest_name);
72 if (i.DnsForestName.string == NULL) {
73 return WERR_NOT_ENOUGH_MEMORY;
76 i.DomainGuid = r->out.domain_guid;
77 i.Sid = dom_sid_dup(mem_ctx, r->out.domain_sid);
78 if (i.Sid == NULL) {
79 return WERR_NOT_ENOUGH_MEMORY;
82 b->DnsDomainInfo = i;
84 if (r->out.dcinfo) {
85 struct netr_DsRGetDCNameInfo *p;
87 p = talloc_steal(mem_ctx, r->out.dcinfo);
88 if (p == NULL) {
89 return WERR_NOT_ENOUGH_MEMORY;
92 b->DcInfo = *p;
96 * According to
97 * https://docs.microsoft.com/en-us/windows/win32/netmgmt/odj-odj_win7blob
98 * it should be 0 but Windows 2019 always sets 6 - gd.
100 b->Options = 6;
102 return WERR_OK;
105 static WERROR libnet_odj_compose_OP_JOINPROV2_PART(TALLOC_CTX *mem_ctx,
106 const struct libnet_JoinCtx *r,
107 struct OP_JOINPROV2_PART **p)
109 struct OP_JOINPROV2_PART *b;
111 b = talloc_zero(mem_ctx, struct OP_JOINPROV2_PART);
112 if (b == NULL) {
113 return WERR_NOT_ENOUGH_MEMORY;
116 /* TODO */
118 *p = b;
120 return WERR_INVALID_LEVEL;
123 static WERROR libnet_odj_compose_OP_JOINPROV3_PART(TALLOC_CTX *mem_ctx,
124 const struct libnet_JoinCtx *r,
125 struct OP_JOINPROV3_PART **p)
127 struct OP_JOINPROV3_PART *b;
128 struct dom_sid *sid;
130 b = talloc_zero(mem_ctx, struct OP_JOINPROV3_PART);
131 if (b == NULL) {
132 return WERR_NOT_ENOUGH_MEMORY;
135 b->Rid = r->out.account_rid;
136 sid = dom_sid_add_rid(mem_ctx, r->out.domain_sid, r->out.account_rid);
137 if (sid == NULL) {
138 return WERR_NOT_ENOUGH_MEMORY;
141 b->lpSid = dom_sid_string(mem_ctx, sid);
142 if (b->lpSid == NULL) {
143 return WERR_NOT_ENOUGH_MEMORY;
146 *p = b;
148 return WERR_OK;
151 static WERROR libnet_odj_compose_OP_PACKAGE_PART(TALLOC_CTX *mem_ctx,
152 const struct libnet_JoinCtx *r,
153 const struct ODJ_WIN7BLOB *win7,
154 const char *join_provider_guid,
155 uint32_t flags,
156 struct OP_PACKAGE_PART *p)
158 struct GUID guid;
159 uint32_t level;
160 WERROR werr;
162 if (!NT_STATUS_IS_OK(GUID_from_string(join_provider_guid, &guid))) {
163 return WERR_NOT_ENOUGH_MEMORY;
166 level = odj_switch_level_from_guid(&guid);
168 p->PartType = guid;
169 p->ulFlags = flags;
170 p->part_len = 0; /* autogenerated */
171 p->Part = talloc_zero(mem_ctx, union OP_PACKAGE_PART_u);
172 if (p->Part == NULL) {
173 return WERR_NOT_ENOUGH_MEMORY;
176 switch (level) {
177 case 1: /* ODJ_GUID_JOIN_PROVIDER */
178 if (win7 == NULL) {
179 return WERR_INVALID_PARAMETER;
181 p->Part->win7blob = *win7;
182 break;
183 case 2: /* ODJ_GUID_JOIN_PROVIDER2 */
184 werr = libnet_odj_compose_OP_JOINPROV2_PART(mem_ctx, r,
185 &p->Part->join_prov2.p);
186 if (!W_ERROR_IS_OK(werr)) {
187 return werr;
189 break;
190 case 3: /* ODJ_GUID_JOIN_PROVIDER3 */
191 werr = libnet_odj_compose_OP_JOINPROV3_PART(mem_ctx, r,
192 &p->Part->join_prov3.p);
193 if (!W_ERROR_IS_OK(werr)) {
194 return werr;
196 break;
197 default:
198 return WERR_INVALID_LEVEL;
201 return WERR_OK;
204 static WERROR libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(TALLOC_CTX *mem_ctx,
205 const struct libnet_JoinCtx *r,
206 const struct ODJ_WIN7BLOB *win7,
207 struct OP_PACKAGE_PART_COLLECTION **pp)
209 WERROR werr;
210 struct OP_PACKAGE_PART_COLLECTION *p;
212 p = talloc_zero(mem_ctx, struct OP_PACKAGE_PART_COLLECTION);
213 if (p == NULL) {
214 return WERR_NOT_ENOUGH_MEMORY;
217 p->cParts = 2;
218 p->pParts = talloc_zero_array(p, struct OP_PACKAGE_PART, p->cParts);
219 if (p->pParts == NULL) {
220 talloc_free(p);
221 return WERR_NOT_ENOUGH_MEMORY;
224 werr = libnet_odj_compose_OP_PACKAGE_PART(p, r, win7,
225 ODJ_GUID_JOIN_PROVIDER,
226 OPSPI_PACKAGE_PART_ESSENTIAL,
227 &p->pParts[0]);
228 if (!W_ERROR_IS_OK(werr)) {
229 talloc_free(p);
230 return werr;
233 werr = libnet_odj_compose_OP_PACKAGE_PART(p, r, NULL,
234 ODJ_GUID_JOIN_PROVIDER3,
236 &p->pParts[1]);
237 if (!W_ERROR_IS_OK(werr)) {
238 talloc_free(p);
239 return werr;
242 *pp = p;
244 return WERR_OK;
247 static WERROR libnet_odj_compose_OP_PACKAGE(TALLOC_CTX *mem_ctx,
248 const struct libnet_JoinCtx *r,
249 const struct ODJ_WIN7BLOB *win7,
250 struct OP_PACKAGE **pp)
252 WERROR werr;
253 struct OP_PACKAGE_PART_COLLECTION *c;
254 struct OP_PACKAGE *p;
256 p = talloc_zero(mem_ctx, struct OP_PACKAGE);
257 if (p == NULL) {
258 return WERR_NOT_ENOUGH_MEMORY;
261 werr = libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(p, r, win7, &c);
262 if (!W_ERROR_IS_OK(werr)) {
263 talloc_free(p);
264 return werr;
267 p->EncryptionType = GUID_zero();
269 p->WrappedPartCollection.cbBlob = 0; /* autogenerated */
270 p->WrappedPartCollection.w = talloc_zero(p,
271 struct OP_PACKAGE_PART_COLLECTION_serialized_ptr);
272 if (p->WrappedPartCollection.w == NULL) {
273 talloc_free(p);
274 return WERR_NOT_ENOUGH_MEMORY;
277 p->WrappedPartCollection.w->s.p = c;
279 *pp = p;
281 return WERR_OK;
284 WERROR libnet_odj_compose_ODJ_PROVISION_DATA(TALLOC_CTX *mem_ctx,
285 const struct libnet_JoinCtx *r,
286 struct ODJ_PROVISION_DATA **b_p)
288 WERROR werr;
289 struct ODJ_PROVISION_DATA *b;
290 struct ODJ_WIN7BLOB win7;
291 struct OP_PACKAGE *package;
293 b = talloc_zero(mem_ctx, struct ODJ_PROVISION_DATA);
294 if (b == NULL) {
295 return WERR_NOT_ENOUGH_MEMORY;
298 b->ulVersion = 1;
299 b->ulcBlobs = 2;
300 b->pBlobs = talloc_zero_array(b, struct ODJ_BLOB, b->ulcBlobs);
301 if (b->pBlobs == NULL) {
302 talloc_free(b);
303 return WERR_NOT_ENOUGH_MEMORY;
306 werr = libnet_odj_compose_ODJ_WIN7BLOB(b, r, &win7);
307 if (!W_ERROR_IS_OK(werr)) {
308 talloc_free(b);
309 return werr;
312 werr = libnet_odj_compose_OP_PACKAGE(b, r, &win7, &package);
313 if (!W_ERROR_IS_OK(werr)) {
314 talloc_free(b);
315 return werr;
318 b->pBlobs[0].ulODJFormat = ODJ_WIN7_FORMAT;
319 b->pBlobs[0].cbBlob = 0; /* autogenerated */
320 b->pBlobs[0].pBlob = talloc_zero(b, union ODJ_BLOB_u);
321 if (b->pBlobs[0].pBlob == NULL) {
322 talloc_free(b);
323 return WERR_NOT_ENOUGH_MEMORY;
325 b->pBlobs[0].pBlob->odj_win7blob = win7;
327 b->pBlobs[1].ulODJFormat = ODJ_WIN8_FORMAT;
328 b->pBlobs[1].cbBlob = 0; /* autogenerated */
329 b->pBlobs[1].pBlob = talloc_zero(b, union ODJ_BLOB_u);
330 if (b->pBlobs[1].pBlob == NULL) {
331 talloc_free(b);
332 return WERR_NOT_ENOUGH_MEMORY;
334 b->pBlobs[1].pBlob->op_package.p = package;
336 *b_p = b;
338 return WERR_OK;
341 WERROR libnet_odj_find_win7blob(const struct ODJ_PROVISION_DATA *r,
342 struct ODJ_WIN7BLOB *win7blob)
344 int i;
346 if (r == NULL) {
347 return WERR_INVALID_PARAMETER;
350 for (i = 0; i < r->ulcBlobs; i++) {
352 struct ODJ_BLOB b = r->pBlobs[i];
354 switch (b.ulODJFormat) {
355 case ODJ_WIN7_FORMAT:
356 *win7blob = b.pBlob->odj_win7blob;
357 return WERR_OK;
359 case ODJ_WIN8_FORMAT: {
360 NTSTATUS status;
361 struct OP_PACKAGE_PART_COLLECTION *col;
362 struct GUID guid;
363 int k;
365 if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) {
366 return WERR_BAD_FORMAT;
369 col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p;
371 status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER, &guid);
372 if (!NT_STATUS_IS_OK(status)) {
373 return WERR_NOT_ENOUGH_MEMORY;
376 for (k = 0; k < col->cParts; k++) {
377 if (GUID_equal(&guid, &col->pParts[k].PartType)) {
378 *win7blob = col->pParts[k].Part->win7blob;
379 return WERR_OK;
382 break;
384 default:
385 return WERR_BAD_FORMAT;
389 return WERR_BAD_FORMAT;
393 WERROR libnet_odj_find_joinprov3(const struct ODJ_PROVISION_DATA *r,
394 struct OP_JOINPROV3_PART *joinprov3)
396 int i;
398 if (r == NULL) {
399 return WERR_INVALID_PARAMETER;
402 for (i = 0; i < r->ulcBlobs; i++) {
404 struct ODJ_BLOB b = r->pBlobs[i];
406 switch (b.ulODJFormat) {
407 case ODJ_WIN7_FORMAT:
408 continue;
410 case ODJ_WIN8_FORMAT: {
411 NTSTATUS status;
412 struct OP_PACKAGE_PART_COLLECTION *col;
413 struct GUID guid;
414 int k;
416 if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) {
417 return WERR_BAD_FORMAT;
420 col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p;
422 status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER3, &guid);
423 if (!NT_STATUS_IS_OK(status)) {
424 return WERR_NOT_ENOUGH_MEMORY;
427 for (k = 0; k < col->cParts; k++) {
428 if (GUID_equal(&guid, &col->pParts[k].PartType)) {
429 *joinprov3 = *col->pParts[k].Part->join_prov3.p;
430 return WERR_OK;
433 break;
435 default:
436 return WERR_BAD_FORMAT;
440 return WERR_BAD_FORMAT;