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
;
37 b
->lpDomain
= talloc_strdup(mem_ctx
, r
->out
.dns_domain_name
);
38 if (b
->lpDomain
== NULL
) {
39 return WERR_NOT_ENOUGH_MEMORY
;
42 samaccount
= talloc_strdup(mem_ctx
, r
->out
.account_name
);
43 if (samaccount
== NULL
) {
44 return WERR_NOT_ENOUGH_MEMORY
;
46 len
= strlen(samaccount
);
47 if (samaccount
[len
-1] == '$') {
48 samaccount
[len
-1] = '\0';
50 b
->lpMachineName
= samaccount
;
52 b
->lpMachinePassword
= talloc_strdup(mem_ctx
, r
->in
.machine_password
);
53 if (b
->lpMachinePassword
== NULL
) {
54 return WERR_NOT_ENOUGH_MEMORY
;
57 /* fill up ODJ_POLICY_DNS_DOMAIN_INFO */
59 i
.Name
.string
= talloc_strdup(mem_ctx
, r
->out
.netbios_domain_name
);
60 if (i
.Name
.string
== NULL
) {
61 return WERR_NOT_ENOUGH_MEMORY
;
64 i
.DnsDomainName
.string
= talloc_strdup(mem_ctx
, r
->out
.dns_domain_name
);
65 if (i
.DnsDomainName
.string
== NULL
) {
66 return WERR_NOT_ENOUGH_MEMORY
;
69 i
.DnsForestName
.string
= talloc_strdup(mem_ctx
, r
->out
.forest_name
);
70 if (i
.DnsForestName
.string
== NULL
) {
71 return WERR_NOT_ENOUGH_MEMORY
;
74 i
.DomainGuid
= r
->out
.domain_guid
;
75 i
.Sid
= dom_sid_dup(mem_ctx
, r
->out
.domain_sid
);
77 return WERR_NOT_ENOUGH_MEMORY
;
83 struct netr_DsRGetDCNameInfo
*p
;
85 p
= talloc_steal(mem_ctx
, r
->out
.dcinfo
);
87 return WERR_NOT_ENOUGH_MEMORY
;
95 * https://docs.microsoft.com/en-us/windows/win32/netmgmt/odj-odj_win7blob
96 * it should be 0 but Windows 2019 always sets 6 - gd.
103 static WERROR
libnet_odj_compose_OP_JOINPROV2_PART(TALLOC_CTX
*mem_ctx
,
104 const struct libnet_JoinCtx
*r
,
105 struct OP_JOINPROV2_PART
**p
)
107 struct OP_JOINPROV2_PART
*b
;
109 b
= talloc_zero(mem_ctx
, struct OP_JOINPROV2_PART
);
111 return WERR_NOT_ENOUGH_MEMORY
;
118 return WERR_INVALID_LEVEL
;
121 static WERROR
libnet_odj_compose_OP_JOINPROV3_PART(TALLOC_CTX
*mem_ctx
,
122 const struct libnet_JoinCtx
*r
,
123 struct OP_JOINPROV3_PART
**p
)
125 struct OP_JOINPROV3_PART
*b
;
128 b
= talloc_zero(mem_ctx
, struct OP_JOINPROV3_PART
);
130 return WERR_NOT_ENOUGH_MEMORY
;
133 b
->Rid
= r
->out
.account_rid
;
134 sid
= dom_sid_add_rid(mem_ctx
, r
->out
.domain_sid
, r
->out
.account_rid
);
136 return WERR_NOT_ENOUGH_MEMORY
;
139 b
->lpSid
= dom_sid_string(mem_ctx
, sid
);
140 if (b
->lpSid
== NULL
) {
141 return WERR_NOT_ENOUGH_MEMORY
;
149 static WERROR
libnet_odj_compose_OP_PACKAGE_PART(TALLOC_CTX
*mem_ctx
,
150 const struct libnet_JoinCtx
*r
,
151 const struct ODJ_WIN7BLOB
*win7
,
152 const char *join_provider_guid
,
154 struct OP_PACKAGE_PART
*p
)
160 if (!NT_STATUS_IS_OK(GUID_from_string(join_provider_guid
, &guid
))) {
161 return WERR_NOT_ENOUGH_MEMORY
;
164 level
= odj_switch_level_from_guid(&guid
);
168 p
->part_len
= 0; /* autogenerated */
169 p
->Part
= talloc_zero(mem_ctx
, union OP_PACKAGE_PART_u
);
170 if (p
->Part
== NULL
) {
171 return WERR_NOT_ENOUGH_MEMORY
;
175 case 1: /* ODJ_GUID_JOIN_PROVIDER */
176 p
->Part
->win7blob
= *win7
;
178 case 2: /* ODJ_GUID_JOIN_PROVIDER2 */
179 werr
= libnet_odj_compose_OP_JOINPROV2_PART(mem_ctx
, r
,
180 &p
->Part
->join_prov2
.p
);
181 if (!W_ERROR_IS_OK(werr
)) {
185 case 3: /* ODJ_GUID_JOIN_PROVIDER3 */
186 werr
= libnet_odj_compose_OP_JOINPROV3_PART(mem_ctx
, r
,
187 &p
->Part
->join_prov3
.p
);
188 if (!W_ERROR_IS_OK(werr
)) {
193 return WERR_INVALID_LEVEL
;
199 static WERROR
libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(TALLOC_CTX
*mem_ctx
,
200 const struct libnet_JoinCtx
*r
,
201 const struct ODJ_WIN7BLOB
*win7
,
202 struct OP_PACKAGE_PART_COLLECTION
**pp
)
205 struct OP_PACKAGE_PART_COLLECTION
*p
;
207 p
= talloc_zero(mem_ctx
, struct OP_PACKAGE_PART_COLLECTION
);
209 return WERR_NOT_ENOUGH_MEMORY
;
213 p
->pParts
= talloc_zero_array(p
, struct OP_PACKAGE_PART
, p
->cParts
);
214 if (p
->pParts
== NULL
) {
216 return WERR_NOT_ENOUGH_MEMORY
;
219 werr
= libnet_odj_compose_OP_PACKAGE_PART(p
, r
, win7
,
220 ODJ_GUID_JOIN_PROVIDER
,
221 OPSPI_PACKAGE_PART_ESSENTIAL
,
223 if (!W_ERROR_IS_OK(werr
)) {
228 werr
= libnet_odj_compose_OP_PACKAGE_PART(p
, r
, NULL
,
229 ODJ_GUID_JOIN_PROVIDER3
,
232 if (!W_ERROR_IS_OK(werr
)) {
242 static WERROR
libnet_odj_compose_OP_PACKAGE(TALLOC_CTX
*mem_ctx
,
243 const struct libnet_JoinCtx
*r
,
244 const struct ODJ_WIN7BLOB
*win7
,
245 struct OP_PACKAGE
**pp
)
248 struct OP_PACKAGE_PART_COLLECTION
*c
;
249 struct OP_PACKAGE
*p
;
251 p
= talloc_zero(mem_ctx
, struct OP_PACKAGE
);
253 return WERR_NOT_ENOUGH_MEMORY
;
256 werr
= libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(p
, r
, win7
, &c
);
257 if (!W_ERROR_IS_OK(werr
)) {
262 p
->EncryptionType
= GUID_zero();
264 p
->WrappedPartCollection
.cbBlob
= 0; /* autogenerated */
265 p
->WrappedPartCollection
.w
= talloc_zero(p
,
266 struct OP_PACKAGE_PART_COLLECTION_serialized_ptr
);
267 if (p
->WrappedPartCollection
.w
== NULL
) {
269 return WERR_NOT_ENOUGH_MEMORY
;
272 p
->WrappedPartCollection
.w
->s
.p
= c
;
279 WERROR
libnet_odj_compose_ODJ_PROVISION_DATA(TALLOC_CTX
*mem_ctx
,
280 const struct libnet_JoinCtx
*r
,
281 struct ODJ_PROVISION_DATA
**b_p
)
284 struct ODJ_PROVISION_DATA
*b
;
285 struct ODJ_WIN7BLOB win7
;
286 struct OP_PACKAGE
*package
;
288 b
= talloc_zero(mem_ctx
, struct ODJ_PROVISION_DATA
);
290 return WERR_NOT_ENOUGH_MEMORY
;
295 b
->pBlobs
= talloc_zero_array(b
, struct ODJ_BLOB
, b
->ulcBlobs
);
296 if (b
->pBlobs
== NULL
) {
298 return WERR_NOT_ENOUGH_MEMORY
;
301 werr
= libnet_odj_compose_ODJ_WIN7BLOB(b
, r
, &win7
);
302 if (!W_ERROR_IS_OK(werr
)) {
307 werr
= libnet_odj_compose_OP_PACKAGE(b
, r
, &win7
, &package
);
308 if (!W_ERROR_IS_OK(werr
)) {
313 b
->pBlobs
[0].ulODJFormat
= ODJ_WIN7_FORMAT
;
314 b
->pBlobs
[0].cbBlob
= 0; /* autogenerated */
315 b
->pBlobs
[0].pBlob
= talloc_zero(b
, union ODJ_BLOB_u
);
316 if (b
->pBlobs
[0].pBlob
== NULL
) {
318 return WERR_NOT_ENOUGH_MEMORY
;
320 b
->pBlobs
[0].pBlob
->odj_win7blob
= win7
;
322 b
->pBlobs
[1].ulODJFormat
= ODJ_WIN8_FORMAT
;
323 b
->pBlobs
[1].cbBlob
= 0; /* autogenerated */
324 b
->pBlobs
[1].pBlob
= talloc_zero(b
, union ODJ_BLOB_u
);
325 if (b
->pBlobs
[1].pBlob
== NULL
) {
327 return WERR_NOT_ENOUGH_MEMORY
;
329 b
->pBlobs
[1].pBlob
->op_package
.p
= package
;
336 WERROR
libnet_odj_find_win7blob(const struct ODJ_PROVISION_DATA
*r
,
337 struct ODJ_WIN7BLOB
*win7blob
)
342 return WERR_INVALID_PARAMETER
;
345 for (i
= 0; i
< r
->ulcBlobs
; i
++) {
347 struct ODJ_BLOB b
= r
->pBlobs
[i
];
349 switch (b
.ulODJFormat
) {
350 case ODJ_WIN7_FORMAT
:
351 *win7blob
= b
.pBlob
->odj_win7blob
;
354 case ODJ_WIN8_FORMAT
: {
356 struct OP_PACKAGE_PART_COLLECTION
*col
;
360 if (b
.pBlob
->op_package
.p
->WrappedPartCollection
.w
== NULL
) {
361 return WERR_BAD_FORMAT
;
364 col
= b
.pBlob
->op_package
.p
->WrappedPartCollection
.w
->s
.p
;
366 status
= GUID_from_string(ODJ_GUID_JOIN_PROVIDER
, &guid
);
367 if (!NT_STATUS_IS_OK(status
)) {
368 return WERR_NOT_ENOUGH_MEMORY
;
371 for (k
= 0; k
< col
->cParts
; k
++) {
372 if (GUID_equal(&guid
, &col
->pParts
[k
].PartType
)) {
373 *win7blob
= col
->pParts
[k
].Part
->win7blob
;
380 return WERR_BAD_FORMAT
;
384 return WERR_BAD_FORMAT
;
388 WERROR
libnet_odj_find_joinprov3(const struct ODJ_PROVISION_DATA
*r
,
389 struct OP_JOINPROV3_PART
*joinprov3
)
394 return WERR_INVALID_PARAMETER
;
397 for (i
= 0; i
< r
->ulcBlobs
; i
++) {
399 struct ODJ_BLOB b
= r
->pBlobs
[i
];
401 switch (b
.ulODJFormat
) {
402 case ODJ_WIN7_FORMAT
:
405 case ODJ_WIN8_FORMAT
: {
407 struct OP_PACKAGE_PART_COLLECTION
*col
;
411 if (b
.pBlob
->op_package
.p
->WrappedPartCollection
.w
== NULL
) {
412 return WERR_BAD_FORMAT
;
415 col
= b
.pBlob
->op_package
.p
->WrappedPartCollection
.w
->s
.p
;
417 status
= GUID_from_string(ODJ_GUID_JOIN_PROVIDER3
, &guid
);
418 if (!NT_STATUS_IS_OK(status
)) {
419 return WERR_NOT_ENOUGH_MEMORY
;
422 for (k
= 0; k
< col
->cParts
; k
++) {
423 if (GUID_equal(&guid
, &col
->pParts
[k
].PartType
)) {
424 *joinprov3
= *col
->pParts
[k
].Part
->join_prov3
.p
;
431 return WERR_BAD_FORMAT
;
435 return WERR_BAD_FORMAT
;