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/>.
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
)
33 struct ODJ_POLICY_DNS_DOMAIN_INFO i
= {
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
);
79 return WERR_NOT_ENOUGH_MEMORY
;
85 struct netr_DsRGetDCNameInfo
*p
;
87 p
= talloc_steal(mem_ctx
, r
->out
.dcinfo
);
89 return WERR_NOT_ENOUGH_MEMORY
;
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.
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
);
113 return WERR_NOT_ENOUGH_MEMORY
;
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
;
130 b
= talloc_zero(mem_ctx
, struct OP_JOINPROV3_PART
);
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
);
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
;
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
,
156 struct OP_PACKAGE_PART
*p
)
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
);
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
;
177 case 1: /* ODJ_GUID_JOIN_PROVIDER */
179 return WERR_INVALID_PARAMETER
;
181 p
->Part
->win7blob
= *win7
;
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
)) {
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
)) {
198 return WERR_INVALID_LEVEL
;
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
)
210 struct OP_PACKAGE_PART_COLLECTION
*p
;
212 p
= talloc_zero(mem_ctx
, struct OP_PACKAGE_PART_COLLECTION
);
214 return WERR_NOT_ENOUGH_MEMORY
;
218 p
->pParts
= talloc_zero_array(p
, struct OP_PACKAGE_PART
, p
->cParts
);
219 if (p
->pParts
== NULL
) {
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
,
228 if (!W_ERROR_IS_OK(werr
)) {
233 werr
= libnet_odj_compose_OP_PACKAGE_PART(p
, r
, NULL
,
234 ODJ_GUID_JOIN_PROVIDER3
,
237 if (!W_ERROR_IS_OK(werr
)) {
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
)
253 struct OP_PACKAGE_PART_COLLECTION
*c
;
254 struct OP_PACKAGE
*p
;
256 p
= talloc_zero(mem_ctx
, struct OP_PACKAGE
);
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
)) {
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
) {
274 return WERR_NOT_ENOUGH_MEMORY
;
277 p
->WrappedPartCollection
.w
->s
.p
= c
;
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
)
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
);
295 return WERR_NOT_ENOUGH_MEMORY
;
300 b
->pBlobs
= talloc_zero_array(b
, struct ODJ_BLOB
, b
->ulcBlobs
);
301 if (b
->pBlobs
== NULL
) {
303 return WERR_NOT_ENOUGH_MEMORY
;
306 werr
= libnet_odj_compose_ODJ_WIN7BLOB(b
, r
, &win7
);
307 if (!W_ERROR_IS_OK(werr
)) {
312 werr
= libnet_odj_compose_OP_PACKAGE(b
, r
, &win7
, &package
);
313 if (!W_ERROR_IS_OK(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
) {
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
) {
332 return WERR_NOT_ENOUGH_MEMORY
;
334 b
->pBlobs
[1].pBlob
->op_package
.p
= package
;
341 WERROR
libnet_odj_find_win7blob(const struct ODJ_PROVISION_DATA
*r
,
342 struct ODJ_WIN7BLOB
*win7blob
)
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
;
359 case ODJ_WIN8_FORMAT
: {
361 struct OP_PACKAGE_PART_COLLECTION
*col
;
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
;
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
)
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
:
410 case ODJ_WIN8_FORMAT
: {
412 struct OP_PACKAGE_PART_COLLECTION
*col
;
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
;
436 return WERR_BAD_FORMAT
;
440 return WERR_BAD_FORMAT
;