xref: /onnv-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c (revision 10966:37e5dcdf36d3)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
228670SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
275331Samw  * This module handles the primary domain controller location protocol.
285331Samw  * The document claims to be version 1.15 of the browsing protocol. It also
295331Samw  * claims to specify the mailslot protocol.
305331Samw  *
315331Samw  * The NETLOGON protocol uses \MAILSLOT\NET mailslots. The protocol
325331Samw  * specification is incomplete, contains errors and is out-of-date but
335331Samw  * it does provide some useful background information. The document
345331Samw  * doesn't mention the NETLOGON_SAMLOGON version of the protocol.
355331Samw  */
365331Samw 
375331Samw #include <stdlib.h>
385331Samw #include <syslog.h>
395331Samw #include <alloca.h>
405331Samw #include <arpa/inet.h>
415331Samw #include <resolv.h>
425331Samw 
435331Samw #include <smbsrv/mailslot.h>
445331Samw #include <smbsrv/libsmbns.h>
455331Samw #include <smbns_browser.h>
465331Samw #include <smbns_netbios.h>
475331Samw 
485331Samw static void smb_netlogon_query(struct name_entry *server, char *mailbox,
495331Samw     char *domain);
505331Samw 
519832Samw@Sun.COM static void smb_netlogon_samlogon(struct name_entry *, char *,
529832Samw@Sun.COM     char *, smb_sid_t *);
535331Samw 
545331Samw static void smb_netlogon_send(struct name_entry *name, char *domain,
555331Samw     unsigned char *buffer, int count);
565331Samw 
575331Samw static void smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr);
587052Samw static int smb_better_dc(uint32_t cur_ip, uint32_t new_ip);
595331Samw 
608334SJose.Borrego@Sun.COM /*
618334SJose.Borrego@Sun.COM  * ntdomain_info
628334SJose.Borrego@Sun.COM  * Temporary. It should be removed once NBTD is integrated.
638334SJose.Borrego@Sun.COM  */
648334SJose.Borrego@Sun.COM extern smb_ntdomain_t ntdomain_info;
658334SJose.Borrego@Sun.COM extern mutex_t ntdomain_mtx;
668334SJose.Borrego@Sun.COM extern cond_t ntdomain_cv;
675331Samw 
685331Samw /*
695331Samw  * smb_netlogon_request
705331Samw  *
715331Samw  * This is the entry point locating the resource domain PDC. A netlogon
725331Samw  * request is sent using the specified protocol on the specified network.
735331Samw  * Note that we need to know the domain SID in order to use the samlogon
745331Samw  * format.
755331Samw  *
765331Samw  * Netlogon responses are received asynchronously and eventually handled
775331Samw  * in smb_netlogon_receive.
785331Samw  */
795331Samw void
smb_netlogon_request(struct name_entry * server,char * domain)809832Samw@Sun.COM smb_netlogon_request(struct name_entry *server, char *domain)
815331Samw {
8210717Samw@Sun.COM 	smb_domain_t di;
839832Samw@Sun.COM 	smb_sid_t *sid = NULL;
849832Samw@Sun.COM 	int protocol = NETLOGON_PROTO_NETLOGON;
855331Samw 
866030Sjb150015 	if (domain == NULL || *domain == '\0')
875331Samw 		return;
885331Samw 
898334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ntdomain_mtx);
908334SJose.Borrego@Sun.COM 	(void) strlcpy(ntdomain_info.n_domain, domain,
918334SJose.Borrego@Sun.COM 	    sizeof (ntdomain_info.n_domain));
928334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ntdomain_mtx);
935331Samw 
949832Samw@Sun.COM 	smb_config_getdomaininfo(di.di_nbname, NULL, di.di_sid, NULL, NULL);
95*10966SJordan.Brown@Sun.COM 	if (smb_strcasecmp(di.di_nbname, domain, 0) == 0) {
969832Samw@Sun.COM 		if ((sid = smb_sid_fromstr(di.di_sid)) != NULL)
979832Samw@Sun.COM 			protocol = NETLOGON_PROTO_SAMLOGON;
989832Samw@Sun.COM 	}
999832Samw@Sun.COM 
1009832Samw@Sun.COM 	if (protocol == NETLOGON_PROTO_SAMLOGON)
1019832Samw@Sun.COM 		smb_netlogon_samlogon(server, MAILSLOT_NETLOGON_SAMLOGON_RDC,
1029832Samw@Sun.COM 		    domain, sid);
1036030Sjb150015 	else
1049832Samw@Sun.COM 		smb_netlogon_query(server, MAILSLOT_NETLOGON_RDC, domain);
1059832Samw@Sun.COM 
1069832Samw@Sun.COM 	smb_sid_free(sid);
1075331Samw }
1085331Samw 
1095331Samw /*
1105331Samw  * smb_netlogon_receive
1115331Samw  *
1125331Samw  * This is where we handle all incoming NetLogon messages. Currently, we
1135331Samw  * ignore requests from anyone else. We are only interested in responses
1145331Samw  * to our own requests. The NetLogonResponse provides the name of the PDC.
1155331Samw  * If we don't already have a controller name, we use the name provided
1165331Samw  * in the message. Otherwise we use the name already in the environment.
1175331Samw  */
1185331Samw void
smb_netlogon_receive(struct datagram * datagram,char * mailbox,unsigned char * data,int datalen)1195331Samw smb_netlogon_receive(struct datagram *datagram,
1205331Samw 				char *mailbox,
1215331Samw 				unsigned char *data,
1225331Samw 				int datalen)
1235331Samw {
1245331Samw 	struct netlogon_opt {
1255331Samw 		char *mailslot;
1265331Samw 		void (*handler)();
1275331Samw 	} netlogon_opt[] = {
1285331Samw 		{ MAILSLOT_NETLOGON_RDC, smb_netlogon_rdc_rsp },
1295331Samw 		{ MAILSLOT_NETLOGON_SAMLOGON_RDC, smb_netlogon_rdc_rsp },
1305331Samw 	};
1315331Samw 
1325331Samw 	smb_msgbuf_t mb;
1335331Samw 	unsigned short opcode;
1345331Samw 	char src_name[SMB_PI_MAX_HOST];
135*10966SJordan.Brown@Sun.COM 	smb_wchar_t unicode_src_name[SMB_PI_MAX_HOST];
1365331Samw 	uint32_t src_ipaddr;
1375331Samw 	char *junk;
1385331Samw 	char *primary;
1395331Samw 	char *domain;
1405331Samw 	int i;
1415331Samw 	char ipstr[16];
1425331Samw 	int rc;
1435331Samw 
1445331Samw 	src_ipaddr = datagram->src.addr_list.sin.sin_addr.s_addr;
1455331Samw 
1465331Samw 	/*
1475331Samw 	 * The datagram->src.name is in oem codepage format.
1485331Samw 	 * Therefore, we need to convert it to unicode and
1495331Samw 	 * store it in multi-bytes format.
1505331Samw 	 */
151*10966SJordan.Brown@Sun.COM 	(void) oemtoucs(unicode_src_name, (char *)datagram->src.name,
152*10966SJordan.Brown@Sun.COM 	    SMB_PI_MAX_HOST, OEM_CPG_850);
153*10966SJordan.Brown@Sun.COM 	(void) smb_wcstombs(src_name, unicode_src_name, SMB_PI_MAX_HOST);
1545331Samw 
1555331Samw 	(void) trim_whitespace(src_name);
1565331Samw 
1575331Samw 	(void) inet_ntop(AF_INET, (const void *)(&src_ipaddr), ipstr,
1585331Samw 	    sizeof (ipstr));
1595331Samw 	syslog(LOG_DEBUG, "NetLogonReceive: src=%s [%s], mbx=%s",
1605331Samw 	    src_name, ipstr, mailbox);
1615331Samw 
1625331Samw 	smb_msgbuf_init(&mb, data, datalen, 0);
1635331Samw 
1645331Samw 	if (smb_msgbuf_decode(&mb, "w", &opcode) < 0) {
1655331Samw 		syslog(LOG_ERR, "NetLogonReceive: decode error");
1665331Samw 		smb_msgbuf_term(&mb);
1675331Samw 		return;
1685331Samw 	}
1695331Samw 
1705331Samw 	switch (opcode) {
1715331Samw 	case LOGON_PRIMARY_RESPONSE:
1725331Samw 		/*
1735331Samw 		 * Message contains:
1745331Samw 		 * PDC name (MBS), PDC name (Unicode), Domain name (unicode)
1755331Samw 		 */
1765331Samw 		rc = smb_msgbuf_decode(&mb, "sUU", &junk, &primary, &domain);
1775331Samw 		if (rc < 0) {
1785331Samw 			syslog(LOG_ERR,
1795331Samw 			    "NetLogonResponse: opcode %d decode error",
1805331Samw 			    opcode);
1815331Samw 			smb_msgbuf_term(&mb);
1825331Samw 			return;
1835331Samw 		}
1845331Samw 		break;
1855331Samw 
1865331Samw 	case LOGON_SAM_LOGON_RESPONSE:
1875331Samw 	case LOGON_SAM_USER_UNKNOWN:
1885331Samw 		/*
1895331Samw 		 * Message contains:
1905331Samw 		 * PDC name, User name, Domain name (all unicode)
1915331Samw 		 */
1925331Samw 		rc = smb_msgbuf_decode(&mb, "UUU", &primary, &junk, &domain);
1935331Samw 		if (rc < 0) {
1945331Samw 			syslog(LOG_ERR,
1955331Samw 			    "NetLogonResponse: opcode %d decode error",
1965331Samw 			    opcode);
1975331Samw 			smb_msgbuf_term(&mb);
1985331Samw 			return;
1995331Samw 		}
2005331Samw 
2015331Samw 		/*
2025331Samw 		 * skip past the "\\" prefix
2035331Samw 		 */
2045331Samw 		primary += strspn(primary, "\\");
2055331Samw 		break;
2065331Samw 
2075331Samw 	default:
2085331Samw 		/*
2095331Samw 		 * We don't respond to PDC discovery requests.
2105331Samw 		 */
2115331Samw 		syslog(LOG_DEBUG, "NetLogonReceive: opcode 0x%04x", opcode);
2125331Samw 		smb_msgbuf_term(&mb);
2135331Samw 		return;
2145331Samw 	}
2155331Samw 
21610717Samw@Sun.COM 	if (domain == NULL || primary == NULL) {
2175331Samw 		syslog(LOG_ERR, "NetLogonResponse: malformed packet");
2185331Samw 		smb_msgbuf_term(&mb);
2195331Samw 		return;
2205331Samw 	}
2215331Samw 
22210717Samw@Sun.COM 	syslog(LOG_DEBUG, "DC Offer Domain=%s PDC=%s From=%s",
2235331Samw 	    domain, primary, src_name);
2245331Samw 
2258334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ntdomain_mtx);
2268334SJose.Borrego@Sun.COM 	if (strcasecmp(domain, ntdomain_info.n_domain)) {
2275331Samw 		syslog(LOG_DEBUG, "NetLogonResponse: other domain "
2288334SJose.Borrego@Sun.COM 		    "%s, requested %s", domain, ntdomain_info.n_domain);
2295331Samw 		smb_msgbuf_term(&mb);
2308334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ntdomain_mtx);
2315331Samw 		return;
2325331Samw 	}
2338334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ntdomain_mtx);
2345331Samw 
2355331Samw 	for (i = 0; i < sizeof (netlogon_opt)/sizeof (netlogon_opt[0]); ++i) {
2365331Samw 		if (strcasecmp(netlogon_opt[i].mailslot, mailbox) == 0) {
2375331Samw 			syslog(LOG_DEBUG, "NetLogonReceive: %s", mailbox);
2385331Samw 			(*netlogon_opt[i].handler)(primary, src_ipaddr);
2395331Samw 			smb_msgbuf_term(&mb);
2405331Samw 			return;
2415331Samw 		}
2425331Samw 	}
2435331Samw 
2445331Samw 	syslog(LOG_DEBUG, "NetLogonReceive[%s]: unknown mailslot", mailbox);
2455331Samw 	smb_msgbuf_term(&mb);
2465331Samw }
2475331Samw 
2485331Samw 
2495331Samw 
2505331Samw /*
2515331Samw  * smb_netlogon_query
2525331Samw  *
2535331Samw  * Build and send a LOGON_PRIMARY_QUERY to the MAILSLOT_NETLOGON. At some
2545331Samw  * point we should receive a LOGON_PRIMARY_RESPONSE in the mailslot we
2555331Samw  * specify in the request.
2565331Samw  *
2575331Samw  *  struct NETLOGON_QUERY {
2585331Samw  *	unsigned short Opcode;		# LOGON_PRIMARY_QUERY
2595331Samw  *	char ComputerName[];		# ASCII hostname. The response
2605331Samw  *					# is sent to <ComputerName>(00).
2615331Samw  *	char MailslotName[];		# MAILSLOT_NETLOGON
2625331Samw  *	char Pad[];			# Pad to short
2635331Samw  *	wchar_t ComputerName[]		# UNICODE hostname
2645331Samw  *	DWORD NT_Version;		# 0x00000001
2655331Samw  *	WORD LmNTToken;			# 0xffff
2665331Samw  *	WORD Lm20Token;			# 0xffff
2675331Samw  *  };
2685331Samw  */
2695331Samw static void
smb_netlogon_query(struct name_entry * server,char * mailbox,char * domain)2705331Samw smb_netlogon_query(struct name_entry *server,
2715331Samw 			char *mailbox,
2725331Samw 			char *domain)
2735331Samw {
2745331Samw 	smb_msgbuf_t mb;
2755331Samw 	int offset, announce_len, data_length, name_lengths;
2765331Samw 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
2777961SNatalie.Li@Sun.COM 	char hostname[NETBIOS_NAME_SZ];
2785331Samw 
2797961SNatalie.Li@Sun.COM 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
2805331Samw 		return;
2815331Samw 
2825331Samw 	name_lengths = strlen(mailbox)+1+strlen(hostname)+1;
2835331Samw 
2845331Samw 	/*
2855331Samw 	 * The (name_lengths & 1) part is to word align the name_lengths
2865331Samw 	 * before the wc equiv strlen and the "+ 2" is to cover the two
2875331Samw 	 * zero bytes that terminate the wchar string.
2885331Samw 	 */
2895331Samw 	data_length = sizeof (short) + name_lengths + (name_lengths & 1) +
290*10966SJordan.Brown@Sun.COM 	    smb_wcequiv_strlen(hostname) + 2 + sizeof (long) + sizeof (short) +
2915331Samw 	    sizeof (short);
2925331Samw 
2935331Samw 	offset = smb_browser_load_transact_header(buffer,
2945331Samw 	    sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
2955331Samw 	    MAILSLOT_NETLOGON);
2965331Samw 
2975331Samw 	if (offset < 0)
2985331Samw 		return;
2995331Samw 
3005331Samw 	smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
3015331Samw 
3025331Samw 	announce_len = smb_msgbuf_encode(&mb, "wssUlww",
3035331Samw 	    (short)LOGON_PRIMARY_QUERY,
3045331Samw 	    hostname,
3055331Samw 	    mailbox,
3065331Samw 	    hostname,
3075331Samw 	    0x1,
3085331Samw 	    0xffff,
3095331Samw 	    0xffff);
3105331Samw 
3115331Samw 	if (announce_len <= 0) {
3125331Samw 		smb_msgbuf_term(&mb);
3135331Samw 		syslog(LOG_ERR, "NetLogonQuery: encode error");
3145331Samw 		return;
3155331Samw 	}
3165331Samw 
3175331Samw 	smb_netlogon_send(server, domain, buffer, offset + announce_len);
3185331Samw 	smb_msgbuf_term(&mb);
3195331Samw }
3205331Samw 
3215331Samw 
3225331Samw /*
3235331Samw  * smb_netlogon_samlogon
3245331Samw  *
3255331Samw  * The SamLogon version of the NetLogon request uses the workstation trust
3265331Samw  * account and, I think, may be a prerequisite to the challenge/response
3275331Samw  * netr authentication. The trust account username is the hostname with a
3285331Samw  * $ appended. The mailslot for this request is MAILSLOT_NTLOGON. At some
3295331Samw  * we should receive a LOGON_SAM_LOGON_RESPONSE in the mailslot we
3305331Samw  * specify in the request.
3315331Samw  *
3325331Samw  * struct NETLOGON_SAM_LOGON {
3335331Samw  *	unsigned short Opcode;			# LOGON_SAM_LOGON_REQUEST
3345331Samw  *	unsigned short RequestCount;		# 0
3355331Samw  *	wchar_t UnicodeComputerName;		# hostname
3365331Samw  *	wchar_t UnicodeUserName;		# hostname$
3375331Samw  *	char *MailslotName;			# response mailslot
3385331Samw  *	DWORD AllowableAccountControlBits;	# 0x80 = WorkstationTrustAccount
3395331Samw  *	DWORD DomainSidSize;			# domain sid length in bytes
3405331Samw  *	BYTE *DomainSid;			# domain sid
3415331Samw  *	uint32_t   NT_Version;		# 0x00000001
3425331Samw  *	unsigned short  LmNTToken;		# 0xffff
3435331Samw  *	unsigned short  Lm20Token;		# 0xffff
3445331Samw  * };
3455331Samw  */
3465331Samw static void
smb_netlogon_samlogon(struct name_entry * server,char * mailbox,char * domain,smb_sid_t * domain_sid)3475331Samw smb_netlogon_samlogon(struct name_entry *server,
3485331Samw 			char *mailbox,
3499832Samw@Sun.COM 			char *domain,
3509832Samw@Sun.COM 			smb_sid_t *domain_sid)
3515331Samw {
3525331Samw 	smb_msgbuf_t mb;
3535331Samw 	unsigned domain_sid_len;
3545331Samw 	char *username;
3555331Samw 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
3565331Samw 	int offset;
3575331Samw 	int announce_len;
3585331Samw 	int data_length;
3595331Samw 	int name_length;
3607961SNatalie.Li@Sun.COM 	char hostname[NETBIOS_NAME_SZ];
3615331Samw 
3625331Samw 	syslog(LOG_DEBUG, "NetLogonSamLogonReq: %s", domain);
3635331Samw 
3647961SNatalie.Li@Sun.COM 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
3655331Samw 		return;
3665331Samw 
3675331Samw 	/*
3685331Samw 	 * The username will be the trust account name on the PDC.
3695331Samw 	 */
3705331Samw 	name_length = strlen(hostname) + 2;
3715331Samw 	username = alloca(name_length);
3725331Samw 	(void) snprintf(username, name_length, "%s$", hostname);
3735331Samw 
3749832Samw@Sun.COM 	domain_sid_len = smb_sid_len(domain_sid);
3755331Samw 	/*
3765331Samw 	 * Add 2 to wide-char equivalent strlen to cover the
3775331Samw 	 * two zero bytes that terminate the wchar string.
3785331Samw 	 */
3795331Samw 	name_length = strlen(mailbox)+1;
3805331Samw 
3815331Samw 	data_length = sizeof (short)
3825331Samw 	    + sizeof (short)
383*10966SJordan.Brown@Sun.COM 	    + smb_wcequiv_strlen(hostname) + 2
384*10966SJordan.Brown@Sun.COM 	    + smb_wcequiv_strlen(username) + 2
3855331Samw 	    + name_length
3865331Samw 	    + sizeof (long)
3875331Samw 	    + sizeof (long)
3885331Samw 	    + domain_sid_len + 3 /* padding */
3895331Samw 	    + sizeof (long)
3905331Samw 	    + sizeof (short)
3915331Samw 	    + sizeof (short);
3925331Samw 
3935331Samw 	offset = smb_browser_load_transact_header(buffer,
3945331Samw 	    sizeof (buffer), data_length, ONE_WAY_TRANSACTION,
3955331Samw 	    MAILSLOT_NTLOGON);
3965331Samw 
3975331Samw 	if (offset < 0) {
3985331Samw 		syslog(LOG_ERR, "NetLogonSamLogonReq: header error");
3995331Samw 		return;
4005331Samw 	}
4015331Samw 
4025331Samw 	/*
4035331Samw 	 * The domain SID is padded with 3 leading zeros.
4045331Samw 	 */
4055331Samw 	smb_msgbuf_init(&mb, buffer + offset, sizeof (buffer) - offset, 0);
4065331Samw 	announce_len = smb_msgbuf_encode(&mb, "wwUUsll3.#clww",
4075331Samw 	    (short)LOGON_SAM_LOGON_REQUEST,
4085331Samw 	    0,				/* RequestCount */
4095331Samw 	    hostname,	/* UnicodeComputerName */
4105331Samw 	    username,			/* UnicodeUserName */
4115331Samw 	    mailbox,			/* MailslotName */
4125331Samw 	    0x00000080,			/* AllowableAccountControlBits */
4135331Samw 	    domain_sid_len,		/* DomainSidSize */
4145331Samw 	    domain_sid_len, domain_sid,	/* DomainSid */
4155331Samw 	    0x00000001,			/* NT_Version */
4165331Samw 	    0xffff,			/* LmNTToken */
4175331Samw 	    0xffff);			/* Lm20Token */
4185331Samw 
4195331Samw 	if (announce_len <= 0) {
4205331Samw 		syslog(LOG_ERR, "NetLogonSamLogonReq: encode error");
4215331Samw 		smb_msgbuf_term(&mb);
4225331Samw 		return;
4235331Samw 	}
4245331Samw 
4255331Samw 	smb_netlogon_send(server, domain, buffer, offset + announce_len);
4265331Samw 	smb_msgbuf_term(&mb);
4275331Samw }
4285331Samw 
4295331Samw 
4305331Samw /*
4315331Samw  * Send a query for each version of the protocol.
4325331Samw  */
4335331Samw static void
smb_netlogon_send(struct name_entry * name,char * domain,unsigned char * buffer,int count)4345331Samw smb_netlogon_send(struct name_entry *name,
4355331Samw 			char *domain,
4365331Samw 			unsigned char *buffer,
4375331Samw 			int count)
4385331Samw {
4395331Samw 	static char suffix[] = { 0x1B, 0x1C };
4405331Samw 	struct name_entry dname;
4415331Samw 	struct name_entry *dest;
4425331Samw 	struct name_entry *dest_dup;
4435331Samw 	int i;
4445331Samw 
4455331Samw 	for (i = 0; i < sizeof (suffix)/sizeof (suffix[0]); i++) {
4465331Samw 		smb_init_name_struct((unsigned char *)domain, suffix[i],
4475331Samw 		    0, 0, 0, 0, 0, &dname);
4485331Samw 
44910717Samw@Sun.COM 		syslog(LOG_DEBUG, "SmbNetlogonSend");
45010717Samw@Sun.COM 		smb_netbios_name_logf(&dname);
4515331Samw 		if ((dest = smb_name_find_name(&dname)) != 0) {
4525331Samw 			dest_dup = smb_netbios_name_dup(dest, 1);
4535331Samw 			smb_name_unlock_name(dest);
4545331Samw 			if (dest_dup) {
4558334SJose.Borrego@Sun.COM 				(void) smb_netbios_datagram_send(name,
4568334SJose.Borrego@Sun.COM 				    dest_dup, buffer, count);
4575331Samw 				free(dest_dup);
4585331Samw 			}
4595331Samw 		} else {
46010717Samw@Sun.COM 			syslog(LOG_DEBUG,
46110717Samw@Sun.COM 			    "SmbNetlogonSend: could not find %s<0x%X>",
4625331Samw 			    domain, suffix[i]);
4635331Samw 		}
4645331Samw 	}
4655331Samw }
4665331Samw 
4675331Samw /*
4685331Samw  * smb_netlogon_rdc_rsp
4695331Samw  *
4705331Samw  * This is where we process netlogon responses for the resource domain.
4715331Samw  * The src_name is the real name of the remote machine.
4725331Samw  */
4735331Samw static void
smb_netlogon_rdc_rsp(char * src_name,uint32_t src_ipaddr)4745331Samw smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr)
4755331Samw {
4765331Samw 	static int initialized = 0;
4775331Samw 	uint32_t ipaddr;
4788670SJose.Borrego@Sun.COM 	uint32_t prefer_ipaddr;
4798670SJose.Borrego@Sun.COM 	char ipstr[INET_ADDRSTRLEN];
4808670SJose.Borrego@Sun.COM 	char srcip[INET_ADDRSTRLEN];
4815331Samw 	int rc;
4825331Samw 
4838670SJose.Borrego@Sun.COM 	(void) inet_ntop(AF_INET, &src_ipaddr, srcip, INET_ADDRSTRLEN);
4845331Samw 
4858670SJose.Borrego@Sun.COM 	rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, INET_ADDRSTRLEN);
4865772Sas200622 	if (rc == SMBD_SMF_OK) {
4875772Sas200622 		rc = inet_pton(AF_INET, ipstr, &prefer_ipaddr);
4885331Samw 		if (rc == 0)
4895331Samw 			prefer_ipaddr = 0;
4905331Samw 
4915331Samw 		if (!initialized) {
4925331Samw 			syslog(LOG_DEBUG, "SMB DC Preference: %s", ipstr);
4935331Samw 			initialized = 1;
4945331Samw 		}
4955331Samw 	}
4965331Samw 
4978334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ntdomain_mtx);
4985331Samw 	syslog(LOG_DEBUG, "DC Offer [%s]: %s [%s]",
4998334SJose.Borrego@Sun.COM 	    ntdomain_info.n_domain, src_name, srcip);
5005331Samw 
5018334SJose.Borrego@Sun.COM 	if (ntdomain_info.n_ipaddr != 0) {
5028670SJose.Borrego@Sun.COM 		if (prefer_ipaddr != 0 &&
5038670SJose.Borrego@Sun.COM 		    prefer_ipaddr == ntdomain_info.n_ipaddr) {
5045331Samw 			syslog(LOG_DEBUG, "DC for %s: %s [%s]",
5058334SJose.Borrego@Sun.COM 			    ntdomain_info.n_domain, src_name, srcip);
5068334SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ntdomain_mtx);
5075331Samw 			return;
5085331Samw 		}
5095331Samw 
5108334SJose.Borrego@Sun.COM 		ipaddr = ntdomain_info.n_ipaddr;
5115331Samw 	} else
5125331Samw 		ipaddr = 0;
5135331Samw 
5147052Samw 	if (smb_better_dc(ipaddr, src_ipaddr) ||
5155331Samw 	    (prefer_ipaddr != 0 && prefer_ipaddr == src_ipaddr)) {
5168334SJose.Borrego@Sun.COM 		/* set nbtd cache */
5178334SJose.Borrego@Sun.COM 		(void) strlcpy(ntdomain_info.n_name, src_name,
5188334SJose.Borrego@Sun.COM 		    SMB_PI_MAX_DOMAIN);
5198334SJose.Borrego@Sun.COM 		ntdomain_info.n_ipaddr = src_ipaddr;
5208334SJose.Borrego@Sun.COM 		(void) cond_broadcast(&ntdomain_cv);
5215331Samw 		syslog(LOG_DEBUG, "DC discovered for %s: %s [%s]",
5228334SJose.Borrego@Sun.COM 		    ntdomain_info.n_domain, src_name, srcip);
5235331Samw 	}
5248334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ntdomain_mtx);
5255331Samw }
5265331Samw 
5275331Samw static int
smb_better_dc(uint32_t cur_ip,uint32_t new_ip)5287052Samw smb_better_dc(uint32_t cur_ip, uint32_t new_ip)
5295331Samw {
5308670SJose.Borrego@Sun.COM 	smb_inaddr_t ipaddr;
5318670SJose.Borrego@Sun.COM 
5325331Samw 	/*
5335331Samw 	 * If we don't have any current DC,
5345331Samw 	 * then use the new one of course.
5355331Samw 	 */
5368670SJose.Borrego@Sun.COM 
5375331Samw 	if (cur_ip == 0)
5385331Samw 		return (1);
5399021Samw@Sun.COM 	/*
5409021Samw@Sun.COM 	 * see if there is a DC in the
5419021Samw@Sun.COM 	 * same subnet
5429021Samw@Sun.COM 	 */
5435331Samw 
5448670SJose.Borrego@Sun.COM 	ipaddr.a_family = AF_INET;
5458670SJose.Borrego@Sun.COM 	ipaddr.a_ipv4 = cur_ip;
5469021Samw@Sun.COM 	if (smb_nic_is_same_subnet(&ipaddr))
5475331Samw 		return (0);
5486030Sjb150015 
5498670SJose.Borrego@Sun.COM 	ipaddr.a_family = AF_INET;
5508670SJose.Borrego@Sun.COM 	ipaddr.a_ipv4 = new_ip;
5519021Samw@Sun.COM 	if (smb_nic_is_same_subnet(&ipaddr))
5525331Samw 		return (1);
5535331Samw 	/*
5545331Samw 	 * Otherwise, just keep the old one.
5555331Samw 	 */
5565331Samw 	return (0);
5575331Samw }
558