/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This module handles the primary domain controller location protocol.
* The document claims to be version 1.15 of the browsing protocol. It also
* claims to specify the mailslot protocol.
*
* The NETLOGON protocol uses \MAILSLOT\NET mailslots. The protocol
* specification is incomplete, contains errors and is out-of-date but
* it does provide some useful background information. The document
* doesn't mention the NETLOGON_SAMLOGON version of the protocol.
*/
#include <stdlib.h>
#include <syslog.h>
#include <alloca.h>
#include <resolv.h>
#include <smbsrv/mailslot.h>
#include <smbsrv/libsmbns.h>
#include <smbns_browser.h>
#include <smbns_netbios.h>
char *domain);
static void smb_netlogon_samlogon(struct name_entry *, char *,
char *, smb_sid_t *);
/*
* ntdomain_info
* Temporary. It should be removed once NBTD is integrated.
*/
extern smb_ntdomain_t ntdomain_info;
extern mutex_t ntdomain_mtx;
extern cond_t ntdomain_cv;
/*
* smb_netlogon_request
*
* This is the entry point locating the resource domain PDC. A netlogon
* request is sent using the specified protocol on the specified network.
* Note that we need to know the domain SID in order to use the samlogon
* format.
*
* Netlogon responses are received asynchronously and eventually handled
* in smb_netlogon_receive.
*/
void
{
return;
(void) mutex_lock(&ntdomain_mtx);
sizeof (ntdomain_info.n_domain));
(void) mutex_unlock(&ntdomain_mtx);
}
if (protocol == NETLOGON_PROTO_SAMLOGON)
else
}
/*
* smb_netlogon_receive
*
* This is where we handle all incoming NetLogon messages. Currently, we
* ignore requests from anyone else. We are only interested in responses
* to our own requests. The NetLogonResponse provides the name of the PDC.
* If we don't already have a controller name, we use the name provided
* in the message. Otherwise we use the name already in the environment.
*/
void
char *mailbox,
unsigned char *data,
int datalen)
{
struct netlogon_opt {
char *mailslot;
void (*handler)();
} netlogon_opt[] = {
};
unsigned short opcode;
char *junk;
char *primary;
char *domain;
int i;
int rc;
/*
* The datagram->src.name is in oem codepage format.
* Therefore, we need to convert it to unicode and
* store it in multi-bytes format.
*/
(void) trim_whitespace(src_name);
sizeof (ipstr));
return;
}
switch (opcode) {
case LOGON_PRIMARY_RESPONSE:
/*
* Message contains:
* PDC name (MBS), PDC name (Unicode), Domain name (unicode)
*/
if (rc < 0) {
"NetLogonResponse: opcode %d decode error",
opcode);
return;
}
break;
case LOGON_SAM_LOGON_RESPONSE:
case LOGON_SAM_USER_UNKNOWN:
/*
* Message contains:
* PDC name, User name, Domain name (all unicode)
*/
if (rc < 0) {
"NetLogonResponse: opcode %d decode error",
opcode);
return;
}
/*
* skip past the "\\" prefix
*/
break;
default:
/*
* We don't respond to PDC discovery requests.
*/
return;
}
return;
}
(void) mutex_lock(&ntdomain_mtx);
(void) mutex_unlock(&ntdomain_mtx);
return;
}
(void) mutex_unlock(&ntdomain_mtx);
for (i = 0; i < sizeof (netlogon_opt)/sizeof (netlogon_opt[0]); ++i) {
return;
}
}
}
/*
* smb_netlogon_query
*
* Build and send a LOGON_PRIMARY_QUERY to the MAILSLOT_NETLOGON. At some
* point we should receive a LOGON_PRIMARY_RESPONSE in the mailslot we
* specify in the request.
*
* struct NETLOGON_QUERY {
* unsigned short Opcode; # LOGON_PRIMARY_QUERY
* char ComputerName[]; # ASCII hostname. The response
* # is sent to <ComputerName>(00).
* char MailslotName[]; # MAILSLOT_NETLOGON
* char Pad[]; # Pad to short
* wchar_t ComputerName[] # UNICODE hostname
* DWORD NT_Version; # 0x00000001
* WORD LmNTToken; # 0xffff
* WORD Lm20Token; # 0xffff
* };
*/
static void
char *mailbox,
char *domain)
{
return;
/*
* The (name_lengths & 1) part is to word align the name_lengths
* before the wc equiv strlen and the "+ 2" is to cover the two
* zero bytes that terminate the wchar string.
*/
sizeof (short);
if (offset < 0)
return;
(short)LOGON_PRIMARY_QUERY,
0x1,
0xffff,
0xffff);
if (announce_len <= 0) {
return;
}
}
/*
* smb_netlogon_samlogon
*
* The SamLogon version of the NetLogon request uses the workstation trust
* netr authentication. The trust account username is the hostname with a
* $ appended. The mailslot for this request is MAILSLOT_NTLOGON. At some
* we should receive a LOGON_SAM_LOGON_RESPONSE in the mailslot we
* specify in the request.
*
* struct NETLOGON_SAM_LOGON {
* unsigned short Opcode; # LOGON_SAM_LOGON_REQUEST
* unsigned short RequestCount; # 0
* wchar_t UnicodeComputerName; # hostname
* wchar_t UnicodeUserName; # hostname$
* char *MailslotName; # response mailslot
* DWORD AllowableAccountControlBits; # 0x80 = WorkstationTrustAccount
* DWORD DomainSidSize; # domain sid length in bytes
* BYTE *DomainSid; # domain sid
* uint32_t NT_Version; # 0x00000001
* unsigned short LmNTToken; # 0xffff
* unsigned short Lm20Token; # 0xffff
* };
*/
static void
char *mailbox,
char *domain,
{
unsigned domain_sid_len;
char *username;
int offset;
int announce_len;
int data_length;
int name_length;
return;
/*
* The username will be the trust account name on the PDC.
*/
/*
* Add 2 to wide-char equivalent strlen to cover the
* two zero bytes that terminate the wchar string.
*/
data_length = sizeof (short)
+ sizeof (short)
+ sizeof (long)
+ sizeof (long)
+ sizeof (long)
+ sizeof (short)
+ sizeof (short);
if (offset < 0) {
return;
}
/*
* The domain SID is padded with 3 leading zeros.
*/
(short)LOGON_SAM_LOGON_REQUEST,
0, /* RequestCount */
hostname, /* UnicodeComputerName */
username, /* UnicodeUserName */
mailbox, /* MailslotName */
0x00000080, /* AllowableAccountControlBits */
domain_sid_len, /* DomainSidSize */
0x00000001, /* NT_Version */
0xffff, /* LmNTToken */
0xffff); /* Lm20Token */
if (announce_len <= 0) {
return;
}
}
/*
* Send a query for each version of the protocol.
*/
static void
char *domain,
unsigned char *buffer,
int count)
{
int i;
0, 0, 0, 0, 0, &dname);
if (dest_dup) {
(void) smb_netbios_datagram_send(name,
}
} else {
"SmbNetlogonSend: could not find %s<0x%X>",
}
}
}
/*
* smb_netlogon_rdc_rsp
*
* This is where we process netlogon responses for the resource domain.
* The src_name is the real name of the remote machine.
*/
static void
{
static int initialized = 0;
int rc;
if (rc == SMBD_SMF_OK) {
if (rc == 0)
prefer_ipaddr = 0;
if (!initialized) {
initialized = 1;
}
}
(void) mutex_lock(&ntdomain_mtx);
if (ntdomain_info.n_ipaddr != 0) {
if (prefer_ipaddr != 0 &&
(void) mutex_unlock(&ntdomain_mtx);
return;
}
} else
ipaddr = 0;
/* set nbtd cache */
(void) cond_broadcast(&ntdomain_cv);
}
(void) mutex_unlock(&ntdomain_mtx);
}
static int
{
/*
* If we don't have any current DC,
* then use the new one of course.
*/
if (cur_ip == 0)
return (1);
/*
* see if there is a DC in the
* same subnet
*/
if (smb_nic_is_same_subnet(&ipaddr))
return (0);
if (smb_nic_is_same_subnet(&ipaddr))
return (1);
/*
* Otherwise, just keep the old one.
*/
return (0);
}