xref: /titanic_52/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c (revision bbf6f00c25b6a2bed23c35eac6d62998ecdb338c)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
227f667e74Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * This module handles the primary domain controller location protocol.
28da6c28aaSamw  * The document claims to be version 1.15 of the browsing protocol. It also
29da6c28aaSamw  * claims to specify the mailslot protocol.
30da6c28aaSamw  *
31da6c28aaSamw  * The NETLOGON protocol uses \MAILSLOT\NET mailslots. The protocol
32da6c28aaSamw  * specification is incomplete, contains errors and is out-of-date but
33da6c28aaSamw  * it does provide some useful background information. The document
34da6c28aaSamw  * doesn't mention the NETLOGON_SAMLOGON version of the protocol.
35da6c28aaSamw  */
36da6c28aaSamw 
37da6c28aaSamw #include <stdlib.h>
38da6c28aaSamw #include <syslog.h>
39da6c28aaSamw #include <alloca.h>
40da6c28aaSamw #include <arpa/inet.h>
41da6c28aaSamw #include <resolv.h>
42da6c28aaSamw 
43da6c28aaSamw #include <smbsrv/mailslot.h>
44da6c28aaSamw #include <smbsrv/libsmbns.h>
45da6c28aaSamw #include <smbns_browser.h>
46da6c28aaSamw #include <smbns_netbios.h>
47da6c28aaSamw 
48da6c28aaSamw static void smb_netlogon_query(struct name_entry *server, char *mailbox,
49da6c28aaSamw     char *domain);
50da6c28aaSamw 
5129bd2886SAlan Wright static void smb_netlogon_samlogon(struct name_entry *, char *,
5229bd2886SAlan Wright     char *, smb_sid_t *);
53da6c28aaSamw 
54da6c28aaSamw static void smb_netlogon_send(struct name_entry *name, char *domain,
55da6c28aaSamw     unsigned char *buffer, int count);
56da6c28aaSamw 
57da6c28aaSamw static void smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr);
583db3f65cSamw static int smb_better_dc(uint32_t cur_ip, uint32_t new_ip);
59da6c28aaSamw 
608d7e4166Sjose borrego /*
618d7e4166Sjose borrego  * ntdomain_info
628d7e4166Sjose borrego  * Temporary. It should be removed once NBTD is integrated.
638d7e4166Sjose borrego  */
648d7e4166Sjose borrego extern smb_ntdomain_t ntdomain_info;
658d7e4166Sjose borrego extern mutex_t ntdomain_mtx;
668d7e4166Sjose borrego extern cond_t ntdomain_cv;
67da6c28aaSamw 
68da6c28aaSamw /*
69da6c28aaSamw  * smb_netlogon_request
70da6c28aaSamw  *
71da6c28aaSamw  * This is the entry point locating the resource domain PDC. A netlogon
72da6c28aaSamw  * request is sent using the specified protocol on the specified network.
73da6c28aaSamw  * Note that we need to know the domain SID in order to use the samlogon
74da6c28aaSamw  * format.
75da6c28aaSamw  *
76da6c28aaSamw  * Netlogon responses are received asynchronously and eventually handled
77da6c28aaSamw  * in smb_netlogon_receive.
78da6c28aaSamw  */
79da6c28aaSamw void
8029bd2886SAlan Wright smb_netlogon_request(struct name_entry *server, char *domain)
81da6c28aaSamw {
82a0aa776eSAlan Wright 	smb_domain_t di;
8329bd2886SAlan Wright 	smb_sid_t *sid = NULL;
8429bd2886SAlan Wright 	int protocol = NETLOGON_PROTO_NETLOGON;
85da6c28aaSamw 
867b59d02dSjb150015 	if (domain == NULL || *domain == '\0')
87da6c28aaSamw 		return;
88da6c28aaSamw 
898d7e4166Sjose borrego 	(void) mutex_lock(&ntdomain_mtx);
908d7e4166Sjose borrego 	(void) strlcpy(ntdomain_info.n_domain, domain,
918d7e4166Sjose borrego 	    sizeof (ntdomain_info.n_domain));
928d7e4166Sjose borrego 	(void) mutex_unlock(&ntdomain_mtx);
93da6c28aaSamw 
9429bd2886SAlan Wright 	smb_config_getdomaininfo(di.di_nbname, NULL, di.di_sid, NULL, NULL);
95*bbf6f00cSJordan Brown 	if (smb_strcasecmp(di.di_nbname, domain, 0) == 0) {
9629bd2886SAlan Wright 		if ((sid = smb_sid_fromstr(di.di_sid)) != NULL)
9729bd2886SAlan Wright 			protocol = NETLOGON_PROTO_SAMLOGON;
9829bd2886SAlan Wright 	}
9929bd2886SAlan Wright 
10029bd2886SAlan Wright 	if (protocol == NETLOGON_PROTO_SAMLOGON)
10129bd2886SAlan Wright 		smb_netlogon_samlogon(server, MAILSLOT_NETLOGON_SAMLOGON_RDC,
10229bd2886SAlan Wright 		    domain, sid);
103da6c28aaSamw 	else
10429bd2886SAlan Wright 		smb_netlogon_query(server, MAILSLOT_NETLOGON_RDC, domain);
10529bd2886SAlan Wright 
10629bd2886SAlan Wright 	smb_sid_free(sid);
107da6c28aaSamw }
108da6c28aaSamw 
109da6c28aaSamw /*
110da6c28aaSamw  * smb_netlogon_receive
111da6c28aaSamw  *
112da6c28aaSamw  * This is where we handle all incoming NetLogon messages. Currently, we
113da6c28aaSamw  * ignore requests from anyone else. We are only interested in responses
114da6c28aaSamw  * to our own requests. The NetLogonResponse provides the name of the PDC.
115da6c28aaSamw  * If we don't already have a controller name, we use the name provided
116da6c28aaSamw  * in the message. Otherwise we use the name already in the environment.
117da6c28aaSamw  */
118da6c28aaSamw void
119da6c28aaSamw smb_netlogon_receive(struct datagram *datagram,
120da6c28aaSamw 				char *mailbox,
121da6c28aaSamw 				unsigned char *data,
122da6c28aaSamw 				int datalen)
123da6c28aaSamw {
124da6c28aaSamw 	struct netlogon_opt {
125da6c28aaSamw 		char *mailslot;
126da6c28aaSamw 		void (*handler)();
127da6c28aaSamw 	} netlogon_opt[] = {
128da6c28aaSamw 		{ MAILSLOT_NETLOGON_RDC, smb_netlogon_rdc_rsp },
129da6c28aaSamw 		{ MAILSLOT_NETLOGON_SAMLOGON_RDC, smb_netlogon_rdc_rsp },
130da6c28aaSamw 	};
131da6c28aaSamw 
132da6c28aaSamw 	smb_msgbuf_t mb;
133da6c28aaSamw 	unsigned short opcode;
134da6c28aaSamw 	char src_name[SMB_PI_MAX_HOST];
135*bbf6f00cSJordan Brown 	smb_wchar_t unicode_src_name[SMB_PI_MAX_HOST];
136da6c28aaSamw 	uint32_t src_ipaddr;
137da6c28aaSamw 	char *junk;
138da6c28aaSamw 	char *primary;
139da6c28aaSamw 	char *domain;
140da6c28aaSamw 	int i;
141da6c28aaSamw 	char ipstr[16];
142da6c28aaSamw 	int rc;
143da6c28aaSamw 
144da6c28aaSamw 	src_ipaddr = datagram->src.addr_list.sin.sin_addr.s_addr;
145da6c28aaSamw 
146da6c28aaSamw 	/*
147da6c28aaSamw 	 * The datagram->src.name is in oem codepage format.
148da6c28aaSamw 	 * Therefore, we need to convert it to unicode and
149da6c28aaSamw 	 * store it in multi-bytes format.
150da6c28aaSamw 	 */
151*bbf6f00cSJordan Brown 	(void) oemtoucs(unicode_src_name, (char *)datagram->src.name,
152*bbf6f00cSJordan Brown 	    SMB_PI_MAX_HOST, OEM_CPG_850);
153*bbf6f00cSJordan Brown 	(void) smb_wcstombs(src_name, unicode_src_name, SMB_PI_MAX_HOST);
154da6c28aaSamw 
155da6c28aaSamw 	(void) trim_whitespace(src_name);
156da6c28aaSamw 
157da6c28aaSamw 	(void) inet_ntop(AF_INET, (const void *)(&src_ipaddr), ipstr,
158da6c28aaSamw 	    sizeof (ipstr));
159da6c28aaSamw 	syslog(LOG_DEBUG, "NetLogonReceive: src=%s [%s], mbx=%s",
160da6c28aaSamw 	    src_name, ipstr, mailbox);
161da6c28aaSamw 
162da6c28aaSamw 	smb_msgbuf_init(&mb, data, datalen, 0);
163da6c28aaSamw 
164da6c28aaSamw 	if (smb_msgbuf_decode(&mb, "w", &opcode) < 0) {
165da6c28aaSamw 		syslog(LOG_ERR, "NetLogonReceive: decode error");
166da6c28aaSamw 		smb_msgbuf_term(&mb);
167da6c28aaSamw 		return;
168da6c28aaSamw 	}
169da6c28aaSamw 
170da6c28aaSamw 	switch (opcode) {
171da6c28aaSamw 	case LOGON_PRIMARY_RESPONSE:
172da6c28aaSamw 		/*
173da6c28aaSamw 		 * Message contains:
174da6c28aaSamw 		 * PDC name (MBS), PDC name (Unicode), Domain name (unicode)
175da6c28aaSamw 		 */
176da6c28aaSamw 		rc = smb_msgbuf_decode(&mb, "sUU", &junk, &primary, &domain);
177da6c28aaSamw 		if (rc < 0) {
178da6c28aaSamw 			syslog(LOG_ERR,
179da6c28aaSamw 			    "NetLogonResponse: opcode %d decode error",
180da6c28aaSamw 			    opcode);
181da6c28aaSamw 			smb_msgbuf_term(&mb);
182da6c28aaSamw 			return;
183da6c28aaSamw 		}
184da6c28aaSamw 		break;
185da6c28aaSamw 
186da6c28aaSamw 	case LOGON_SAM_LOGON_RESPONSE:
187da6c28aaSamw 	case LOGON_SAM_USER_UNKNOWN:
188da6c28aaSamw 		/*
189da6c28aaSamw 		 * Message contains:
190da6c28aaSamw 		 * PDC name, User name, Domain name (all unicode)
191da6c28aaSamw 		 */
192da6c28aaSamw 		rc = smb_msgbuf_decode(&mb, "UUU", &primary, &junk, &domain);
193da6c28aaSamw 		if (rc < 0) {
194da6c28aaSamw 			syslog(LOG_ERR,
195da6c28aaSamw 			    "NetLogonResponse: opcode %d decode error",
196da6c28aaSamw 			    opcode);
197da6c28aaSamw 			smb_msgbuf_term(&mb);
198da6c28aaSamw 			return;
199da6c28aaSamw 		}
200da6c28aaSamw 
201da6c28aaSamw 		/*
202da6c28aaSamw 		 * skip past the "\\" prefix
203da6c28aaSamw 		 */
204da6c28aaSamw 		primary += strspn(primary, "\\");
205da6c28aaSamw 		break;
206da6c28aaSamw 
207da6c28aaSamw 	default:
208da6c28aaSamw 		/*
209da6c28aaSamw 		 * We don't respond to PDC discovery requests.
210da6c28aaSamw 		 */
211da6c28aaSamw 		syslog(LOG_DEBUG, "NetLogonReceive: opcode 0x%04x", opcode);
212da6c28aaSamw 		smb_msgbuf_term(&mb);
213da6c28aaSamw 		return;
214da6c28aaSamw 	}
215da6c28aaSamw 
216a0aa776eSAlan Wright 	if (domain == NULL || primary == NULL) {
217da6c28aaSamw 		syslog(LOG_ERR, "NetLogonResponse: malformed packet");
218da6c28aaSamw 		smb_msgbuf_term(&mb);
219da6c28aaSamw 		return;
220da6c28aaSamw 	}
221da6c28aaSamw 
222a0aa776eSAlan Wright 	syslog(LOG_DEBUG, "DC Offer Domain=%s PDC=%s From=%s",
223da6c28aaSamw 	    domain, primary, src_name);
224da6c28aaSamw 
2258d7e4166Sjose borrego 	(void) mutex_lock(&ntdomain_mtx);
2268d7e4166Sjose borrego 	if (strcasecmp(domain, ntdomain_info.n_domain)) {
227da6c28aaSamw 		syslog(LOG_DEBUG, "NetLogonResponse: other domain "
2288d7e4166Sjose borrego 		    "%s, requested %s", domain, ntdomain_info.n_domain);
229da6c28aaSamw 		smb_msgbuf_term(&mb);
2308d7e4166Sjose borrego 		(void) mutex_unlock(&ntdomain_mtx);
231da6c28aaSamw 		return;
232da6c28aaSamw 	}
2338d7e4166Sjose borrego 	(void) mutex_unlock(&ntdomain_mtx);
234da6c28aaSamw 
235da6c28aaSamw 	for (i = 0; i < sizeof (netlogon_opt)/sizeof (netlogon_opt[0]); ++i) {
236da6c28aaSamw 		if (strcasecmp(netlogon_opt[i].mailslot, mailbox) == 0) {
237da6c28aaSamw 			syslog(LOG_DEBUG, "NetLogonReceive: %s", mailbox);
238da6c28aaSamw 			(*netlogon_opt[i].handler)(primary, src_ipaddr);
239da6c28aaSamw 			smb_msgbuf_term(&mb);
240da6c28aaSamw 			return;
241da6c28aaSamw 		}
242da6c28aaSamw 	}
243da6c28aaSamw 
244da6c28aaSamw 	syslog(LOG_DEBUG, "NetLogonReceive[%s]: unknown mailslot", mailbox);
245da6c28aaSamw 	smb_msgbuf_term(&mb);
246da6c28aaSamw }
247da6c28aaSamw 
248da6c28aaSamw 
249da6c28aaSamw 
250da6c28aaSamw /*
251da6c28aaSamw  * smb_netlogon_query
252da6c28aaSamw  *
253da6c28aaSamw  * Build and send a LOGON_PRIMARY_QUERY to the MAILSLOT_NETLOGON. At some
254da6c28aaSamw  * point we should receive a LOGON_PRIMARY_RESPONSE in the mailslot we
255da6c28aaSamw  * specify in the request.
256da6c28aaSamw  *
257da6c28aaSamw  *  struct NETLOGON_QUERY {
258da6c28aaSamw  *	unsigned short Opcode;		# LOGON_PRIMARY_QUERY
259da6c28aaSamw  *	char ComputerName[];		# ASCII hostname. The response
260da6c28aaSamw  *					# is sent to <ComputerName>(00).
261da6c28aaSamw  *	char MailslotName[];		# MAILSLOT_NETLOGON
262da6c28aaSamw  *	char Pad[];			# Pad to short
263da6c28aaSamw  *	wchar_t ComputerName[]		# UNICODE hostname
264da6c28aaSamw  *	DWORD NT_Version;		# 0x00000001
265da6c28aaSamw  *	WORD LmNTToken;			# 0xffff
266da6c28aaSamw  *	WORD Lm20Token;			# 0xffff
267da6c28aaSamw  *  };
268da6c28aaSamw  */
269da6c28aaSamw static void
270da6c28aaSamw smb_netlogon_query(struct name_entry *server,
271da6c28aaSamw 			char *mailbox,
272da6c28aaSamw 			char *domain)
273da6c28aaSamw {
274da6c28aaSamw 	smb_msgbuf_t mb;
275da6c28aaSamw 	int offset, announce_len, data_length, name_lengths;
276da6c28aaSamw 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
277b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char hostname[NETBIOS_NAME_SZ];
278da6c28aaSamw 
279b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
280da6c28aaSamw 		return;
281da6c28aaSamw 
282da6c28aaSamw 	name_lengths = strlen(mailbox)+1+strlen(hostname)+1;
283da6c28aaSamw 
284da6c28aaSamw 	/*
285da6c28aaSamw 	 * The (name_lengths & 1) part is to word align the name_lengths
286da6c28aaSamw 	 * before the wc equiv strlen and the "+ 2" is to cover the two
287da6c28aaSamw 	 * zero bytes that terminate the wchar string.
288da6c28aaSamw 	 */
289da6c28aaSamw 	data_length = sizeof (short) + name_lengths + (name_lengths & 1) +
290*bbf6f00cSJordan Brown 	    smb_wcequiv_strlen(hostname) + 2 + sizeof (long) + sizeof (short) +
291da6c28aaSamw 	    sizeof (short);
292da6c28aaSamw 
293da6c28aaSamw 	offset = smb_browser_load_transact_header(buffer,
294da6c28aaSamw 	    sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
295da6c28aaSamw 	    MAILSLOT_NETLOGON);
296da6c28aaSamw 
297da6c28aaSamw 	if (offset < 0)
298da6c28aaSamw 		return;
299da6c28aaSamw 
300da6c28aaSamw 	smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
301da6c28aaSamw 
302da6c28aaSamw 	announce_len = smb_msgbuf_encode(&mb, "wssUlww",
303da6c28aaSamw 	    (short)LOGON_PRIMARY_QUERY,
304da6c28aaSamw 	    hostname,
305da6c28aaSamw 	    mailbox,
306da6c28aaSamw 	    hostname,
307da6c28aaSamw 	    0x1,
308da6c28aaSamw 	    0xffff,
309da6c28aaSamw 	    0xffff);
310da6c28aaSamw 
311da6c28aaSamw 	if (announce_len <= 0) {
312da6c28aaSamw 		smb_msgbuf_term(&mb);
313da6c28aaSamw 		syslog(LOG_ERR, "NetLogonQuery: encode error");
314da6c28aaSamw 		return;
315da6c28aaSamw 	}
316da6c28aaSamw 
317da6c28aaSamw 	smb_netlogon_send(server, domain, buffer, offset + announce_len);
318da6c28aaSamw 	smb_msgbuf_term(&mb);
319da6c28aaSamw }
320da6c28aaSamw 
321da6c28aaSamw 
322da6c28aaSamw /*
323da6c28aaSamw  * smb_netlogon_samlogon
324da6c28aaSamw  *
325da6c28aaSamw  * The SamLogon version of the NetLogon request uses the workstation trust
326da6c28aaSamw  * account and, I think, may be a prerequisite to the challenge/response
327da6c28aaSamw  * netr authentication. The trust account username is the hostname with a
328da6c28aaSamw  * $ appended. The mailslot for this request is MAILSLOT_NTLOGON. At some
329da6c28aaSamw  * we should receive a LOGON_SAM_LOGON_RESPONSE in the mailslot we
330da6c28aaSamw  * specify in the request.
331da6c28aaSamw  *
332da6c28aaSamw  * struct NETLOGON_SAM_LOGON {
333da6c28aaSamw  *	unsigned short Opcode;			# LOGON_SAM_LOGON_REQUEST
334da6c28aaSamw  *	unsigned short RequestCount;		# 0
335da6c28aaSamw  *	wchar_t UnicodeComputerName;		# hostname
336da6c28aaSamw  *	wchar_t UnicodeUserName;		# hostname$
337da6c28aaSamw  *	char *MailslotName;			# response mailslot
338da6c28aaSamw  *	DWORD AllowableAccountControlBits;	# 0x80 = WorkstationTrustAccount
339da6c28aaSamw  *	DWORD DomainSidSize;			# domain sid length in bytes
340da6c28aaSamw  *	BYTE *DomainSid;			# domain sid
341da6c28aaSamw  *	uint32_t   NT_Version;		# 0x00000001
342da6c28aaSamw  *	unsigned short  LmNTToken;		# 0xffff
343da6c28aaSamw  *	unsigned short  Lm20Token;		# 0xffff
344da6c28aaSamw  * };
345da6c28aaSamw  */
346da6c28aaSamw static void
347da6c28aaSamw smb_netlogon_samlogon(struct name_entry *server,
348da6c28aaSamw 			char *mailbox,
34929bd2886SAlan Wright 			char *domain,
35029bd2886SAlan Wright 			smb_sid_t *domain_sid)
351da6c28aaSamw {
352da6c28aaSamw 	smb_msgbuf_t mb;
353da6c28aaSamw 	unsigned domain_sid_len;
354da6c28aaSamw 	char *username;
355da6c28aaSamw 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
356da6c28aaSamw 	int offset;
357da6c28aaSamw 	int announce_len;
358da6c28aaSamw 	int data_length;
359da6c28aaSamw 	int name_length;
360b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char hostname[NETBIOS_NAME_SZ];
361da6c28aaSamw 
362da6c28aaSamw 	syslog(LOG_DEBUG, "NetLogonSamLogonReq: %s", domain);
363da6c28aaSamw 
364b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
365da6c28aaSamw 		return;
366da6c28aaSamw 
367da6c28aaSamw 	/*
368da6c28aaSamw 	 * The username will be the trust account name on the PDC.
369da6c28aaSamw 	 */
370da6c28aaSamw 	name_length = strlen(hostname) + 2;
371da6c28aaSamw 	username = alloca(name_length);
372da6c28aaSamw 	(void) snprintf(username, name_length, "%s$", hostname);
373da6c28aaSamw 
37429bd2886SAlan Wright 	domain_sid_len = smb_sid_len(domain_sid);
375da6c28aaSamw 	/*
376da6c28aaSamw 	 * Add 2 to wide-char equivalent strlen to cover the
377da6c28aaSamw 	 * two zero bytes that terminate the wchar string.
378da6c28aaSamw 	 */
379da6c28aaSamw 	name_length = strlen(mailbox)+1;
380da6c28aaSamw 
381da6c28aaSamw 	data_length = sizeof (short)
382da6c28aaSamw 	    + sizeof (short)
383*bbf6f00cSJordan Brown 	    + smb_wcequiv_strlen(hostname) + 2
384*bbf6f00cSJordan Brown 	    + smb_wcequiv_strlen(username) + 2
385da6c28aaSamw 	    + name_length
386da6c28aaSamw 	    + sizeof (long)
387da6c28aaSamw 	    + sizeof (long)
388da6c28aaSamw 	    + domain_sid_len + 3 /* padding */
389da6c28aaSamw 	    + sizeof (long)
390da6c28aaSamw 	    + sizeof (short)
391da6c28aaSamw 	    + sizeof (short);
392da6c28aaSamw 
393da6c28aaSamw 	offset = smb_browser_load_transact_header(buffer,
394da6c28aaSamw 	    sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
395da6c28aaSamw 	    MAILSLOT_NTLOGON);
396da6c28aaSamw 
397da6c28aaSamw 	if (offset < 0) {
398da6c28aaSamw 		syslog(LOG_ERR, "NetLogonSamLogonReq: header error");
399da6c28aaSamw 		return;
400da6c28aaSamw 	}
401da6c28aaSamw 
402da6c28aaSamw 	/*
403da6c28aaSamw 	 * The domain SID is padded with 3 leading zeros.
404da6c28aaSamw 	 */
405da6c28aaSamw 	smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
406da6c28aaSamw 	announce_len = smb_msgbuf_encode(&mb, "wwUUsll3.#clww",
407da6c28aaSamw 	    (short)LOGON_SAM_LOGON_REQUEST,
408da6c28aaSamw 	    0,				/* RequestCount */
409da6c28aaSamw 	    hostname,	/* UnicodeComputerName */
410da6c28aaSamw 	    username,			/* UnicodeUserName */
411da6c28aaSamw 	    mailbox,			/* MailslotName */
412da6c28aaSamw 	    0x00000080,			/* AllowableAccountControlBits */
413da6c28aaSamw 	    domain_sid_len,		/* DomainSidSize */
414da6c28aaSamw 	    domain_sid_len, domain_sid,	/* DomainSid */
415da6c28aaSamw 	    0x00000001,			/* NT_Version */
416da6c28aaSamw 	    0xffff,			/* LmNTToken */
417da6c28aaSamw 	    0xffff);			/* Lm20Token */
418da6c28aaSamw 
419da6c28aaSamw 	if (announce_len <= 0) {
420da6c28aaSamw 		syslog(LOG_ERR, "NetLogonSamLogonReq: encode error");
421da6c28aaSamw 		smb_msgbuf_term(&mb);
422da6c28aaSamw 		return;
423da6c28aaSamw 	}
424da6c28aaSamw 
425da6c28aaSamw 	smb_netlogon_send(server, domain, buffer, offset + announce_len);
426da6c28aaSamw 	smb_msgbuf_term(&mb);
427da6c28aaSamw }
428da6c28aaSamw 
429da6c28aaSamw 
430da6c28aaSamw /*
431da6c28aaSamw  * Send a query for each version of the protocol.
432da6c28aaSamw  */
433da6c28aaSamw static void
434da6c28aaSamw smb_netlogon_send(struct name_entry *name,
435da6c28aaSamw 			char *domain,
436da6c28aaSamw 			unsigned char *buffer,
437da6c28aaSamw 			int count)
438da6c28aaSamw {
439da6c28aaSamw 	static char suffix[] = { 0x1B, 0x1C };
440da6c28aaSamw 	struct name_entry dname;
441da6c28aaSamw 	struct name_entry *dest;
442da6c28aaSamw 	struct name_entry *dest_dup;
443da6c28aaSamw 	int i;
444da6c28aaSamw 
445da6c28aaSamw 	for (i = 0; i < sizeof (suffix)/sizeof (suffix[0]); i++) {
446da6c28aaSamw 		smb_init_name_struct((unsigned char *)domain, suffix[i],
447da6c28aaSamw 		    0, 0, 0, 0, 0, &dname);
448da6c28aaSamw 
449a0aa776eSAlan Wright 		syslog(LOG_DEBUG, "SmbNetlogonSend");
450a0aa776eSAlan Wright 		smb_netbios_name_logf(&dname);
451da6c28aaSamw 		if ((dest = smb_name_find_name(&dname)) != 0) {
452da6c28aaSamw 			dest_dup = smb_netbios_name_dup(dest, 1);
453da6c28aaSamw 			smb_name_unlock_name(dest);
454da6c28aaSamw 			if (dest_dup) {
4558d7e4166Sjose borrego 				(void) smb_netbios_datagram_send(name,
4568d7e4166Sjose borrego 				    dest_dup, buffer, count);
457da6c28aaSamw 				free(dest_dup);
458da6c28aaSamw 			}
459da6c28aaSamw 		} else {
460a0aa776eSAlan Wright 			syslog(LOG_DEBUG,
461a0aa776eSAlan Wright 			    "SmbNetlogonSend: could not find %s<0x%X>",
462da6c28aaSamw 			    domain, suffix[i]);
463da6c28aaSamw 		}
464da6c28aaSamw 	}
465da6c28aaSamw }
466da6c28aaSamw 
467da6c28aaSamw /*
468da6c28aaSamw  * smb_netlogon_rdc_rsp
469da6c28aaSamw  *
470da6c28aaSamw  * This is where we process netlogon responses for the resource domain.
471da6c28aaSamw  * The src_name is the real name of the remote machine.
472da6c28aaSamw  */
473da6c28aaSamw static void
474da6c28aaSamw smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr)
475da6c28aaSamw {
476da6c28aaSamw 	static int initialized = 0;
477da6c28aaSamw 	uint32_t ipaddr;
4787f667e74Sjose borrego 	uint32_t prefer_ipaddr;
4797f667e74Sjose borrego 	char ipstr[INET_ADDRSTRLEN];
4807f667e74Sjose borrego 	char srcip[INET_ADDRSTRLEN];
481da6c28aaSamw 	int rc;
482da6c28aaSamw 
4837f667e74Sjose borrego 	(void) inet_ntop(AF_INET, &src_ipaddr, srcip, INET_ADDRSTRLEN);
484da6c28aaSamw 
4857f667e74Sjose borrego 	rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, INET_ADDRSTRLEN);
486dc20a302Sas200622 	if (rc == SMBD_SMF_OK) {
487dc20a302Sas200622 		rc = inet_pton(AF_INET, ipstr, &prefer_ipaddr);
488da6c28aaSamw 		if (rc == 0)
489da6c28aaSamw 			prefer_ipaddr = 0;
490da6c28aaSamw 
491da6c28aaSamw 		if (!initialized) {
492da6c28aaSamw 			syslog(LOG_DEBUG, "SMB DC Preference: %s", ipstr);
493da6c28aaSamw 			initialized = 1;
494da6c28aaSamw 		}
495da6c28aaSamw 	}
496da6c28aaSamw 
4978d7e4166Sjose borrego 	(void) mutex_lock(&ntdomain_mtx);
498da6c28aaSamw 	syslog(LOG_DEBUG, "DC Offer [%s]: %s [%s]",
4998d7e4166Sjose borrego 	    ntdomain_info.n_domain, src_name, srcip);
500da6c28aaSamw 
5018d7e4166Sjose borrego 	if (ntdomain_info.n_ipaddr != 0) {
5027f667e74Sjose borrego 		if (prefer_ipaddr != 0 &&
5037f667e74Sjose borrego 		    prefer_ipaddr == ntdomain_info.n_ipaddr) {
504da6c28aaSamw 			syslog(LOG_DEBUG, "DC for %s: %s [%s]",
5058d7e4166Sjose borrego 			    ntdomain_info.n_domain, src_name, srcip);
5068d7e4166Sjose borrego 			(void) mutex_unlock(&ntdomain_mtx);
507da6c28aaSamw 			return;
508da6c28aaSamw 		}
509da6c28aaSamw 
5108d7e4166Sjose borrego 		ipaddr = ntdomain_info.n_ipaddr;
511da6c28aaSamw 	} else
512da6c28aaSamw 		ipaddr = 0;
513da6c28aaSamw 
5143db3f65cSamw 	if (smb_better_dc(ipaddr, src_ipaddr) ||
515da6c28aaSamw 	    (prefer_ipaddr != 0 && prefer_ipaddr == src_ipaddr)) {
5168d7e4166Sjose borrego 		/* set nbtd cache */
5178d7e4166Sjose borrego 		(void) strlcpy(ntdomain_info.n_name, src_name,
5188d7e4166Sjose borrego 		    SMB_PI_MAX_DOMAIN);
5198d7e4166Sjose borrego 		ntdomain_info.n_ipaddr = src_ipaddr;
5208d7e4166Sjose borrego 		(void) cond_broadcast(&ntdomain_cv);
521da6c28aaSamw 		syslog(LOG_DEBUG, "DC discovered for %s: %s [%s]",
5228d7e4166Sjose borrego 		    ntdomain_info.n_domain, src_name, srcip);
523da6c28aaSamw 	}
5248d7e4166Sjose borrego 	(void) mutex_unlock(&ntdomain_mtx);
525da6c28aaSamw }
526da6c28aaSamw 
527da6c28aaSamw static int
5283db3f65cSamw smb_better_dc(uint32_t cur_ip, uint32_t new_ip)
529da6c28aaSamw {
5307f667e74Sjose borrego 	smb_inaddr_t ipaddr;
5317f667e74Sjose borrego 
532da6c28aaSamw 	/*
533da6c28aaSamw 	 * If we don't have any current DC,
534da6c28aaSamw 	 * then use the new one of course.
535da6c28aaSamw 	 */
5367f667e74Sjose borrego 
537da6c28aaSamw 	if (cur_ip == 0)
538da6c28aaSamw 		return (1);
539fc724630SAlan Wright 	/*
540fc724630SAlan Wright 	 * see if there is a DC in the
541fc724630SAlan Wright 	 * same subnet
542fc724630SAlan Wright 	 */
543da6c28aaSamw 
5447f667e74Sjose borrego 	ipaddr.a_family = AF_INET;
5457f667e74Sjose borrego 	ipaddr.a_ipv4 = cur_ip;
546fc724630SAlan Wright 	if (smb_nic_is_same_subnet(&ipaddr))
547da6c28aaSamw 		return (0);
5487b59d02dSjb150015 
5497f667e74Sjose borrego 	ipaddr.a_family = AF_INET;
5507f667e74Sjose borrego 	ipaddr.a_ipv4 = new_ip;
551fc724630SAlan Wright 	if (smb_nic_is_same_subnet(&ipaddr))
552da6c28aaSamw 		return (1);
553da6c28aaSamw 	/*
554da6c28aaSamw 	 * Otherwise, just keep the old one.
555da6c28aaSamw 	 */
556da6c28aaSamw 	return (0);
557da6c28aaSamw }
558