xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1*da6c28aaSamw /*
2*da6c28aaSamw  * CDDL HEADER START
3*da6c28aaSamw  *
4*da6c28aaSamw  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
7*da6c28aaSamw  *
8*da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10*da6c28aaSamw  * See the License for the specific language governing permissions
11*da6c28aaSamw  * and limitations under the License.
12*da6c28aaSamw  *
13*da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14*da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16*da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17*da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da6c28aaSamw  *
19*da6c28aaSamw  * CDDL HEADER END
20*da6c28aaSamw  */
21*da6c28aaSamw /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*da6c28aaSamw  * Use is subject to license terms.
24*da6c28aaSamw  */
25*da6c28aaSamw 
26*da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*da6c28aaSamw 
28*da6c28aaSamw /*
29*da6c28aaSamw  * Main startup code for SMB/NETBIOS and some utility routines
30*da6c28aaSamw  * for the NETBIOS layer.
31*da6c28aaSamw  */
32*da6c28aaSamw 
33*da6c28aaSamw #include <synch.h>
34*da6c28aaSamw #include <unistd.h>
35*da6c28aaSamw #include <syslog.h>
36*da6c28aaSamw #include <string.h>
37*da6c28aaSamw #include <strings.h>
38*da6c28aaSamw #include <sys/socket.h>
39*da6c28aaSamw 
40*da6c28aaSamw #include <smbns_netbios.h>
41*da6c28aaSamw 
42*da6c28aaSamw netbios_status_t nb_status;
43*da6c28aaSamw 
44*da6c28aaSamw static pthread_t smb_nbns_thr; /* name service */
45*da6c28aaSamw static pthread_t smb_nbds_thr; /* dgram service */
46*da6c28aaSamw static pthread_t smb_nbts_thr; /* timer */
47*da6c28aaSamw static pthread_t smb_nbbs_thr; /* browser */
48*da6c28aaSamw 
49*da6c28aaSamw static void *smb_netbios_timer(void *);
50*da6c28aaSamw 
51*da6c28aaSamw void
52*da6c28aaSamw smb_netbios_chg_status(uint32_t status, int set)
53*da6c28aaSamw {
54*da6c28aaSamw 	(void) mutex_lock(&nb_status.mtx);
55*da6c28aaSamw 	if (set)
56*da6c28aaSamw 		nb_status.state |= status;
57*da6c28aaSamw 	else
58*da6c28aaSamw 		nb_status.state &= ~status;
59*da6c28aaSamw 	(void) cond_broadcast(&nb_status.cv);
60*da6c28aaSamw 	(void) mutex_unlock(&nb_status.mtx);
61*da6c28aaSamw }
62*da6c28aaSamw 
63*da6c28aaSamw void
64*da6c28aaSamw smb_netbios_shutdown(void)
65*da6c28aaSamw {
66*da6c28aaSamw 	smb_netbios_chg_status(NETBIOS_SHUTTING_DOWN, 1);
67*da6c28aaSamw 
68*da6c28aaSamw 	(void) pthread_join(smb_nbts_thr, 0);
69*da6c28aaSamw 	(void) pthread_join(smb_nbbs_thr, 0);
70*da6c28aaSamw 	(void) pthread_join(smb_nbns_thr, 0);
71*da6c28aaSamw 	(void) pthread_join(smb_nbds_thr, 0);
72*da6c28aaSamw 
73*da6c28aaSamw 	nb_status.state = NETBIOS_SHUT_DOWN;
74*da6c28aaSamw }
75*da6c28aaSamw 
76*da6c28aaSamw void
77*da6c28aaSamw smb_netbios_start()
78*da6c28aaSamw {
79*da6c28aaSamw 	int rc;
80*da6c28aaSamw 	mutex_t *mp;
81*da6c28aaSamw 	cond_t *cvp;
82*da6c28aaSamw 
83*da6c28aaSamw 	/* Startup Netbios named; port 137 */
84*da6c28aaSamw 	rc = pthread_create(&smb_nbns_thr, 0,
85*da6c28aaSamw 	    smb_netbios_name_service_daemon, 0);
86*da6c28aaSamw 	if (rc)
87*da6c28aaSamw 		return;
88*da6c28aaSamw 
89*da6c28aaSamw 	mp = &nb_status.mtx;
90*da6c28aaSamw 	cvp = &nb_status.cv;
91*da6c28aaSamw 
92*da6c28aaSamw 	(void) mutex_lock(mp);
93*da6c28aaSamw 
94*da6c28aaSamw 	while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING |
95*da6c28aaSamw 	    NETBIOS_NAME_SVC_FAILED))) {
96*da6c28aaSamw 		(void) cond_wait(cvp, mp);
97*da6c28aaSamw 	}
98*da6c28aaSamw 
99*da6c28aaSamw 	if (nb_status.state & NETBIOS_NAME_SVC_FAILED) {
100*da6c28aaSamw 		(void) mutex_unlock(mp);
101*da6c28aaSamw 		(void) fprintf(stderr,
102*da6c28aaSamw 		    "smbd: Netbios Name service startup failed!");
103*da6c28aaSamw 		smb_netbios_shutdown();
104*da6c28aaSamw 		return;
105*da6c28aaSamw 	}
106*da6c28aaSamw 	(void) mutex_unlock(mp);
107*da6c28aaSamw 
108*da6c28aaSamw 	(void) fprintf(stderr, "smbd: Netbios Name service started.");
109*da6c28aaSamw 	smb_netbios_name_config();
110*da6c28aaSamw 
111*da6c28aaSamw 	/* Startup Netbios datagram service; port 138 */
112*da6c28aaSamw 	rc = pthread_create(&smb_nbds_thr, 0,
113*da6c28aaSamw 	    smb_netbios_datagram_service_daemon, 0);
114*da6c28aaSamw 	if (rc == 0) {
115*da6c28aaSamw 		(void) mutex_lock(mp);
116*da6c28aaSamw 		while (!(nb_status.state & (NETBIOS_DATAGRAM_SVC_RUNNING |
117*da6c28aaSamw 		    NETBIOS_DATAGRAM_SVC_FAILED))) {
118*da6c28aaSamw 			(void) cond_wait(cvp, mp);
119*da6c28aaSamw 		}
120*da6c28aaSamw 
121*da6c28aaSamw 		if (nb_status.state & NETBIOS_DATAGRAM_SVC_FAILED) {
122*da6c28aaSamw 			(void) mutex_unlock(mp);
123*da6c28aaSamw 			(void) fprintf(stderr, "smbd: Netbios Datagram service "
124*da6c28aaSamw 			    "startup failed!");
125*da6c28aaSamw 			smb_netbios_shutdown();
126*da6c28aaSamw 			return;
127*da6c28aaSamw 		}
128*da6c28aaSamw 		(void) mutex_unlock(mp);
129*da6c28aaSamw 	} else {
130*da6c28aaSamw 		smb_netbios_shutdown();
131*da6c28aaSamw 		return;
132*da6c28aaSamw 	}
133*da6c28aaSamw 
134*da6c28aaSamw 	(void) fprintf(stderr, "smbd: Netbios Datagram service started.");
135*da6c28aaSamw 
136*da6c28aaSamw 	/* Startup Netbios browser service */
137*da6c28aaSamw 	rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0);
138*da6c28aaSamw 	if (rc) {
139*da6c28aaSamw 		smb_netbios_shutdown();
140*da6c28aaSamw 		return;
141*da6c28aaSamw 	}
142*da6c28aaSamw 
143*da6c28aaSamw 	(void) fprintf(stderr, "smbd: Netbios Browser client started.");
144*da6c28aaSamw 
145*da6c28aaSamw 	/* Startup Our internal, 1 second resolution, timer */
146*da6c28aaSamw 	rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0);
147*da6c28aaSamw 	if (rc == 0) {
148*da6c28aaSamw 		(void) mutex_lock(mp);
149*da6c28aaSamw 		while (!(nb_status.state & (NETBIOS_TIMER_RUNNING |
150*da6c28aaSamw 		    NETBIOS_TIMER_FAILED))) {
151*da6c28aaSamw 			(void) cond_wait(cvp, mp);
152*da6c28aaSamw 		}
153*da6c28aaSamw 
154*da6c28aaSamw 		if (nb_status.state & NETBIOS_TIMER_FAILED) {
155*da6c28aaSamw 			(void) mutex_unlock(mp);
156*da6c28aaSamw 			smb_netbios_shutdown();
157*da6c28aaSamw 			return;
158*da6c28aaSamw 		}
159*da6c28aaSamw 		(void) mutex_unlock(mp);
160*da6c28aaSamw 	} else {
161*da6c28aaSamw 		smb_netbios_shutdown();
162*da6c28aaSamw 		return;
163*da6c28aaSamw 	}
164*da6c28aaSamw 
165*da6c28aaSamw 	(void) fprintf(stderr, "smbd: Netbios Timer service started.");
166*da6c28aaSamw }
167*da6c28aaSamw 
168*da6c28aaSamw /*ARGSUSED*/
169*da6c28aaSamw static void *
170*da6c28aaSamw smb_netbios_timer(void *arg)
171*da6c28aaSamw {
172*da6c28aaSamw 	static unsigned int	ticks;
173*da6c28aaSamw 
174*da6c28aaSamw 	smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1);
175*da6c28aaSamw 
176*da6c28aaSamw 	while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
177*da6c28aaSamw 		(void) sleep(1);
178*da6c28aaSamw 
179*da6c28aaSamw 		if (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING)
180*da6c28aaSamw 			smb_netbios_datagram_tick();
181*da6c28aaSamw 		else
182*da6c28aaSamw 			break;
183*da6c28aaSamw 
184*da6c28aaSamw 		if (nb_status.state & NETBIOS_NAME_SVC_RUNNING) {
185*da6c28aaSamw 			smb_netbios_name_tick();
186*da6c28aaSamw 
187*da6c28aaSamw 			/* every 10 minutes */
188*da6c28aaSamw 			if ((ticks % 600) == 0)
189*da6c28aaSamw 				smb_netbios_cache_clean();
190*da6c28aaSamw 		}
191*da6c28aaSamw 		else
192*da6c28aaSamw 			break;
193*da6c28aaSamw 	}
194*da6c28aaSamw 
195*da6c28aaSamw 	nb_status.state &= ~NETBIOS_TIMER_RUNNING;
196*da6c28aaSamw 	if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
197*da6c28aaSamw 		/* either name or datagram service has failed */
198*da6c28aaSamw 		smb_netbios_shutdown();
199*da6c28aaSamw 	}
200*da6c28aaSamw 
201*da6c28aaSamw 	return (0);
202*da6c28aaSamw }
203*da6c28aaSamw 
204*da6c28aaSamw int
205*da6c28aaSamw smb_first_level_name_encode(struct name_entry *name,
206*da6c28aaSamw 				unsigned char *out, int max_out)
207*da6c28aaSamw {
208*da6c28aaSamw 	return (netbios_first_level_name_encode(name->name, name->scope,
209*da6c28aaSamw 	    out, max_out));
210*da6c28aaSamw }
211*da6c28aaSamw 
212*da6c28aaSamw int
213*da6c28aaSamw smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
214*da6c28aaSamw {
215*da6c28aaSamw 	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
216*da6c28aaSamw 	    (char *)name->scope));
217*da6c28aaSamw }
218*da6c28aaSamw 
219*da6c28aaSamw /*
220*da6c28aaSamw  * smb_encode_netbios_name
221*da6c28aaSamw  *
222*da6c28aaSamw  * Set up the name and scope fields in the destination name_entry structure.
223*da6c28aaSamw  * The name is padded with spaces to 15 bytes. The suffix is copied into the
224*da6c28aaSamw  * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
225*da6c28aaSamw  * to uppercase.
226*da6c28aaSamw  */
227*da6c28aaSamw void
228*da6c28aaSamw smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
229*da6c28aaSamw     struct name_entry *dest)
230*da6c28aaSamw {
231*da6c28aaSamw 	char tmp_name[NETBIOS_NAME_SZ];
232*da6c28aaSamw 	mts_wchar_t wtmp_name[NETBIOS_NAME_SZ];
233*da6c28aaSamw 	unsigned int cpid;
234*da6c28aaSamw 	int	len;
235*da6c28aaSamw 	size_t rc;
236*da6c28aaSamw 
237*da6c28aaSamw 	len = 0;
238*da6c28aaSamw 	rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
239*da6c28aaSamw 
240*da6c28aaSamw 	if (rc != (size_t)-1) {
241*da6c28aaSamw 		wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
242*da6c28aaSamw 		cpid = oem_get_smb_cpid();
243*da6c28aaSamw 		rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid);
244*da6c28aaSamw 		if (rc > 0)
245*da6c28aaSamw 			len = strlen(tmp_name);
246*da6c28aaSamw 	}
247*da6c28aaSamw 
248*da6c28aaSamw 	(void) memset(dest->name, ' ', NETBIOS_NAME_SZ - 1);
249*da6c28aaSamw 	if (len) {
250*da6c28aaSamw 		(void) utf8_strupr(tmp_name);
251*da6c28aaSamw 		(void) memcpy(dest->name, tmp_name, len);
252*da6c28aaSamw 	}
253*da6c28aaSamw 	dest->name[NETBIOS_NAME_SZ - 1] = suffix;
254*da6c28aaSamw 
255*da6c28aaSamw 	if (scope == NULL) {
256*da6c28aaSamw 		smb_config_rdlock();
257*da6c28aaSamw 		(void) strlcpy((char *)dest->scope,
258*da6c28aaSamw 		    smb_config_getstr(SMB_CI_NBSCOPE), NETBIOS_DOMAIN_NAME_MAX);
259*da6c28aaSamw 		smb_config_unlock();
260*da6c28aaSamw 	} else {
261*da6c28aaSamw 		(void) strlcpy((char *)dest->scope, (const char *)scope,
262*da6c28aaSamw 		    NETBIOS_DOMAIN_NAME_MAX);
263*da6c28aaSamw 	}
264*da6c28aaSamw 	(void) utf8_strupr((char *)dest->scope);
265*da6c28aaSamw }
266*da6c28aaSamw 
267*da6c28aaSamw void
268*da6c28aaSamw smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
269*da6c28aaSamw     uint32_t ipaddr, unsigned short port, uint32_t attr,
270*da6c28aaSamw     uint32_t addr_attr, struct name_entry *dest)
271*da6c28aaSamw {
272*da6c28aaSamw 	bzero(dest, sizeof (struct name_entry));
273*da6c28aaSamw 	smb_encode_netbios_name(name, suffix, scope, dest);
274*da6c28aaSamw 
275*da6c28aaSamw 	switch (smb_node_type) {
276*da6c28aaSamw 	case 'H':
277*da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
278*da6c28aaSamw 		break;
279*da6c28aaSamw 	case 'M':
280*da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
281*da6c28aaSamw 		break;
282*da6c28aaSamw 	case 'P':
283*da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
284*da6c28aaSamw 		break;
285*da6c28aaSamw 	case 'B':
286*da6c28aaSamw 	default:
287*da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
288*da6c28aaSamw 		break;
289*da6c28aaSamw 	}
290*da6c28aaSamw 
291*da6c28aaSamw 	dest->addr_list.refresh_ttl = dest->addr_list.ttl =
292*da6c28aaSamw 	    TO_SECONDS(DEFAULT_TTL);
293*da6c28aaSamw 
294*da6c28aaSamw 	dest->addr_list.sin.sin_family = AF_INET;
295*da6c28aaSamw 	dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
296*da6c28aaSamw 	dest->addr_list.sin.sin_addr.s_addr = ipaddr;
297*da6c28aaSamw 	dest->addr_list.sin.sin_port = port;
298*da6c28aaSamw 	dest->addr_list.attributes = addr_attr;
299*da6c28aaSamw 	dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
300*da6c28aaSamw }
301