Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * libnet Join offline support
4 : * Copyright (C) Guenther Deschner 2021
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 "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"
26 :
27 18 : static WERROR libnet_odj_compose_ODJ_WIN7BLOB(TALLOC_CTX *mem_ctx,
28 : const struct libnet_JoinCtx *r,
29 : struct ODJ_WIN7BLOB *b)
30 : {
31 0 : char *samaccount;
32 0 : uint32_t len;
33 18 : struct ODJ_POLICY_DNS_DOMAIN_INFO i = {
34 : .Sid = NULL,
35 : };
36 :
37 18 : ZERO_STRUCTP(b);
38 :
39 18 : b->lpDomain = talloc_strdup(mem_ctx, r->out.dns_domain_name);
40 18 : if (b->lpDomain == NULL) {
41 0 : return WERR_NOT_ENOUGH_MEMORY;
42 : }
43 :
44 18 : samaccount = talloc_strdup(mem_ctx, r->out.account_name);
45 18 : if (samaccount == NULL) {
46 0 : return WERR_NOT_ENOUGH_MEMORY;
47 : }
48 18 : len = strlen(samaccount);
49 18 : if (samaccount[len-1] == '$') {
50 18 : samaccount[len-1] = '\0';
51 : }
52 18 : b->lpMachineName = samaccount;
53 :
54 18 : b->lpMachinePassword = talloc_strdup(mem_ctx, r->in.machine_password);
55 18 : if (b->lpMachinePassword == NULL) {
56 0 : return WERR_NOT_ENOUGH_MEMORY;
57 : }
58 :
59 : /* fill up ODJ_POLICY_DNS_DOMAIN_INFO */
60 :
61 18 : i.Name.string = talloc_strdup(mem_ctx, r->out.netbios_domain_name);
62 18 : if (i.Name.string == NULL) {
63 0 : return WERR_NOT_ENOUGH_MEMORY;
64 : }
65 :
66 18 : i.DnsDomainName.string = talloc_strdup(mem_ctx, r->out.dns_domain_name);
67 18 : if (i.DnsDomainName.string == NULL) {
68 0 : return WERR_NOT_ENOUGH_MEMORY;
69 : }
70 :
71 18 : i.DnsForestName.string = talloc_strdup(mem_ctx, r->out.forest_name);
72 18 : if (i.DnsForestName.string == NULL) {
73 0 : return WERR_NOT_ENOUGH_MEMORY;
74 : }
75 :
76 18 : i.DomainGuid = r->out.domain_guid;
77 18 : i.Sid = dom_sid_dup(mem_ctx, r->out.domain_sid);
78 18 : if (i.Sid == NULL) {
79 0 : return WERR_NOT_ENOUGH_MEMORY;
80 : }
81 :
82 18 : b->DnsDomainInfo = i;
83 :
84 18 : if (r->out.dcinfo) {
85 0 : struct netr_DsRGetDCNameInfo *p;
86 :
87 18 : p = talloc_steal(mem_ctx, r->out.dcinfo);
88 18 : if (p == NULL) {
89 0 : return WERR_NOT_ENOUGH_MEMORY;
90 : }
91 :
92 18 : b->DcInfo = *p;
93 : }
94 :
95 : /*
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.
99 : */
100 18 : b->Options = 6;
101 :
102 18 : return WERR_OK;
103 : }
104 :
105 0 : static WERROR libnet_odj_compose_OP_JOINPROV2_PART(TALLOC_CTX *mem_ctx,
106 : const struct libnet_JoinCtx *r,
107 : struct OP_JOINPROV2_PART **p)
108 : {
109 0 : struct OP_JOINPROV2_PART *b;
110 :
111 0 : b = talloc_zero(mem_ctx, struct OP_JOINPROV2_PART);
112 0 : if (b == NULL) {
113 0 : return WERR_NOT_ENOUGH_MEMORY;
114 : }
115 :
116 : /* TODO */
117 :
118 0 : *p = b;
119 :
120 0 : return WERR_INVALID_LEVEL;
121 : }
122 :
123 18 : static WERROR libnet_odj_compose_OP_JOINPROV3_PART(TALLOC_CTX *mem_ctx,
124 : const struct libnet_JoinCtx *r,
125 : struct OP_JOINPROV3_PART **p)
126 : {
127 0 : struct OP_JOINPROV3_PART *b;
128 0 : struct dom_sid *sid;
129 :
130 18 : b = talloc_zero(mem_ctx, struct OP_JOINPROV3_PART);
131 18 : if (b == NULL) {
132 0 : return WERR_NOT_ENOUGH_MEMORY;
133 : }
134 :
135 18 : b->Rid = r->out.account_rid;
136 18 : sid = dom_sid_add_rid(mem_ctx, r->out.domain_sid, r->out.account_rid);
137 18 : if (sid == NULL) {
138 0 : return WERR_NOT_ENOUGH_MEMORY;
139 : }
140 :
141 18 : b->lpSid = dom_sid_string(mem_ctx, sid);
142 18 : if (b->lpSid == NULL) {
143 0 : return WERR_NOT_ENOUGH_MEMORY;
144 : }
145 :
146 18 : *p = b;
147 :
148 18 : return WERR_OK;
149 : }
150 :
151 36 : 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)
157 : {
158 0 : struct GUID guid;
159 0 : uint32_t level;
160 0 : WERROR werr;
161 :
162 36 : if (!NT_STATUS_IS_OK(GUID_from_string(join_provider_guid, &guid))) {
163 0 : return WERR_NOT_ENOUGH_MEMORY;
164 : }
165 :
166 36 : level = odj_switch_level_from_guid(&guid);
167 :
168 36 : p->PartType = guid;
169 36 : p->ulFlags = flags;
170 36 : p->part_len = 0; /* autogenerated */
171 36 : p->Part = talloc_zero(mem_ctx, union OP_PACKAGE_PART_u);
172 36 : if (p->Part == NULL) {
173 0 : return WERR_NOT_ENOUGH_MEMORY;
174 : }
175 :
176 36 : switch (level) {
177 18 : case 1: /* ODJ_GUID_JOIN_PROVIDER */
178 18 : if (win7 == NULL) {
179 0 : return WERR_INVALID_PARAMETER;
180 : }
181 18 : p->Part->win7blob = *win7;
182 18 : break;
183 0 : case 2: /* ODJ_GUID_JOIN_PROVIDER2 */
184 0 : werr = libnet_odj_compose_OP_JOINPROV2_PART(mem_ctx, r,
185 0 : &p->Part->join_prov2.p);
186 0 : if (!W_ERROR_IS_OK(werr)) {
187 0 : return werr;
188 : }
189 0 : break;
190 18 : case 3: /* ODJ_GUID_JOIN_PROVIDER3 */
191 18 : werr = libnet_odj_compose_OP_JOINPROV3_PART(mem_ctx, r,
192 18 : &p->Part->join_prov3.p);
193 18 : if (!W_ERROR_IS_OK(werr)) {
194 0 : return werr;
195 : }
196 18 : break;
197 0 : default:
198 0 : return WERR_INVALID_LEVEL;
199 : }
200 :
201 36 : return WERR_OK;
202 : }
203 :
204 18 : 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)
208 : {
209 0 : WERROR werr;
210 0 : struct OP_PACKAGE_PART_COLLECTION *p;
211 :
212 18 : p = talloc_zero(mem_ctx, struct OP_PACKAGE_PART_COLLECTION);
213 18 : if (p == NULL) {
214 0 : return WERR_NOT_ENOUGH_MEMORY;
215 : }
216 :
217 18 : p->cParts = 2;
218 18 : p->pParts = talloc_zero_array(p, struct OP_PACKAGE_PART, p->cParts);
219 18 : if (p->pParts == NULL) {
220 0 : talloc_free(p);
221 0 : return WERR_NOT_ENOUGH_MEMORY;
222 : }
223 :
224 18 : 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 18 : if (!W_ERROR_IS_OK(werr)) {
229 0 : talloc_free(p);
230 0 : return werr;
231 : }
232 :
233 18 : werr = libnet_odj_compose_OP_PACKAGE_PART(p, r, NULL,
234 : ODJ_GUID_JOIN_PROVIDER3,
235 : 0,
236 18 : &p->pParts[1]);
237 18 : if (!W_ERROR_IS_OK(werr)) {
238 0 : talloc_free(p);
239 0 : return werr;
240 : }
241 :
242 18 : *pp = p;
243 :
244 18 : return WERR_OK;
245 : }
246 :
247 18 : 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)
251 : {
252 0 : WERROR werr;
253 0 : struct OP_PACKAGE_PART_COLLECTION *c;
254 0 : struct OP_PACKAGE *p;
255 :
256 18 : p = talloc_zero(mem_ctx, struct OP_PACKAGE);
257 18 : if (p == NULL) {
258 0 : return WERR_NOT_ENOUGH_MEMORY;
259 : }
260 :
261 18 : werr = libnet_odj_compose_OP_PACKAGE_PART_COLLECTION(p, r, win7, &c);
262 18 : if (!W_ERROR_IS_OK(werr)) {
263 0 : talloc_free(p);
264 0 : return werr;
265 : }
266 :
267 18 : p->EncryptionType = GUID_zero();
268 :
269 18 : p->WrappedPartCollection.cbBlob = 0; /* autogenerated */
270 18 : p->WrappedPartCollection.w = talloc_zero(p,
271 : struct OP_PACKAGE_PART_COLLECTION_serialized_ptr);
272 18 : if (p->WrappedPartCollection.w == NULL) {
273 0 : talloc_free(p);
274 0 : return WERR_NOT_ENOUGH_MEMORY;
275 : }
276 :
277 18 : p->WrappedPartCollection.w->s.p = c;
278 :
279 18 : *pp = p;
280 :
281 18 : return WERR_OK;
282 : }
283 :
284 18 : WERROR libnet_odj_compose_ODJ_PROVISION_DATA(TALLOC_CTX *mem_ctx,
285 : const struct libnet_JoinCtx *r,
286 : struct ODJ_PROVISION_DATA **b_p)
287 : {
288 0 : WERROR werr;
289 0 : struct ODJ_PROVISION_DATA *b;
290 0 : struct ODJ_WIN7BLOB win7;
291 0 : struct OP_PACKAGE *package;
292 :
293 18 : b = talloc_zero(mem_ctx, struct ODJ_PROVISION_DATA);
294 18 : if (b == NULL) {
295 0 : return WERR_NOT_ENOUGH_MEMORY;
296 : }
297 :
298 18 : b->ulVersion = 1;
299 18 : b->ulcBlobs = 2;
300 18 : b->pBlobs = talloc_zero_array(b, struct ODJ_BLOB, b->ulcBlobs);
301 18 : if (b->pBlobs == NULL) {
302 0 : talloc_free(b);
303 0 : return WERR_NOT_ENOUGH_MEMORY;
304 : }
305 :
306 18 : werr = libnet_odj_compose_ODJ_WIN7BLOB(b, r, &win7);
307 18 : if (!W_ERROR_IS_OK(werr)) {
308 0 : talloc_free(b);
309 0 : return werr;
310 : }
311 :
312 18 : werr = libnet_odj_compose_OP_PACKAGE(b, r, &win7, &package);
313 18 : if (!W_ERROR_IS_OK(werr)) {
314 0 : talloc_free(b);
315 0 : return werr;
316 : }
317 :
318 18 : b->pBlobs[0].ulODJFormat = ODJ_WIN7_FORMAT;
319 18 : b->pBlobs[0].cbBlob = 0; /* autogenerated */
320 18 : b->pBlobs[0].pBlob = talloc_zero(b, union ODJ_BLOB_u);
321 18 : if (b->pBlobs[0].pBlob == NULL) {
322 0 : talloc_free(b);
323 0 : return WERR_NOT_ENOUGH_MEMORY;
324 : }
325 18 : b->pBlobs[0].pBlob->odj_win7blob = win7;
326 :
327 18 : b->pBlobs[1].ulODJFormat = ODJ_WIN8_FORMAT;
328 18 : b->pBlobs[1].cbBlob = 0; /* autogenerated */
329 18 : b->pBlobs[1].pBlob = talloc_zero(b, union ODJ_BLOB_u);
330 18 : if (b->pBlobs[1].pBlob == NULL) {
331 0 : talloc_free(b);
332 0 : return WERR_NOT_ENOUGH_MEMORY;
333 : }
334 18 : b->pBlobs[1].pBlob->op_package.p = package;
335 :
336 18 : *b_p = b;
337 :
338 18 : return WERR_OK;
339 : }
340 :
341 36 : WERROR libnet_odj_find_win7blob(const struct ODJ_PROVISION_DATA *r,
342 : struct ODJ_WIN7BLOB *win7blob)
343 : {
344 0 : int i;
345 :
346 36 : if (r == NULL) {
347 0 : return WERR_INVALID_PARAMETER;
348 : }
349 :
350 36 : for (i = 0; i < r->ulcBlobs; i++) {
351 :
352 36 : struct ODJ_BLOB b = r->pBlobs[i];
353 :
354 36 : switch (b.ulODJFormat) {
355 36 : case ODJ_WIN7_FORMAT:
356 36 : *win7blob = b.pBlob->odj_win7blob;
357 36 : return WERR_OK;
358 :
359 0 : case ODJ_WIN8_FORMAT: {
360 0 : NTSTATUS status;
361 0 : struct OP_PACKAGE_PART_COLLECTION *col;
362 0 : struct GUID guid;
363 0 : int k;
364 :
365 0 : if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) {
366 0 : return WERR_BAD_FORMAT;
367 : }
368 :
369 0 : col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p;
370 :
371 0 : status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER, &guid);
372 0 : if (!NT_STATUS_IS_OK(status)) {
373 0 : return WERR_NOT_ENOUGH_MEMORY;
374 : }
375 :
376 0 : for (k = 0; k < col->cParts; k++) {
377 0 : if (GUID_equal(&guid, &col->pParts[k].PartType)) {
378 0 : *win7blob = col->pParts[k].Part->win7blob;
379 0 : return WERR_OK;
380 : }
381 : }
382 0 : break;
383 : }
384 0 : default:
385 0 : return WERR_BAD_FORMAT;
386 : }
387 : }
388 :
389 0 : return WERR_BAD_FORMAT;
390 : }
391 :
392 :
393 18 : WERROR libnet_odj_find_joinprov3(const struct ODJ_PROVISION_DATA *r,
394 : struct OP_JOINPROV3_PART *joinprov3)
395 : {
396 0 : int i;
397 :
398 18 : if (r == NULL) {
399 0 : return WERR_INVALID_PARAMETER;
400 : }
401 :
402 36 : for (i = 0; i < r->ulcBlobs; i++) {
403 :
404 36 : struct ODJ_BLOB b = r->pBlobs[i];
405 :
406 36 : switch (b.ulODJFormat) {
407 18 : case ODJ_WIN7_FORMAT:
408 18 : continue;
409 :
410 18 : case ODJ_WIN8_FORMAT: {
411 0 : NTSTATUS status;
412 0 : struct OP_PACKAGE_PART_COLLECTION *col;
413 0 : struct GUID guid;
414 0 : int k;
415 :
416 18 : if (b.pBlob->op_package.p->WrappedPartCollection.w == NULL) {
417 0 : return WERR_BAD_FORMAT;
418 : }
419 :
420 18 : col = b.pBlob->op_package.p->WrappedPartCollection.w->s.p;
421 :
422 18 : status = GUID_from_string(ODJ_GUID_JOIN_PROVIDER3, &guid);
423 18 : if (!NT_STATUS_IS_OK(status)) {
424 0 : return WERR_NOT_ENOUGH_MEMORY;
425 : }
426 :
427 36 : for (k = 0; k < col->cParts; k++) {
428 36 : if (GUID_equal(&guid, &col->pParts[k].PartType)) {
429 18 : *joinprov3 = *col->pParts[k].Part->join_prov3.p;
430 18 : return WERR_OK;
431 : }
432 : }
433 0 : break;
434 : }
435 0 : default:
436 0 : return WERR_BAD_FORMAT;
437 : }
438 : }
439 :
440 0 : return WERR_BAD_FORMAT;
441 : }
|