From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/libnet/libnet_join_offline.c | 441 +++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 source3/libnet/libnet_join_offline.c (limited to 'source3/libnet/libnet_join_offline.c') diff --git a/source3/libnet/libnet_join_offline.c b/source3/libnet/libnet_join_offline.c new file mode 100644 index 0000000..d1317dd --- /dev/null +++ b/source3/libnet/libnet_join_offline.c @@ -0,0 +1,441 @@ +/* + * Unix SMB/CIFS implementation. + * libnet Join offline support + * Copyright (C) Guenther Deschner 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_libnet_join.h" +#include "../librpc/gen_ndr/ndr_ODJ.h" +#include "libnet/libnet_join_offline.h" +#include "libcli/security/dom_sid.h" +#include "rpc_client/util_netlogon.h" + +static WERROR libnet_odj_compose_ODJ_WIN7BLOB(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + struct ODJ_WIN7BLOB *b) +{ + char *samaccount; + uint32_t len; + struct ODJ_POLICY_DNS_DOMAIN_INFO i = { + .Sid = NULL, + }; + + ZERO_STRUCTP(b); + + b->lpDomain = talloc_strdup(mem_ctx, r->out.dns_domain_name); + if (b->lpDomain == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + samaccount = talloc_strdup(mem_ctx, r->out.account_name); + if (samaccount == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + len = strlen(samaccount); + if (samaccount[len-1] == '$') { + samaccount[len-1] = '\0'; + } + b->lpMachineName = samaccount; + + b->lpMachinePassword = talloc_strdup(mem_ctx, r->in.machine_password); + if (b->lpMachinePassword == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + /* fill up ODJ_POLICY_DNS_DOMAIN_INFO */ + + i.Name.string = talloc_strdup(mem_ctx, r->out.netbios_domain_name); + if (i.Name.string == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + i.DnsDomainName.string = talloc_strdup(mem_ctx, r->out.dns_domain_name); + if (i.DnsDomainName.string == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + i.DnsForestName.string = talloc_strdup(mem_ctx, r->out.forest_name); + if (i.DnsForestName.string == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + i.DomainGuid = r->out.domain_guid; + i.Sid = dom_sid_dup(mem_ctx, r->out.domain_sid); + if (i.Sid == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + b->DnsDomainInfo = i; + + if (r->out.dcinfo) { + struct netr_DsRGetDCNameInfo *p; + + p = talloc_steal(mem_ctx, r->out.dcinfo); + if (p == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + b->DcInfo = *p; + } + + /* + * According to + * https://docs.microsoft.com/en-us/windows/win32/netmgmt/odj-odj_win7blob + * it should be 0 but Windows 2019 always sets 6 - gd. + */ + b->Options = 6; + + return WERR_OK; +} + +static WERROR libnet_odj_compose_OP_JOINPROV2_PART(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + struct OP_JOINPROV2_PART **p) +{ + struct OP_JOINPROV2_PART *b; + + b = talloc_zero(mem_ctx, struct OP_JOINPROV2_PART); + if (b == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + /* TODO */ + + *p = b; + + return WERR_INVALID_LEVEL; +} + +static WERROR libnet_odj_compose_OP_JOINPROV3_PART(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + struct OP_JOINPROV3_PART **p) +{ + struct OP_JOINPROV3_PART *b; + struct dom_sid *sid; + + b = talloc_zero(mem_ctx, struct OP_JOINPROV3_PART); + if (b == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + b->Rid = r->out.account_rid; + sid = dom_sid_add_rid(mem_ctx, r->out.domain_sid, r->out.account_rid); + if (sid == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + b->lpSid = dom_sid_string(mem_ctx, sid); + if (b->lpSid == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + *p = b; + + return WERR_OK; +} + +static WERROR libnet_odj_compose_OP_PACKAGE_PART(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + const struct ODJ_WIN7BLOB *win7, + const char *join_provider_guid, + uint32_t flags, + struct OP_PACKAGE_PART *p) +{ + struct GUID guid; + uint32_t level; + WERROR werr; + + if (!NT_STATUS_IS_OK(GUID_from_string(join_provider_guid, &guid))) { + return WERR_NOT_ENOUGH_MEMORY; + } + + level = odj_switch_level_from_guid(&guid); + + p->PartType = guid; + p->ulFlags = flags; + p->part_len = 0; /* autogenerated */ + p->Part = talloc_zero(mem_ctx, union OP_PACKAGE_PART_u); + if (p->Part == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + switch (level) { + case 1: /* ODJ_GUID_JOIN_PROVIDER */ + if (win7 == NULL) { + return WERR_INVALID_PARAMETER; + } + p->Part->win7blob = *win7; + break; + case 2: /* ODJ_GUID_JOIN_PROVIDER2 */ + werr = libnet_odj_compose_OP_JOINPROV2_PART(mem_ctx, r, + &p->Part->join_prov2.p); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + break; + case 3: /* ODJ_GUID_JOIN_PROVIDER3 */ + werr = libnet_odj_compose_OP_JOINPROV3_PART(mem_ctx, r, + &p->Part->join_prov3.p); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + break; + default: + return WERR_INVALID_LEVEL; + } + + return WERR_OK; +} + +static WERROR libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + const struct ODJ_WIN7BLOB *win7, + struct OP_PACKAGE_PART_COLLECTION **pp) +{ + WERROR werr; + struct OP_PACKAGE_PART_COLLECTION *p; + + p = talloc_zero(mem_ctx, struct OP_PACKAGE_PART_COLLECTION); + if (p == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + p->cParts = 2; + p->pParts = talloc_zero_array(p, struct OP_PACKAGE_PART, p->cParts); + if (p->pParts == NULL) { + talloc_free(p); + return WERR_NOT_ENOUGH_MEMORY; + } + + werr = libnet_odj_compose_OP_PACKAGE_PART(p, r, win7, + ODJ_GUID_JOIN_PROVIDER, + OPSPI_PACKAGE_PART_ESSENTIAL, + &p->pParts[0]); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(p); + return werr; + } + + werr = libnet_odj_compose_OP_PACKAGE_PART(p, r, NULL, + ODJ_GUID_JOIN_PROVIDER3, + 0, + &p->pParts[1]); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(p); + return werr; + } + + *pp = p; + + return WERR_OK; +} + +static WERROR libnet_odj_compose_OP_PACKAGE(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + const struct ODJ_WIN7BLOB *win7, + struct OP_PACKAGE **pp) +{ + WERROR werr; + struct OP_PACKAGE_PART_COLLECTION *c; + struct OP_PACKAGE *p; + + p = talloc_zero(mem_ctx, struct OP_PACKAGE); + if (p == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + werr = libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(p, r, win7, &c); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(p); + return werr; + } + + p->EncryptionType = GUID_zero(); + + p->WrappedPartCollection.cbBlob = 0; /* autogenerated */ + p->WrappedPartCollection.w = talloc_zero(p, + struct OP_PACKAGE_PART_COLLECTION_serialized_ptr); + if (p->WrappedPartCollection.w == NULL) { + talloc_free(p); + return WERR_NOT_ENOUGH_MEMORY; + } + + p->WrappedPartCollection.w->s.p = c; + + *pp = p; + + return WERR_OK; +} + +WERROR libnet_odj_compose_ODJ_PROVISION_DATA(TALLOC_CTX *mem_ctx, + const struct libnet_JoinCtx *r, + struct ODJ_PROVISION_DATA **b_p) +{ + WERROR werr; + struct ODJ_PROVISION_DATA *b; + struct ODJ_WIN7BLOB win7; + struct OP_PACKAGE *package; + + b = talloc_zero(mem_ctx, struct ODJ_PROVISION_DATA); + if (b == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + b->ulVersion = 1; + b->ulcBlobs = 2; + b->pBlobs = talloc_zero_array(b, struct ODJ_BLOB, b->ulcBlobs); + if (b->pBlobs == NULL) { + talloc_free(b); + return WERR_NOT_ENOUGH_MEMORY; + } + + werr = libnet_odj_compose_ODJ_WIN7BLOB(b, r, &win7); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(b); + return werr; + } + + werr = libnet_odj_compose_OP_PACKAGE(b, r, &win7, &package); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(b); + return werr; + } + + b->pBlobs[0].ulODJFormat = ODJ_WIN7_FORMAT; + b->pBlobs[0].cbBlob = 0; /* autogenerated */ + b->pBlobs[0].pBlob = talloc_zero(b, union ODJ_BLOB_u); + if (b->pBlobs[0].pBlob == NULL) { + talloc_free(b); + return WERR_NOT_ENOUGH_MEMORY; + } + b->pBlobs[0].pBlob->odj_win7blob = win7; + + b->pBlobs[1].ulODJFormat = ODJ_WIN8_FORMAT; + b->pBlobs[1].cbBlob = 0; /* autogenerated */ + b->pBlobs[1].pBlob = talloc_zero(b, union ODJ_BLOB_u); + if (b->pBlobs[1].pBlob == NULL) { + talloc_free(b); + return WERR_NOT_ENOUGH_MEMORY; + } + b->pBlobs[1].pBlob->op_package.p = package; + + *b_p = b; + + return WERR_OK; +} + +WERROR libnet_odj_find_win7blob(const struct ODJ_PROVISION_DATA *r, + struct ODJ_WIN7BLOB *win7blob) +{ + int i; + + if (r == NULL) { + return WERR_INVALID_PARAMETER; + } + + for (i = 0; i < r->ulcBlobs; i++) { + + struct ODJ_BLOB b = r->pBlobs[i]; + + switch (b.ulODJFormat) { + case ODJ_WIN7_FORMAT: + *win7blob = b.pBlob->odj_win7blob; + return WERR_OK; + + case ODJ_WIN8_FORMAT: { + NTSTATUS status; + struct OP_PACKAGE_PART_COLLECTION *col; + struct GUID guid; + int k; + + if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) { + return WERR_BAD_FORMAT; + } + + col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p; + + status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER, &guid); + if (!NT_STATUS_IS_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + for (k = 0; k < col->cParts; k++) { + if (GUID_equal(&guid, &col->pParts[k].PartType)) { + *win7blob = col->pParts[k].Part->win7blob; + return WERR_OK; + } + } + break; + } + default: + return WERR_BAD_FORMAT; + } + } + + return WERR_BAD_FORMAT; +} + + +WERROR libnet_odj_find_joinprov3(const struct ODJ_PROVISION_DATA *r, + struct OP_JOINPROV3_PART *joinprov3) +{ + int i; + + if (r == NULL) { + return WERR_INVALID_PARAMETER; + } + + for (i = 0; i < r->ulcBlobs; i++) { + + struct ODJ_BLOB b = r->pBlobs[i]; + + switch (b.ulODJFormat) { + case ODJ_WIN7_FORMAT: + continue; + + case ODJ_WIN8_FORMAT: { + NTSTATUS status; + struct OP_PACKAGE_PART_COLLECTION *col; + struct GUID guid; + int k; + + if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) { + return WERR_BAD_FORMAT; + } + + col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p; + + status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER3, &guid); + if (!NT_STATUS_IS_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + for (k = 0; k < col->cParts; k++) { + if (GUID_equal(&guid, &col->pParts[k].PartType)) { + *joinprov3 = *col->pParts[k].Part->join_prov3.p; + return WERR_OK; + } + } + break; + } + default: + return WERR_BAD_FORMAT; + } + } + + return WERR_BAD_FORMAT; +} -- cgit v1.2.3