summaryrefslogtreecommitdiff
path: root/net-fs/samba/files/samba-4.20.8-CVE-2025-0620.patch
blob: 6b15a2258411ffa239394450fcc236413a95a0ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
From 9fd05848d4a59db3977ae74f1a7a89f63f22b9ca Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Fri, 11 Oct 2024 13:32:22 +0000
Subject: [PATCH 1/3] s3:libsmb: let discover_dc_netbios() return
 DOMAIN_CONTROLLER_NOT_FOUND

We may get NT_STATUS_NOT_FOUND when the name can't be resolved
and NT_STATUS_INVALID_ADDRESS if the system doesn't have ipv4
addresses...

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit e47ce1d10b13d8ef165c70984e6e490f4c2a64c2)
---
 source3/libsmb/dsgetdcname.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 654893c172c..00e1fac6b93 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -483,7 +483,19 @@ static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx,
 					&count,
 					resolve_order);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10,("discover_dc_netbios: failed to find DC\n"));
+		NTSTATUS raw_status = status;
+
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+			status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+		}
+		if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_ADDRESS)) {
+			status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+		}
+
+		DBG_DEBUG("failed to find DC for %s: %s => %s\n",
+			  domain_name,
+			  nt_errstr(raw_status),
+			  nt_errstr(status));
 		return status;
 	}
 
-- 
2.47.2


From 4108b021383ccad766a571c93bd6d5fafc4e7b80 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Fri, 9 May 2025 09:38:41 +0200
Subject: [PATCH 2/3] s3:winbindd: avoid using any netlogon call to get a dc
 name

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15876

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(backported from commit f86a4bf6848ade2db7229d182576db3320c3ece7)
---
 source3/winbindd/winbindd_cm.c       | 145 ---------------------------
 source3/winbindd/winbindd_dual_srv.c | 105 +------------------
 2 files changed, 5 insertions(+), 245 deletions(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 1685edbabaa..28ebc15ddf9 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -475,135 +475,6 @@ static bool cm_is_ipc_credentials(struct cli_credentials *creds)
 	return ret;
 }
 
-static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
-				     fstring dcname,
-				     struct sockaddr_storage *dc_ss,
-				     uint32_t request_flags)
-{
-	struct winbindd_domain *our_domain = NULL;
-	struct rpc_pipe_client *netlogon_pipe = NULL;
-	NTSTATUS result;
-	WERROR werr;
-	TALLOC_CTX *mem_ctx;
-	unsigned int orig_timeout;
-	const char *tmp = NULL;
-	const char *p;
-	struct dcerpc_binding_handle *b;
-
-	/* Hmmmm. We can only open one connection to the NETLOGON pipe at the
-	 * moment.... */
-
-	if (IS_DC) {
-		return False;
-	}
-
-	if (domain->primary) {
-		return False;
-	}
-
-	our_domain = find_our_domain();
-
-	if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
-		return False;
-	}
-
-	result = cm_connect_netlogon(our_domain, &netlogon_pipe);
-	if (!NT_STATUS_IS_OK(result)) {
-		talloc_destroy(mem_ctx);
-		return False;
-	}
-
-	b = netlogon_pipe->binding_handle;
-
-	/* This call can take a long time - allow the server to time out.
-	   35 seconds should do it. */
-
-	orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
-
-	if (our_domain->active_directory) {
-		struct netr_DsRGetDCNameInfo *domain_info = NULL;
-
-		/*
-		 * TODO request flags are not respected in the server
-		 * (and in some cases, like REQUIRE_PDC, causes an error)
-		 */
-		result = dcerpc_netr_DsRGetDCName(b,
-						  mem_ctx,
-						  our_domain->dcname,
-						  domain->name,
-						  NULL,
-						  NULL,
-						  request_flags|DS_RETURN_DNS_NAME,
-						  &domain_info,
-						  &werr);
-		if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) {
-			tmp = talloc_strdup(
-				mem_ctx, domain_info->dc_unc);
-			if (tmp == NULL) {
-				DEBUG(0, ("talloc_strdup failed\n"));
-				talloc_destroy(mem_ctx);
-				return false;
-			}
-			if (domain->alt_name == NULL) {
-				domain->alt_name = talloc_strdup(domain,
-								 domain_info->domain_name);
-				if (domain->alt_name == NULL) {
-					DEBUG(0, ("talloc_strdup failed\n"));
-					talloc_destroy(mem_ctx);
-					return false;
-				}
-			}
-			if (domain->forest_name == NULL) {
-				domain->forest_name = talloc_strdup(domain,
-								    domain_info->forest_name);
-				if (domain->forest_name == NULL) {
-					DEBUG(0, ("talloc_strdup failed\n"));
-					talloc_destroy(mem_ctx);
-					return false;
-				}
-			}
-		}
-	} else {
-		result = dcerpc_netr_GetAnyDCName(b, mem_ctx,
-						  our_domain->dcname,
-						  domain->name,
-						  &tmp,
-						  &werr);
-	}
-
-	/* And restore our original timeout. */
-	rpccli_set_timeout(netlogon_pipe, orig_timeout);
-
-	if (!NT_STATUS_IS_OK(result)) {
-		DEBUG(10,("dcerpc_netr_GetAnyDCName failed: %s\n",
-			nt_errstr(result)));
-		talloc_destroy(mem_ctx);
-		return false;
-	}
-
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(10,("dcerpc_netr_GetAnyDCName failed: %s\n",
-			   win_errstr(werr)));
-		talloc_destroy(mem_ctx);
-		return false;
-	}
-
-	/* dcerpc_netr_GetAnyDCName gives us a name with \\ */
-	p = strip_hostname(tmp);
-
-	fstrcpy(dcname, p);
-
-	talloc_destroy(mem_ctx);
-
-	DEBUG(10,("dcerpc_netr_GetAnyDCName returned %s\n", dcname));
-
-	if (!resolve_name(dcname, dc_ss, 0x20, true)) {
-		return False;
-	}
-
-	return True;
-}
-
 /**
  * Helper function to assemble trust password and account name
  */
@@ -1283,24 +1154,8 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
 	struct  samba_sockaddr *sa_list = NULL;
 	size_t     salist_size = 0;
 	size_t     i;
-	bool    is_our_domain;
 	enum security_types sec = (enum security_types)lp_security();
 
-	is_our_domain = strequal(domain->name, lp_workgroup());
-
-	/* If not our domain, get the preferred DC, by asking our primary DC */
-	if ( !is_our_domain
-		&& get_dc_name_via_netlogon(domain, dcname, &ss, request_flags)
-		&& add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
-		       num_dcs) )
-	{
-		char addr[INET6_ADDRSTRLEN];
-		print_sockaddr(addr, sizeof(addr), &ss);
-		DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
-			   dcname, addr));
-		return True;
-	}
-
 	if ((sec == SEC_ADS) && (domain->alt_name != NULL)) {
 		char *sitename = NULL;
 
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index bbdaf6e5807..0d9d88733da 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -662,106 +662,11 @@ NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
 
 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 {
-	struct winbindd_domain *domain = wb_child_domain();
-	struct rpc_pipe_client *netlogon_pipe;
-	struct netr_DsRGetDCNameInfo *dc_info;
-	NTSTATUS status;
-	WERROR werr;
-	unsigned int orig_timeout;
-	struct dcerpc_binding_handle *b;
-	bool retry = false;
-	bool try_dsrgetdcname = false;
-
-	if (domain == NULL) {
-		return dsgetdcname(p->mem_ctx, global_messaging_context(),
-				   r->in.domain_name, r->in.domain_guid,
-				   r->in.site_name ? r->in.site_name : "",
-				   r->in.flags,
-				   r->out.dc_info);
-	}
-
-	if (domain->active_directory) {
-		try_dsrgetdcname = true;
-	}
-
-reconnect:
-	status = cm_connect_netlogon(domain, &netlogon_pipe);
-
-	reset_cm_connection_on_error(domain, NULL, status);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
-		return status;
-	}
-
-	b = netlogon_pipe->binding_handle;
-
-	/* This call can take a long time - allow the server to time out.
-	   35 seconds should do it. */
-
-	orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
-
-	if (try_dsrgetdcname) {
-		status = dcerpc_netr_DsRGetDCName(b,
-			p->mem_ctx, domain->dcname,
-			r->in.domain_name, NULL, r->in.domain_guid,
-			r->in.flags, r->out.dc_info, &werr);
-		if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
-			goto done;
-		}
-		if (!retry &&
-		    reset_cm_connection_on_error(domain, NULL, status))
-		{
-			retry = true;
-			goto reconnect;
-		}
-		try_dsrgetdcname = false;
-		retry = false;
-	}
-
-	/*
-	 * Fallback to less capable methods
-	 */
-
-	dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
-	if (dc_info == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto done;
-	}
-
-	if (r->in.flags & DS_PDC_REQUIRED) {
-		status = dcerpc_netr_GetDcName(b,
-			p->mem_ctx, domain->dcname,
-			r->in.domain_name, &dc_info->dc_unc, &werr);
-	} else {
-		status = dcerpc_netr_GetAnyDCName(b,
-			p->mem_ctx, domain->dcname,
-			r->in.domain_name, &dc_info->dc_unc, &werr);
-	}
-
-	if (!retry && reset_cm_connection_on_error(domain, b, status)) {
-		retry = true;
-		goto reconnect;
-	}
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
-			   nt_errstr(status)));
-		goto done;
-	}
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
-			   win_errstr(werr)));
-		status = werror_to_ntstatus(werr);
-		goto done;
-	}
-
-	*r->out.dc_info = dc_info;
-	status = NT_STATUS_OK;
-
-done:
-	/* And restore our original timeout. */
-	rpccli_set_timeout(netlogon_pipe, orig_timeout);
-
-	return status;
+	return dsgetdcname(p->mem_ctx, global_messaging_context(),
+			   r->in.domain_name, r->in.domain_guid,
+			   r->in.site_name ? r->in.site_name : "",
+			   r->in.flags,
+			   r->out.dc_info);
 }
 
 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
-- 
2.47.2


From 41191db034ea7825acd01a0166cd2a8b425878ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Wed, 2 Jul 2025 21:59:48 +0200
Subject: [PATCH 3/3] s3-winbindd: Fix internal winbind dsgetdcname calls
 w.r.t. domain name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

when winbind calls to dsgetdcname internally, make sure to
prefer the DNS domain name if we have it. Makes DNS lookups much more
likely to succeed.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15876

Guenther

Signed-off-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>

Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Mon Jul  7 10:44:37 UTC 2025 on atb-devel-224

(cherry picked from commit 2560c9b3224816ffd371a62103f65b3aca301ad5)
---
 source3/winbindd/wb_queryuser.c   | 17 +++++++++++++----
 source3/winbindd/wb_sids2xids.c   | 17 +++++++++++++----
 source3/winbindd/wb_xids2sids.c   | 12 +++++++++---
 source3/winbindd/winbindd_dual.c  |  6 +++++-
 source3/winbindd/winbindd_proto.h |  1 +
 source3/winbindd/winbindd_util.c  | 19 +++++++++++++++++++
 6 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c
index c2758f1b76a..db8e946ba71 100644
--- a/source3/winbindd/wb_queryuser.c
+++ b/source3/winbindd/wb_queryuser.c
@@ -289,10 +289,19 @@ static void wb_queryuser_done(struct tevent_req *subreq)
 
 	if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
 	    !state->tried_dclookup) {
-		D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling wb_dsgetdcname_send()\n");
-		subreq = wb_dsgetdcname_send(
-			state, state->ev, state->info->domain_name, NULL, NULL,
-			DS_RETURN_DNS_NAME);
+		const char *domain_name = find_dns_domain_name(
+			state->info->domain_name);
+
+		D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling "
+			"wb_dsgetdcname_send(%s)\n",
+			domain_name);
+
+		subreq = wb_dsgetdcname_send(state,
+					     state->ev,
+					     domain_name,
+					     NULL,
+					     NULL,
+					     DS_RETURN_DNS_NAME);
 		if (tevent_req_nomem(subreq, req)) {
 			return;
 		}
diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c
index f0f6c23fc20..03e5e7e0258 100644
--- a/source3/winbindd/wb_sids2xids.c
+++ b/source3/winbindd/wb_sids2xids.c
@@ -612,13 +612,22 @@ static void wb_sids2xids_done(struct tevent_req *subreq)
 	    !state->tried_dclookup) {
 
 		struct lsa_DomainInfo *d;
+		const char *domain_name = NULL;
 
-		D_DEBUG("Domain controller not found. Calling wb_dsgetdcname_send() to get it.\n");
 		d = &state->idmap_doms.domains[state->dom_index];
 
-		subreq = wb_dsgetdcname_send(
-			state, state->ev, d->name.string, NULL, NULL,
-			DS_RETURN_DNS_NAME);
+		domain_name = find_dns_domain_name(d->name.string);
+
+		D_DEBUG("Domain controller not found. Calling "
+			"wb_dsgetdcname_send(%s) to get it.\n",
+			domain_name);
+
+		subreq = wb_dsgetdcname_send(state,
+					     state->ev,
+					     domain_name,
+					     NULL,
+					     NULL,
+					     DS_RETURN_DNS_NAME);
 		if (tevent_req_nomem(subreq, req)) {
 			return;
 		}
diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c
index 86bd7f9deab..6fcf524d94f 100644
--- a/source3/winbindd/wb_xids2sids.c
+++ b/source3/winbindd/wb_xids2sids.c
@@ -143,9 +143,15 @@ static void wb_xids2sids_dom_done(struct tevent_req *subreq)
 	if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
 	    !state->tried_dclookup) {
 
-		subreq = wb_dsgetdcname_send(
-			state, state->ev, state->dom_map->name, NULL, NULL,
-			DS_RETURN_DNS_NAME);
+		const char *domain_name = find_dns_domain_name(
+			state->dom_map->name);
+
+		subreq = wb_dsgetdcname_send(state,
+					     state->ev,
+					     domain_name,
+					     NULL,
+					     NULL,
+					     DS_RETURN_DNS_NAME);
 		if (tevent_req_nomem(subreq, req)) {
 			return;
 		}
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index b8e1ceddecc..ee80a4725fa 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -532,6 +532,7 @@ static void wb_domain_request_trigger(struct tevent_req *req,
 	struct wb_domain_request_state *state = tevent_req_data(
 		req, struct wb_domain_request_state);
 	struct winbindd_domain *domain = state->domain;
+	const char *domain_name = NULL;
 	struct tevent_req *subreq = NULL;
 	size_t shortest_queue_length;
 
@@ -604,8 +605,11 @@ static void wb_domain_request_trigger(struct tevent_req *req,
 	 * which is indicated by DS_RETURN_DNS_NAME.
 	 * For NT4 domains we still get the netbios name.
 	 */
+
+	domain_name = find_dns_domain_name(state->domain->name);
+
 	subreq = wb_dsgetdcname_send(state, state->ev,
-				     state->domain->name,
+				     domain_name,
 				     NULL, /* domain_guid */
 				     NULL, /* site_name */
 				     DS_RETURN_DNS_NAME); /* flags */
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 4dee9b046cf..292b96ee5fa 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -603,6 +603,7 @@ bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
 		   struct dom_sid **sids, uint32_t *num_sids);
 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
 		   struct unixid **pxids, uint32_t *pnum_xids);
+const char *find_dns_domain_name(const char *domain_name);
 
 /* The following definitions come from winbindd/winbindd_wins.c  */
 
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 7527a78b30e..5c832fc22b5 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -2241,3 +2241,22 @@ fail:
 	TALLOC_FREE(xids);
 	return false;
 }
+
+/**
+ * Helper to extract the DNS Domain Name from a struct winbindd_domain
+ */
+const char *find_dns_domain_name(const char *domain_name)
+{
+	struct winbindd_domain *wbdom = NULL;
+
+	wbdom = find_domain_from_name(domain_name);
+	if (wbdom == NULL) {
+		return domain_name;
+	}
+
+	if (wbdom->active_directory && wbdom->alt_name != NULL) {
+		return wbdom->alt_name;
+	}
+
+	return wbdom->name;
+}
-- 
2.47.2