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