xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Main startup code for SMB/NETBIOS and some utility routines
28  * for the NETBIOS layer.
29  */
30 
31 #include <sys/tzfile.h>
32 #include <assert.h>
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 #include <stdio.h>
40 #include <pwd.h>
41 #include <grp.h>
42 #include <smbns_netbios.h>
43 
44 #define	SMB_NETBIOS_DUMP_FILE		"netbios"
45 
46 static netbios_service_t nbtd;
47 
48 static void smb_netbios_shutdown(void);
49 static void *smb_netbios_service(void *);
50 static void smb_netbios_dump(void);
51 
52 /*
53  * Start the NetBIOS services
54  */
55 int
56 smb_netbios_start(void)
57 {
58 	pthread_t	tid;
59 	pthread_attr_t	attr;
60 	int		rc;
61 
62 	if (smb_netbios_cache_init() < 0)
63 		return (-1);
64 
65 	(void) pthread_attr_init(&attr);
66 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
67 	rc = pthread_create(&tid, &attr, smb_netbios_service, NULL);
68 	(void) pthread_attr_destroy(&attr);
69 	return (rc);
70 }
71 
72 /*
73  * Stop the NetBIOS services
74  */
75 void
76 smb_netbios_stop(void)
77 {
78 	char	fname[MAXPATHLEN];
79 
80 	smb_netbios_event(NETBIOS_EVENT_STOP);
81 
82 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
83 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
84 	(void) unlink(fname);
85 
86 }
87 
88 /*
89  * Launch the NetBIOS Name Service, Datagram and Browser services
90  * and then sit in a loop providing a 1 second resolution timer.
91  * The timer will:
92  *	- update the netbios stats file every 10 minutes
93  *	- clean the cache every 10 minutes
94  */
95 /*ARGSUSED*/
96 static void *
97 smb_netbios_service(void *arg)
98 {
99 	static uint32_t	ticks = 0;
100 	pthread_t	tid;
101 	int		rc;
102 
103 	smb_netbios_event(NETBIOS_EVENT_START);
104 
105 	rc = pthread_create(&tid, NULL, smb_netbios_name_service, NULL);
106 	if (rc != 0) {
107 		smb_netbios_shutdown();
108 		return (NULL);
109 	}
110 
111 	smb_netbios_wait(NETBIOS_EVENT_NS_START);
112 	if (smb_netbios_error()) {
113 		smb_netbios_shutdown();
114 		return (NULL);
115 	}
116 
117 	smb_netbios_name_config();
118 
119 	rc = pthread_create(&tid, NULL, smb_netbios_datagram_service, NULL);
120 	if (rc != 0) {
121 		smb_netbios_shutdown();
122 		return (NULL);
123 	}
124 
125 	smb_netbios_wait(NETBIOS_EVENT_DGM_START);
126 	if (smb_netbios_error()) {
127 		smb_netbios_shutdown();
128 		return (NULL);
129 	}
130 
131 	rc = pthread_create(&tid, NULL, smb_browser_service, NULL);
132 	if (rc != 0) {
133 		smb_netbios_shutdown();
134 		return (NULL);
135 	}
136 
137 	smb_netbios_event(NETBIOS_EVENT_TIMER_START);
138 
139 	for (;;) {
140 		(void) sleep(1);
141 		ticks++;
142 
143 		if (!smb_netbios_running())
144 			break;
145 
146 		smb_netbios_datagram_tick();
147 		smb_netbios_name_tick();
148 
149 		if ((ticks % 600) == 0) {
150 			smb_netbios_event(NETBIOS_EVENT_DUMP);
151 			smb_netbios_cache_clean();
152 		}
153 	}
154 
155 	smb_netbios_event(NETBIOS_EVENT_TIMER_STOP);
156 	smb_netbios_shutdown();
157 	return (NULL);
158 }
159 
160 static void
161 smb_netbios_shutdown(void)
162 {
163 	(void) pthread_join(nbtd.nbs_browser.s_tid, 0);
164 	(void) pthread_join(nbtd.nbs_dgm.s_tid, 0);
165 	(void) pthread_join(nbtd.nbs_ns.s_tid, 0);
166 
167 	nbtd.nbs_browser.s_tid = 0;
168 	nbtd.nbs_dgm.s_tid = 0;
169 	nbtd.nbs_ns.s_tid = 0;
170 
171 	smb_netbios_cache_fini();
172 
173 	if (smb_netbios_error()) {
174 		smb_netbios_event(NETBIOS_EVENT_RESET);
175 		if (smb_netbios_start() != 0)
176 			syslog(LOG_ERR, "netbios: restart failed");
177 	}
178 }
179 
180 int
181 smb_first_level_name_encode(struct name_entry *name,
182 				unsigned char *out, int max_out)
183 {
184 	return (netbios_first_level_name_encode(name->name, name->scope,
185 	    out, max_out));
186 }
187 
188 int
189 smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
190 {
191 	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
192 	    (char *)name->scope));
193 }
194 
195 /*
196  * smb_encode_netbios_name
197  *
198  * Set up the name and scope fields in the destination name_entry structure.
199  * The name is padded with spaces to 15 bytes. The suffix is copied into the
200  * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
201  * to uppercase.
202  */
203 void
204 smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
205     struct name_entry *dest)
206 {
207 	smb_tonetbiosname((char *)name, (char *)dest->name, suffix);
208 
209 	if (scope) {
210 		(void) strlcpy((char *)dest->scope, (const char *)scope,
211 		    sizeof (dest->scope));
212 	} else {
213 		(void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
214 		    sizeof (dest->scope));
215 	}
216 
217 	(void) smb_strupr((char *)dest->scope);
218 }
219 
220 void
221 smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
222     uint32_t ipaddr, unsigned short port, uint32_t attr,
223     uint32_t addr_attr, struct name_entry *dest)
224 {
225 	bzero(dest, sizeof (struct name_entry));
226 	smb_encode_netbios_name(name, suffix, scope, dest);
227 
228 	switch (smb_node_type) {
229 	case 'H':
230 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
231 		break;
232 	case 'M':
233 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
234 		break;
235 	case 'P':
236 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
237 		break;
238 	case 'B':
239 	default:
240 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
241 		break;
242 	}
243 
244 	dest->addr_list.refresh_ttl = dest->addr_list.ttl =
245 	    TO_SECONDS(DEFAULT_TTL);
246 
247 	dest->addr_list.sin.sin_family = AF_INET;
248 	dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
249 	dest->addr_list.sin.sin_addr.s_addr = ipaddr;
250 	dest->addr_list.sin.sin_port = port;
251 	dest->addr_list.attributes = addr_attr;
252 	dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
253 }
254 
255 void
256 smb_netbios_event(netbios_event_t event)
257 {
258 	static char *event_msg[] = {
259 		"startup",
260 		"shutdown",
261 		"restart",
262 		"name service started",
263 		"name service stopped",
264 		"datagram service started",
265 		"datagram service stopped",
266 		"browser service started",
267 		"browser service stopped",
268 		"timer service started",
269 		"timer service stopped",
270 		"error",
271 		"dump"
272 	};
273 
274 	(void) mutex_lock(&nbtd.nbs_mtx);
275 
276 	if (event == NETBIOS_EVENT_DUMP) {
277 		if (nbtd.nbs_last_event == NULL)
278 			nbtd.nbs_last_event = event_msg[event];
279 		smb_netbios_dump();
280 		(void) mutex_unlock(&nbtd.nbs_mtx);
281 		return;
282 	}
283 
284 	nbtd.nbs_last_event = event_msg[event];
285 	syslog(LOG_DEBUG, "netbios: %s", nbtd.nbs_last_event);
286 
287 	switch (nbtd.nbs_state) {
288 	case NETBIOS_STATE_INIT:
289 		if (event == NETBIOS_EVENT_START)
290 			nbtd.nbs_state = NETBIOS_STATE_RUNNING;
291 		break;
292 
293 	case NETBIOS_STATE_RUNNING:
294 		switch (event) {
295 		case NETBIOS_EVENT_NS_START:
296 			nbtd.nbs_ns.s_tid = pthread_self();
297 			nbtd.nbs_ns.s_up = B_TRUE;
298 			break;
299 		case NETBIOS_EVENT_NS_STOP:
300 			nbtd.nbs_ns.s_up = B_FALSE;
301 			break;
302 		case NETBIOS_EVENT_DGM_START:
303 			nbtd.nbs_dgm.s_tid = pthread_self();
304 			nbtd.nbs_dgm.s_up = B_TRUE;
305 			break;
306 		case NETBIOS_EVENT_DGM_STOP:
307 			nbtd.nbs_dgm.s_up = B_FALSE;
308 			break;
309 		case NETBIOS_EVENT_BROWSER_START:
310 			nbtd.nbs_browser.s_tid = pthread_self();
311 			nbtd.nbs_browser.s_up = B_TRUE;
312 			break;
313 		case NETBIOS_EVENT_BROWSER_STOP:
314 			nbtd.nbs_browser.s_up = B_FALSE;
315 			break;
316 		case NETBIOS_EVENT_TIMER_START:
317 			nbtd.nbs_timer.s_tid = pthread_self();
318 			nbtd.nbs_timer.s_up = B_TRUE;
319 			break;
320 		case NETBIOS_EVENT_TIMER_STOP:
321 			nbtd.nbs_timer.s_up = B_FALSE;
322 			break;
323 		case NETBIOS_EVENT_STOP:
324 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
325 			break;
326 		case NETBIOS_EVENT_ERROR:
327 			nbtd.nbs_state = NETBIOS_STATE_ERROR;
328 			++nbtd.nbs_errors;
329 			break;
330 		default:
331 			break;
332 		}
333 		break;
334 
335 	case NETBIOS_STATE_CLOSING:
336 	case NETBIOS_STATE_ERROR:
337 	default:
338 		switch (event) {
339 		case NETBIOS_EVENT_NS_STOP:
340 			nbtd.nbs_ns.s_up = B_FALSE;
341 			break;
342 		case NETBIOS_EVENT_DGM_STOP:
343 			nbtd.nbs_dgm.s_up = B_FALSE;
344 			break;
345 		case NETBIOS_EVENT_BROWSER_STOP:
346 			nbtd.nbs_browser.s_up = B_FALSE;
347 			break;
348 		case NETBIOS_EVENT_TIMER_STOP:
349 			nbtd.nbs_timer.s_up = B_FALSE;
350 			break;
351 		case NETBIOS_EVENT_STOP:
352 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
353 			break;
354 		case NETBIOS_EVENT_RESET:
355 			nbtd.nbs_state = NETBIOS_STATE_INIT;
356 			break;
357 		case NETBIOS_EVENT_ERROR:
358 			++nbtd.nbs_errors;
359 			break;
360 		default:
361 			break;
362 		}
363 		break;
364 	}
365 
366 	smb_netbios_dump();
367 	(void) cond_broadcast(&nbtd.nbs_cv);
368 	(void) mutex_unlock(&nbtd.nbs_mtx);
369 }
370 
371 void
372 smb_netbios_wait(netbios_event_t event)
373 {
374 	boolean_t *svc = NULL;
375 	boolean_t desired_state;
376 
377 	(void) mutex_lock(&nbtd.nbs_mtx);
378 
379 	switch (event) {
380 	case NETBIOS_EVENT_NS_START:
381 	case NETBIOS_EVENT_NS_STOP:
382 		svc = &nbtd.nbs_ns.s_up;
383 		desired_state =
384 		    (event == NETBIOS_EVENT_NS_START) ? B_TRUE : B_FALSE;
385 		break;
386 	case NETBIOS_EVENT_DGM_START:
387 	case NETBIOS_EVENT_DGM_STOP:
388 		svc = &nbtd.nbs_dgm.s_up;
389 		desired_state =
390 		    (event == NETBIOS_EVENT_DGM_START) ? B_TRUE : B_FALSE;
391 		break;
392 	case NETBIOS_EVENT_BROWSER_START:
393 	case NETBIOS_EVENT_BROWSER_STOP:
394 		svc = &nbtd.nbs_browser.s_up;
395 		desired_state =
396 		    (event == NETBIOS_EVENT_BROWSER_START) ? B_TRUE : B_FALSE;
397 		break;
398 	default:
399 		(void) mutex_unlock(&nbtd.nbs_mtx);
400 		return;
401 	}
402 
403 	while (*svc != desired_state) {
404 		if (nbtd.nbs_state != NETBIOS_STATE_RUNNING)
405 			break;
406 
407 		(void) cond_wait(&nbtd.nbs_cv, &nbtd.nbs_mtx);
408 	}
409 
410 	(void) mutex_unlock(&nbtd.nbs_mtx);
411 }
412 
413 void
414 smb_netbios_sleep(time_t seconds)
415 {
416 	timestruc_t reltimeout;
417 
418 	(void) mutex_lock(&nbtd.nbs_mtx);
419 
420 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING) {
421 		if (seconds == 0)
422 			seconds  = 1;
423 		reltimeout.tv_sec = seconds;
424 		reltimeout.tv_nsec = 0;
425 
426 		(void) cond_reltimedwait(&nbtd.nbs_cv,
427 		    &nbtd.nbs_mtx, &reltimeout);
428 	}
429 
430 	(void) mutex_unlock(&nbtd.nbs_mtx);
431 }
432 
433 boolean_t
434 smb_netbios_running(void)
435 {
436 	boolean_t is_running;
437 
438 	(void) mutex_lock(&nbtd.nbs_mtx);
439 
440 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING)
441 		is_running = B_TRUE;
442 	else
443 		is_running = B_FALSE;
444 
445 	(void) mutex_unlock(&nbtd.nbs_mtx);
446 	return (is_running);
447 }
448 
449 boolean_t
450 smb_netbios_error(void)
451 {
452 	boolean_t error;
453 
454 	(void) mutex_lock(&nbtd.nbs_mtx);
455 
456 	if (nbtd.nbs_state == NETBIOS_STATE_ERROR)
457 		error = B_TRUE;
458 	else
459 		error = B_FALSE;
460 
461 	(void) mutex_unlock(&nbtd.nbs_mtx);
462 	return (error);
463 }
464 
465 /*
466  * Write the service state to /var/run/smb/netbios.
467  *
468  * This is a private interface.  To update the file use:
469  *	smb_netbios_event(NETBIOS_EVENT_DUMP);
470  */
471 static void
472 smb_netbios_dump(void)
473 {
474 	static struct {
475 		netbios_state_t state;
476 		char		*text;
477 	} sm[] = {
478 		{ NETBIOS_STATE_INIT,		"init" },
479 		{ NETBIOS_STATE_RUNNING,	"running" },
480 		{ NETBIOS_STATE_CLOSING,	"closing" },
481 		{ NETBIOS_STATE_ERROR,		"error" }
482 	};
483 
484 	char		fname[MAXPATHLEN];
485 	FILE		*fp;
486 	struct passwd	*pwd;
487 	struct group	*grp;
488 	uid_t		uid;
489 	gid_t		gid;
490 	char		*last_event = "none";
491 	int		i;
492 
493 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
494 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
495 
496 	if ((fp = fopen(fname, "w")) == NULL)
497 		return;
498 
499 	pwd = getpwnam("root");
500 	grp = getgrnam("sys");
501 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
502 	gid = (grp == NULL) ? 3 : grp->gr_gid;
503 
504 	(void) lockf(fileno(fp), F_LOCK, 0);
505 	(void) fchmod(fileno(fp), 0600);
506 	(void) fchown(fileno(fp), uid, gid);
507 
508 	if (nbtd.nbs_last_event)
509 		last_event = nbtd.nbs_last_event;
510 
511 	for (i = 0; i < sizeof (sm) / sizeof (sm[0]); ++i) {
512 		if (nbtd.nbs_state == sm[i].state) {
513 			(void) fprintf(fp,
514 			    "State             %s  (event: %s, errors: %u)\n",
515 			    sm[i].text, last_event, nbtd.nbs_errors);
516 			break;
517 		}
518 	}
519 
520 	(void) fprintf(fp, "Name Service      %-7s  (%u)\n",
521 	    nbtd.nbs_ns.s_up ? "up" : "down", nbtd.nbs_ns.s_tid);
522 	(void) fprintf(fp, "Datagram Service  %-7s  (%u)\n",
523 	    nbtd.nbs_dgm.s_up ? "up" : "down", nbtd.nbs_dgm.s_tid);
524 	(void) fprintf(fp, "Browser Service   %-7s  (%u)\n",
525 	    nbtd.nbs_browser.s_up ? "up" : "down", nbtd.nbs_browser.s_tid);
526 	(void) fprintf(fp, "Timer Service     %-7s  (%u)\n",
527 	    nbtd.nbs_timer.s_up ? "up" : "down", nbtd.nbs_timer.s_tid);
528 
529 	smb_netbios_cache_dump(fp);
530 
531 	(void) lockf(fileno(fp), F_ULOCK, 0);
532 	(void) fclose(fp);
533 }
534