1da6c28aamw/*
2da6c28aamw * CDDL HEADER START
3da6c28aamw *
4da6c28aamw * The contents of this file are subject to the terms of the
5da6c28aamw * Common Development and Distribution License (the "License").
6da6c28aamw * You may not use this file except in compliance with the License.
7da6c28aamw *
8da6c28aamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aamw * or http://www.opensolaris.org/os/licensing.
10da6c28aamw * See the License for the specific language governing permissions
11da6c28aamw * and limitations under the License.
12da6c28aamw *
13da6c28aamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aamw *
19da6c28aamw * CDDL HEADER END
20da6c28aamw */
21da6c28aamw/*
229fb67eaafshin salek ardakani - Sun Microsystems - Irvine United States * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aamw * Use is subject to license terms.
2448bbca8Daniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
25da6c28aamw */
26da6c28aamw
27da6c28aamw/*
28a0aa776Alan Wright * NetBIOS name resolution node types.
29da6c28aamw *
30a0aa776Alan Wright * A B-node (broadcast node) uses broadcasts for name registration
31a0aa776Alan Wright * and resolution.  Routers typically do not forward broadcasts and
32a0aa776Alan Wright * only computers on the local subnet will respond.
33da6c28aamw *
34a0aa776Alan Wright * A P-node (peer-to-peer node) uses a NetBIOS name server (WINS)
35a0aa776Alan Wright * to resolve NetBIOS names, which allows it to work across routers.
36a0aa776Alan Wright * In order to function in a P-node environment, all computers must
37a0aa776Alan Wright * be configured to use the NetBIOS name server because P-nodes do
38a0aa776Alan Wright * not broadcast on the network.
39da6c28aamw *
40a0aa776Alan Wright * A mixed node (M-node) behaves as a B-node by default.  If it cannot
41a0aa776Alan Wright * resolve the name via broadcast then it tries a NetBIOS name server
42a0aa776Alan Wright * lookup (P-node).
43da6c28aamw *
44a0aa776Alan Wright * A hybrid node (H-node) behaves as a P-node by default.  If it cannot
45a0aa776Alan Wright * resolve the name using a NetBIOS name server then it resorts to
46a0aa776Alan Wright * broadcasts (B-node).
47da6c28aamw *
48a0aa776Alan Wright * NetBIOS Name Service Protocols
49da6c28aamw *
50a0aa776Alan Wright * A REQUEST packet is always sent to the well known UDP port 137.
51a0aa776Alan Wright * The destination address is normally either the IP broadcast address or
52a0aa776Alan Wright * the address of the NAME - the address of the NAME server it set up at
53a0aa776Alan Wright * initialization time.  In rare cases, a request packet will be sent to
54a0aa776Alan Wright * an end node, e.g.  a NAME QUERY REQUEST sent to "challenge" a node.
55da6c28aamw *
56a0aa776Alan Wright * A RESPONSE packet is always sent to the source UDP port and source IP
57a0aa776Alan Wright * address of the request packet.
58da6c28aamw *
59a0aa776Alan Wright * A DEMAND packet must always be sent to the well known UDP port 137.
60a0aa776Alan Wright * There is no restriction on the target IP address.
61da6c28aamw *
62a0aa776Alan Wright * A transaction ID is a value composed from the requestor's IP address and
63a0aa776Alan Wright * a unique 16 bit value generated by the originator of the transaction.
64da6c28aamw */
65da6c28aamw
66da6c28aamw#include <unistd.h>
67da6c28aamw#include <syslog.h>
68da6c28aamw#include <stdlib.h>
69da6c28aamw#include <synch.h>
70da6c28aamw#include <errno.h>
71da6c28aamw#include <netdb.h>
72da6c28aamw#include <sys/socket.h>
73da6c28aamw#include <sys/sockio.h>
74da6c28aamw#include <arpa/inet.h>
75da6c28aamw#include <net/if_arp.h>
76da6c28aamw
77da6c28aamw#include <smbsrv/libsmbns.h>
78da6c28aamw#include <smbns_netbios.h>
79da6c28aamw
80a0aa776Alan Wright/*
81a0aa776Alan Wright * RFC 1002 4.2.1.1.  HEADER
82a0aa776Alan Wright */
83a0aa776Alan Wright#define	QUESTION_TYPE_NETBIOS_GENERAL	0x20
84a0aa776Alan Wright#define	QUESTION_TYPE_NETBIOS_STATUS	0x21
85a0aa776Alan Wright
86a0aa776Alan Wright#define	QUESTION_CLASS_INTERNET		0x0001
87da6c28aamw
88a0aa776Alan Wright/*
89a0aa776Alan Wright * RFC 1002 4.2.1.3.  RESOURCE RECORD
90a0aa776Alan Wright */
91a0aa776Alan Wright#define	RR_TYPE_IP_ADDRESS_RESOURCE	0x0001
92a0aa776Alan Wright#define	RR_TYPE_NAME_SERVER_RESOURCE	0x0002
93a0aa776Alan Wright#define	RR_TYPE_NULL_RESOURCE		0x000A
94a0aa776Alan Wright#define	RR_TYPE_NETBIOS_RESOURCE	0x0020
95a0aa776Alan Wright#define	RR_TYPE_NETBIOS_STATUS		0x0021
96a0aa776Alan Wright
97a0aa776Alan Wright/*
98a0aa776Alan Wright *
99a0aa776Alan Wright * RESOURCE RECORD RR_CLASS field definitions
100a0aa776Alan Wright */
101a0aa776Alan Wright#define	RR_CLASS_INTERNET_CLASS		0x0001
102a0aa776Alan Wright
103a0aa776Alan Wright/*
104a0aa776Alan Wright * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of NB.
105a0aa776Alan Wright */
106a0aa776Alan Wright#define	RR_FLAGS_NB_ONT_MASK		0x6000
107a0aa776Alan Wright#define	RR_FLAGS_NB_ONT_B_NODE		0x0000
108a0aa776Alan Wright#define	RR_FLAGS_NB_ONT_P_NODE		0x2000
109a0aa776Alan Wright#define	RR_FLAGS_NB_ONT_M_NODE		0x4000
110a0aa776Alan Wright#define	RR_FLAGS_NB_ONT_RESERVED	0x6000
111a0aa776Alan Wright#define	RR_FLAGS_NB_GROUP_NAME		0x8000
112a0aa776Alan Wright
113a0aa776Alan Wright#define	NAME_FLAGS_PERMANENT_NAME	0x0200
114a0aa776Alan Wright#define	NAME_FLAGS_ACTIVE_NAME		0x0400
115a0aa776Alan Wright#define	NAME_FLAGS_CONFLICT		0x0800
116a0aa776Alan Wright#define	NAME_FLAGS_DEREGISTER		0x1000
117a0aa776Alan Wright#define	NAME_FLAGS_ONT_MASK		0x6000
118a0aa776Alan Wright#define	NAME_FLAGS_ONT_B_NODE		0x0000
119a0aa776Alan Wright#define	NAME_FLAGS_ONT_P_NODE		0x2000
120a0aa776Alan Wright#define	NAME_FLAGS_ONT_M_NODE		0x4000
121a0aa776Alan Wright#define	NAME_FLAGS_ONT_RESERVED		0x6000
122a0aa776Alan Wright#define	NAME_FLAGS_GROUP_NAME		0x8000
123a0aa776Alan Wright
124a0aa776Alan Wright#define	MAX_NETBIOS_REPLY_DATA_SIZE	500
125a0aa776Alan Wright
126a0aa776Alan Wright#define	NAME_HEADER_SIZE		12
127da6c28aamw
128a0aa776Alan Wrighttypedef struct nbt_name_reply {
129a0aa776Alan Wright	struct nbt_name_reply	*forw;
130a0aa776Alan Wright	struct nbt_name_reply	*back;
131a0aa776Alan Wright	struct name_packet	*packet;
132a0aa776Alan Wright	addr_entry_t		*addr;
133a0aa776Alan Wright	uint16_t		name_trn_id;
134a0aa776Alan Wright	boolean_t		reply_ready;
135a0aa776Alan Wright} nbt_name_reply_t;
136a0aa776Alan Wright
137a0aa776Alan Wrightstatic nbt_name_reply_t reply_queue;
138da6c28aamwstatic mutex_t rq_mtx;
139a0aa776Alan Wrightstatic cond_t rq_cv;
140da6c28aamw
141a0aa776Alan Wrightstatic mutex_t nbt_name_config_mtx;
142da6c28aamw
143da6c28aamwstatic name_queue_t delete_queue;
144da6c28aamwstatic name_queue_t refresh_queue;
145da6c28aamw
146da6c28aamwstatic int name_sock = 0;
147da6c28aamw
148da6c28aamwstatic int bcast_num = 0;
149da6c28aamwstatic int nbns_num = 0;
150a0aa776Alan Wrightstatic addr_entry_t smb_bcast_list[SMB_PI_MAX_NETWORKS];
151a0aa776Alan Wrightstatic addr_entry_t smb_nbns[SMB_PI_MAX_WINS];
152da6c28aamw
153a0aa776Alan Wrightstatic int smb_netbios_process_response(uint16_t, addr_entry_t *,
154da6c28aamw    struct name_packet *, uint32_t);
155da6c28aamw
156a0aa776Alan Wrightstatic int smb_send_name_service_packet(addr_entry_t *addr,
157da6c28aamw    struct name_packet *packet);
158da6c28aamw
159a0aa776Alan Wright/*
160a0aa776Alan Wright * Allocate a transaction id.
161a0aa776Alan Wright */
162a0aa776Alan Wrightstatic uint16_t
163a0aa776Alan Wrightsmb_netbios_name_trn_id(void)
164a0aa776Alan Wright{
165a0aa776Alan Wright	static uint16_t trn_id;
166a0aa776Alan Wright	static mutex_t trn_id_mtx;
167a0aa776Alan Wright
168a0aa776Alan Wright	(void) mutex_lock(&trn_id_mtx);
169a0aa776Alan Wright
170a0aa776Alan Wright	do {
171a0aa776Alan Wright		++trn_id;
172a0aa776Alan Wright	} while (trn_id == 0 || trn_id == (uint16_t)-1);
173a0aa776Alan Wright
174a0aa776Alan Wright	(void) mutex_unlock(&trn_id_mtx);
175a0aa776Alan Wright	return (trn_id);
176a0aa776Alan Wright}
177a0aa776Alan Wright
178da6c28aamwstatic int
179a0aa776Alan Wrightsmb_end_node_challenge(nbt_name_reply_t *reply_info)
180da6c28aamw{
181da6c28aamw	int			rc;
182da6c28aamw	uint32_t		retry;
183a0aa776Alan Wright	uint16_t		tid;
184da6c28aamw	struct resource_record	*answer;
185da6c28aamw	struct name_question	question;
186a0aa776Alan Wright	addr_entry_t		*addr;
187da6c28aamw	struct name_entry 	*destination;
188da6c28aamw	struct name_packet	packet;
189da6c28aamw	struct timespec 	st;
190da6c28aamw
191da6c28aamw	/*
192da6c28aamw	 * The response packet has in it the address of the presumed owner
193da6c28aamw	 * of the name.  Challenge that owner.  If owner either does not
19448bbca8Daniel Hoffman	 * respond or indicates that they no longer own the name, claim the
195da6c28aamw	 * name.  Otherwise, the name cannot be claimed.
196da6c28aamw	 */
197da6c28aamw
198da6c28aamw	if ((answer = reply_info->packet->answer) == 0)
199da6c28aamw		return (-1);
200da6c28aamw
201da6c28aamw	destination = answer->name;
202da6c28aamw	question.name = answer->name;
203da6c28aamw
204da6c28aamw	packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
205da6c28aamw	packet.qdcount = 1;	/* question entries */
206da6c28aamw	packet.question = &question;
207da6c28aamw	packet.ancount = 0;	/* answer recs */
208da6c28aamw	packet.answer = NULL;
209da6c28aamw	packet.nscount = 0;	/* authority recs */
210da6c28aamw	packet.authority = NULL;
211da6c28aamw	packet.arcount = 0;	/* additional recs */
212da6c28aamw	packet.additional = NULL;
213da6c28aamw
214da6c28aamw	addr = &destination->addr_list;
215da6c28aamw	for (retry = 0; retry < UCAST_REQ_RETRY_COUNT; retry++) {
216a0aa776Alan Wright		tid = smb_netbios_name_trn_id();
217da6c28aamw		packet.name_trn_id = tid;
218da6c28aamw		if (smb_send_name_service_packet(addr, &packet) >= 0) {
219da6c28aamw			if ((rc = smb_netbios_process_response(tid, addr,
220da6c28aamw			    &packet, UCAST_REQ_RETRY_TIMEOUT)) != 0)
221da6c28aamw				return (rc);
222da6c28aamw		}
223da6c28aamw		st.tv_sec = 0;
224da6c28aamw		st.tv_nsec = (UCAST_REQ_RETRY_TIMEOUT * 1000000);
225da6c28aamw		(void) nanosleep(&st, 0);
226da6c28aamw	}
227da6c28aamw	/* No reply */
228da6c28aamw	return (0);
229da6c28aamw}
230da6c28aamw
231a0aa776Alan Wrightstatic nbt_name_reply_t *
232a0aa776Alan Wrightsmb_name_get_reply(uint16_t tid, uint32_t timeout)
233da6c28aamw{
234a0aa776Alan Wright	uint16_t		info;
235da6c28aamw	struct resource_record	*answer;
236a0aa776Alan Wright	nbt_name_reply_t 	*reply;
237da6c28aamw	uint32_t 		wait_time, to_save; /* in millisecond */
238da6c28aamw	struct timeval 		wt;
239da6c28aamw	timestruc_t 		to;
240da6c28aamw
241da6c28aamw	to_save = timeout;
242a0aa776Alan Wright	reply = malloc(sizeof (nbt_name_reply_t));
243a0aa776Alan Wright	if (reply != NULL) {
244a0aa776Alan Wright		reply->reply_ready = B_FALSE;
245da6c28aamw		reply->name_trn_id = tid;
246da6c28aamw		(void) mutex_lock(&rq_mtx);
247da6c28aamw		QUEUE_INSERT_TAIL(&reply_queue, reply);
248da6c28aamw		(void) mutex_unlock(&rq_mtx);
249da6c28aamw
250da6c28aamw		for (;;) {
251