xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
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 2007 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 void
77 smb_netbios_start()
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;
88 
89 	mp = &nb_status.mtx;
90 	cvp = &nb_status.cv;
91 
92 	(void) mutex_lock(mp);
93 
94 	while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING |
95 	    NETBIOS_NAME_SVC_FAILED))) {
96 		(void) cond_wait(cvp, mp);
97 	}
98 
99 	if (nb_status.state & NETBIOS_NAME_SVC_FAILED) {
100 		(void) mutex_unlock(mp);
101 		(void) fprintf(stderr,
102 		    "smbd: Netbios Name service startup failed!");
103 		smb_netbios_shutdown();
104 		return;
105 	}
106 	(void) mutex_unlock(mp);
107 
108 	(void) fprintf(stderr, "smbd: Netbios Name service started.");
109 	smb_netbios_name_config();
110 
111 	/* Startup Netbios datagram service; port 138 */
112 	rc = pthread_create(&smb_nbds_thr, 0,
113 	    smb_netbios_datagram_service_daemon, 0);
114 	if (rc == 0) {
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 			(void) fprintf(stderr, "smbd: Netbios Datagram service "
124 			    "startup failed!");
125 			smb_netbios_shutdown();
126 			return;
127 		}
128 		(void) mutex_unlock(mp);
129 	} else {
130 		smb_netbios_shutdown();
131 		return;
132 	}
133 
134 	(void) fprintf(stderr, "smbd: Netbios Datagram service started.");
135 
136 	/* Startup Netbios browser service */
137 	rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0);
138 	if (rc) {
139 		smb_netbios_shutdown();
140 		return;
141 	}
142 
143 	(void) fprintf(stderr, "smbd: Netbios Browser client started.");
144 
145 	/* Startup Our internal, 1 second resolution, timer */
146 	rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0);
147 	if (rc == 0) {
148 		(void) mutex_lock(mp);
149 		while (!(nb_status.state & (NETBIOS_TIMER_RUNNING |
150 		    NETBIOS_TIMER_FAILED))) {
151 			(void) cond_wait(cvp, mp);
152 		}
153 
154 		if (nb_status.state & NETBIOS_TIMER_FAILED) {
155 			(void) mutex_unlock(mp);
156 			smb_netbios_shutdown();
157 			return;
158 		}
159 		(void) mutex_unlock(mp);
160 	} else {
161 		smb_netbios_shutdown();
162 		return;
163 	}
164 
165 	(void) fprintf(stderr, "smbd: Netbios Timer service started.");
166 }
167 
168 /*ARGSUSED*/
169 static void *
170 smb_netbios_timer(void *arg)
171 {
172 	static unsigned int	ticks;
173 
174 	smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1);
175 
176 	while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
177 		(void) sleep(1);
178 
179 		if (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING)
180 			smb_netbios_datagram_tick();
181 		else
182 			break;
183 
184 		if (nb_status.state & NETBIOS_NAME_SVC_RUNNING) {
185 			smb_netbios_name_tick();
186 
187 			/* every 10 minutes */
188 			if ((ticks % 600) == 0)
189 				smb_netbios_cache_clean();
190 		}
191 		else
192 			break;
193 	}
194 
195 	nb_status.state &= ~NETBIOS_TIMER_RUNNING;
196 	if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
197 		/* either name or datagram service has failed */
198 		smb_netbios_shutdown();
199 	}
200 
201 	return (0);
202 }
203 
204 int
205 smb_first_level_name_encode(struct name_entry *name,
206 				unsigned char *out, int max_out)
207 {
208 	return (netbios_first_level_name_encode(name->name, name->scope,
209 	    out, max_out));
210 }
211 
212 int
213 smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
214 {
215 	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
216 	    (char *)name->scope));
217 }
218 
219 /*
220  * smb_encode_netbios_name
221  *
222  * Set up the name and scope fields in the destination name_entry structure.
223  * The name is padded with spaces to 15 bytes. The suffix is copied into the
224  * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
225  * to uppercase.
226  */
227 void
228 smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
229     struct name_entry *dest)
230 {
231 	char tmp_name[NETBIOS_NAME_SZ];
232 	mts_wchar_t wtmp_name[NETBIOS_NAME_SZ];
233 	unsigned int cpid;
234 	int	len;
235 	size_t rc;
236 
237 	len = 0;
238 	rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
239 
240 	if (rc != (size_t)-1) {
241 		wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
242 		cpid = oem_get_smb_cpid();
243 		rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid);
244 		if (rc > 0)
245 			len = strlen(tmp_name);
246 	}
247 
248 	(void) memset(dest->name, ' ', NETBIOS_NAME_SZ - 1);
249 	if (len) {
250 		(void) utf8_strupr(tmp_name);
251 		(void) memcpy(dest->name, tmp_name, len);
252 	}
253 	dest->name[NETBIOS_NAME_SZ - 1] = suffix;
254 
255 	if (scope == NULL) {
256 		smb_config_rdlock();
257 		(void) strlcpy((char *)dest->scope,
258 		    smb_config_getstr(SMB_CI_NBSCOPE), NETBIOS_DOMAIN_NAME_MAX);
259 		smb_config_unlock();
260 	} else {
261 		(void) strlcpy((char *)dest->scope, (const char *)scope,
262 		    NETBIOS_DOMAIN_NAME_MAX);
263 	}
264 	(void) utf8_strupr((char *)dest->scope);
265 }
266 
267 void
268 smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
269     uint32_t ipaddr, unsigned short port, uint32_t attr,
270     uint32_t addr_attr, struct name_entry *dest)
271 {
272 	bzero(dest, sizeof (struct name_entry));
273 	smb_encode_netbios_name(name, suffix, scope, dest);
274 
275 	switch (smb_node_type) {
276 	case 'H':
277 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
278 		break;
279 	case 'M':
280 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
281 		break;
282 	case 'P':
283 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
284 		break;
285 	case 'B':
286 	default:
287 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
288 		break;
289 	}
290 
291 	dest->addr_list.refresh_ttl = dest->addr_list.ttl =
292 	    TO_SECONDS(DEFAULT_TTL);
293 
294 	dest->addr_list.sin.sin_family = AF_INET;
295 	dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
296 	dest->addr_list.sin.sin_addr.s_addr = ipaddr;
297 	dest->addr_list.sin.sin_port = port;
298 	dest->addr_list.attributes = addr_attr;
299 	dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
300 }
301