xref: /netbsd-src/usr.sbin/sdpd/server.c (revision 213aa76def5f7e6d8b6925a59d5bc8221df842d9)
1 /*	$NetBSD: server.c,v 1.12 2021/08/08 20:54:49 nia Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 Itronix Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of Itronix Inc. may not be used to endorse
16  *    or promote products derived from this software without specific
17  *    prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*-
32  * Copyright (c) 2009 The NetBSD Foundation, Inc.
33  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $
58  */
59 
60 #include <sys/cdefs.h>
61 __RCSID("$NetBSD: server.c,v 1.12 2021/08/08 20:54:49 nia Exp $");
62 
63 #include <sys/select.h>
64 #include <sys/stat.h>
65 #include <sys/ucred.h>
66 #include <sys/un.h>
67 
68 #include <assert.h>
69 #include <bluetooth.h>
70 #include <errno.h>
71 #include <grp.h>
72 #include <pwd.h>
73 #include <sdp.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 
79 #include "sdpd.h"
80 
81 static bool	server_open_control	(server_t *, char const *);
82 static bool	server_open_l2cap	(server_t *);
83 static void	server_accept_client	(server_t *, int);
84 static bool	server_process_request	(server_t *, int);
85 static void	server_close_fd		(server_t *, int);
86 static bool	server_auth_check	(server_t *, void *);
87 
88 /* number of groups we allocate space for in cmsg */
89 #define MAX_GROUPS	20
90 
91 /*
92  * Initialize server
93  */
94 bool
server_init(server_t * srv,char const * control,char const * sgroup)95 server_init(server_t *srv, char const *control, char const *sgroup)
96 {
97 
98 	assert(srv != NULL);
99 	assert(control != NULL);
100 
101 	memset(srv, 0, sizeof(*srv));
102 	FD_ZERO(&srv->fdset);
103 	srv->sgroup = sgroup;
104 
105 	srv->fdmax = -1;
106 	srv->fdidx = calloc(FD_SETSIZE, sizeof(fd_idx_t));
107 	if (srv->fdidx == NULL) {
108 		log_crit("Failed to allocate fd index");
109 		goto fail;
110 	}
111 
112 	srv->ctllen = CMSG_SPACE(SOCKCREDSIZE(MAX_GROUPS));
113 	srv->ctlbuf = malloc(srv->ctllen);
114 	if (srv->ctlbuf == NULL) {
115 		log_crit("Malloc cmsg buffer (len=%zu) failed.", srv->ctllen);
116 		goto fail;
117 	}
118 
119 	srv->imtu = SDP_LOCAL_MTU - sizeof(sdp_pdu_t);
120 	srv->ibuf = malloc(srv->imtu);
121 	if (srv->ibuf == NULL) {
122 		log_crit("Malloc input buffer (imtu=%d) failed.", srv->imtu);
123 		goto fail;
124 	}
125 
126 	srv->omtu = L2CAP_MTU_DEFAULT - sizeof(sdp_pdu_t);
127 	srv->obuf = malloc(srv->omtu);
128 	if (srv->obuf == NULL) {
129 		log_crit("Malloc output buffer (omtu=%d) failed.", srv->omtu);
130 		goto fail;
131 	}
132 
133 	if (db_init(srv)
134 	    && server_open_control(srv, control)
135 	    && server_open_l2cap(srv))
136 		return true;
137 
138 fail:
139 	server_shutdown(srv);
140 	return false;
141 }
142 
143 /*
144  * Open local control socket
145  */
146 static bool
server_open_control(server_t * srv,char const * control)147 server_open_control(server_t *srv, char const *control)
148 {
149 	struct sockaddr_un	un;
150 	int			opt, fd;
151 
152 	if (unlink(control) == -1 && errno != ENOENT) {
153 		log_crit("Could not unlink(%s). %s (%d)",
154 		    control, strerror(errno), errno);
155 
156 		return false;
157 	}
158 
159 	fd = socket(PF_LOCAL, SOCK_STREAM, 0);
160 	if (fd == -1) {
161 		log_crit("Could not create control socket. %s (%d)",
162 		    strerror(errno), errno);
163 
164 		return false;
165 	}
166 
167 	opt = 1;
168 	if (setsockopt(fd, SOL_LOCAL, LOCAL_CREDS, &opt, sizeof(opt)) == -1)
169 		log_crit("Warning: No credential checks on control socket");
170 
171 	memset(&un, 0, sizeof(un));
172 	un.sun_len = sizeof(un);
173 	un.sun_family = AF_LOCAL;
174 	strlcpy(un.sun_path, control, sizeof(un.sun_path));
175 
176 	if (bind(fd, (struct sockaddr *) &un, sizeof(un)) == -1) {
177 		log_crit("Could not bind control socket. %s (%d)",
178 		    strerror(errno), errno);
179 
180 		close(fd);
181 		return false;
182 	}
183 
184 	if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
185 		log_crit("Could not set permissions on control socket. %s (%d)",
186 		    strerror(errno), errno);
187 
188 		close(fd);
189 		return false;
190 	}
191 
192 	if (listen(fd, 5) == -1) {
193 		log_crit("Could not listen on control socket. %s (%d)",
194 		    strerror(errno), errno);
195 
196 		close(fd);
197 		return false;
198 	}
199 
200 	/* Add control descriptor to index */
201 	if (fd > srv->fdmax)
202 		srv->fdmax = fd;
203 
204 	FD_SET(fd, &srv->fdset);
205 	srv->fdidx[fd].valid = true;
206 	srv->fdidx[fd].server = true;
207 	srv->fdidx[fd].control = true;
208 	srv->fdidx[fd].priv = false;
209 	return true;
210 }
211 
212 /*
213  * Open L2CAP server socket
214  */
215 static bool
server_open_l2cap(server_t * srv)216 server_open_l2cap(server_t *srv)
217 {
218 	struct sockaddr_bt	sa;
219 	int			fd;
220 
221 	fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
222 	if (fd == -1) {
223 		log_crit("Could not create L2CAP socket. %s (%d)",
224 		    strerror(errno), errno);
225 
226 		return false;
227 	}
228 
229         if (setsockopt(fd, BTPROTO_L2CAP, SO_L2CAP_IMTU,
230 	    &srv->imtu, sizeof(srv->imtu)) == -1) {
231 		log_crit("Could not set L2CAP Incoming MTU. %s (%d)",
232 		    strerror(errno), errno);
233 
234 		close(fd);
235 		return false;
236         }
237 
238 	memset(&sa, 0, sizeof(sa));
239 	sa.bt_len = sizeof(sa);
240 	sa.bt_family = AF_BLUETOOTH;
241 	sa.bt_psm = L2CAP_PSM_SDP;
242 	bdaddr_copy(&sa.bt_bdaddr, BDADDR_ANY);
243 
244 	if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
245 		log_crit("Could not bind L2CAP socket. %s (%d)",
246 		    strerror(errno), errno);
247 
248 		close(fd);
249 		return false;
250 	}
251 
252 	if (listen(fd, 5) == -1) {
253 		log_crit("Could not listen on L2CAP socket. %s (%d)",
254 		    strerror(errno), errno);
255 
256 		close(fd);
257 		return false;
258 	}
259 
260 	/* Add L2CAP descriptor to index */
261 	if (fd > srv->fdmax)
262 		srv->fdmax = fd;
263 
264 	FD_SET(fd, &srv->fdset);
265 	srv->fdidx[fd].valid = true;
266 	srv->fdidx[fd].server = true;
267 	srv->fdidx[fd].control = false;
268 	srv->fdidx[fd].priv = false;
269 	return true;
270 }
271 
272 /*
273  * Shutdown server
274  */
275 void
server_shutdown(server_t * srv)276 server_shutdown(server_t *srv)
277 {
278 	record_t *r;
279 	int	fd;
280 
281 	assert(srv != NULL);
282 
283 	while ((r = LIST_FIRST(&srv->rlist)) != NULL) {
284 		LIST_REMOVE(r, next);
285 		free(r);
286 	}
287 
288 	for (fd = 0; fd < srv->fdmax + 1; fd ++) {
289 		if (srv->fdidx[fd].valid)
290 			server_close_fd(srv, fd);
291 	}
292 
293 	free(srv->fdidx);
294 	free(srv->ctlbuf);
295 	free(srv->ibuf);
296 	free(srv->obuf);
297 
298 	memset(srv, 0, sizeof(*srv));
299 }
300 
301 /*
302  * Do one server iteration
303  */
304 bool
server_do(server_t * srv)305 server_do(server_t *srv)
306 {
307 	fd_set	fdset;
308 	int	n, fd;
309 
310 	assert(srv != NULL);
311 
312 	memcpy(&fdset, &srv->fdset, sizeof(fdset));
313 	n = select(srv->fdmax + 1, &fdset, NULL, NULL, NULL);
314 	if (n == -1) {
315 		if (errno == EINTR)
316 			return true;
317 
318 		log_err("Could not select(%d, %p). %s (%d)",
319 		    srv->fdmax + 1, &fdset, strerror(errno), errno);
320 
321 		return false;
322 	}
323 
324 	for (fd = 0; fd < srv->fdmax + 1 && n > 0; fd++) {
325 		if (!FD_ISSET(fd, &fdset))
326 			continue;
327 
328 		assert(srv->fdidx[fd].valid);
329 
330 		if (srv->fdidx[fd].server)
331 			server_accept_client(srv, fd);
332 		else if (!server_process_request(srv, fd))
333 			server_close_fd(srv, fd);
334 
335 		n--;
336 	}
337 
338 	return true;
339 
340 }
341 
342 /*
343  * Accept new client connection and register it with index
344  */
345 static void
server_accept_client(server_t * srv,int fd)346 server_accept_client(server_t *srv, int fd)
347 {
348 	struct sockaddr_bt	sa;
349 	socklen_t		len;
350 	int			cfd;
351 	uint16_t		omtu;
352 
353 	do {
354 		cfd = accept(fd, NULL, NULL);
355 	} while (cfd == -1 && errno == EINTR);
356 
357 	if (cfd == -1) {
358 		log_err("Could not accept connection on %s socket. %s (%d)",
359 		    srv->fdidx[fd].control ? "control" : "L2CAP",
360 		    strerror(errno), errno);
361 
362 		return;
363 	}
364 
365 	if (cfd >= FD_SETSIZE) {
366 		log_crit("File descriptor too large");
367 		close(cfd);
368 		return;
369 	}
370 
371 	assert(!FD_ISSET(cfd, &srv->fdset));
372 	assert(!srv->fdidx[cfd].valid);
373 
374 	memset(&sa, 0, sizeof(sa));
375 	omtu = srv->omtu;
376 
377 	if (!srv->fdidx[fd].control) {
378 		len = sizeof(sa);
379 		if (getsockname(cfd, (struct sockaddr *)&sa, &len) == -1)
380 			log_warning("getsockname failed, using BDADDR_ANY");
381 
382 		len = sizeof(omtu);
383 	        if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &len) == -1)
384 			log_warning("Could not get L2CAP OMTU, using %d", omtu);
385 		else
386 			omtu -= sizeof(sdp_pdu_t);
387 	}
388 
389 	/* Add client descriptor to the index */
390 	if (cfd > srv->fdmax)
391 		srv->fdmax = cfd;
392 
393 	FD_SET(cfd, &srv->fdset);
394 	srv->fdidx[cfd].valid = true;
395 	srv->fdidx[cfd].server = false;
396 	srv->fdidx[cfd].control = srv->fdidx[fd].control;
397 	srv->fdidx[cfd].priv = false;
398 	srv->fdidx[cfd].omtu = (omtu > srv->omtu) ? srv->omtu : omtu;
399 	srv->fdidx[cfd].offset = 0;
400 	bdaddr_copy(&srv->fdidx[cfd].bdaddr, &sa.bt_bdaddr);
401 
402 	log_debug("new %s client on fd#%d",
403 	    srv->fdidx[cfd].control ? "control" : "L2CAP", cfd);
404 }
405 
406 /*
407  * Process request from the client
408  */
409 static bool
server_process_request(server_t * srv,int fd)410 server_process_request(server_t *srv, int fd)
411 {
412 	struct msghdr	msg;
413 	struct iovec	iov[2];
414 	struct cmsghdr	*cmsg;
415 	ssize_t		len;
416 	uint16_t	error;
417 
418 	assert(FD_ISSET(fd, &srv->fdset));
419 	assert(srv->fdidx[fd].valid);
420 	assert(!srv->fdidx[fd].server);
421 
422 	iov[0].iov_base = &srv->pdu;
423 	iov[0].iov_len = sizeof(srv->pdu);
424 	iov[1].iov_base = srv->ibuf;
425 	iov[1].iov_len = srv->imtu;
426 
427 	msg.msg_name = NULL;
428 	msg.msg_namelen = 0;
429 	msg.msg_iov = iov;
430 	msg.msg_iovlen = __arraycount(iov);
431 	msg.msg_control = srv->ctlbuf;
432 	msg.msg_controllen = srv->ctllen;
433 	msg.msg_flags = 0;
434 
435 	do {
436 		len = recvmsg(fd, &msg, 0);
437 	} while (len == -1 && errno == EINTR);
438 
439 	if (len == -1) {
440 		log_err("Could not receive SDP request on %s socket. %s (%d)",
441 		    srv->fdidx[fd].control ? "control" : "L2CAP",
442 		    strerror(errno), errno);
443 
444 		return false;
445 	}
446 
447 	if (len == 0) {
448 		log_info("Client on %s socket has disconnected",
449 		    srv->fdidx[fd].control ? "control" : "L2CAP");
450 
451 		return false;
452 	}
453 
454 	if (msg.msg_flags & MSG_TRUNC)
455 		log_info("Truncated message on %s socket",
456 		    srv->fdidx[fd].control ? "control" : "L2CAP");
457 
458 	if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
459 	    && cmsg->cmsg_level == SOL_SOCKET
460 	    && cmsg->cmsg_type == SCM_CREDS
461 	    && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0)))
462 		srv->fdidx[fd].priv = server_auth_check(srv, CMSG_DATA(cmsg));
463 
464 	srv->pdu.len = be16toh(srv->pdu.len);
465 
466 	if ((uint32_t)len < sizeof(srv->pdu)
467 	    || (uint32_t)len != sizeof(srv->pdu) + srv->pdu.len) {
468 		error = SDP_ERROR_CODE_INVALID_PDU_SIZE;
469 	} else {
470 		switch (srv->pdu.pid) {
471 		case SDP_PDU_SERVICE_SEARCH_REQUEST:
472 			error = service_search_request(srv, fd);
473 			break;
474 
475 		case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
476 			error = service_attribute_request(srv, fd);
477 			break;
478 
479 		case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
480 			error = service_search_attribute_request(srv, fd);
481 			break;
482 
483 #ifdef SDP_COMPAT
484 		case SDP_PDU_SERVICE_REGISTER_REQUEST:
485 			error = compat_register_request(srv, fd);
486 			break;
487 
488 		case SDP_PDU_SERVICE_CHANGE_REQUEST:
489 			error = compat_change_request(srv, fd);
490 			break;
491 #endif
492 
493 		case SDP_PDU_RECORD_INSERT_REQUEST:
494 			error = record_insert_request(srv, fd);
495 			break;
496 
497 		case SDP_PDU_RECORD_UPDATE_REQUEST:
498 			error = record_update_request(srv, fd);
499 			break;
500 
501 		case SDP_PDU_RECORD_REMOVE_REQUEST:
502 			error = record_remove_request(srv, fd);
503 			break;
504 
505 		default:
506 			error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
507 			break;
508 		}
509 	}
510 
511 	if (error != 0) {
512 		srv->fdidx[fd].offset = 0;
513 		db_unselect(srv, fd);
514 		srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
515 		srv->pdu.len = sizeof(error);
516 		be16enc(srv->obuf, error);
517 		log_debug("sending ErrorResponse (error=0x%04x)", error);
518 	}
519 
520 	iov[0].iov_base = &srv->pdu;
521 	iov[0].iov_len = sizeof(srv->pdu);
522 	iov[1].iov_base = srv->obuf;
523 	iov[1].iov_len = srv->pdu.len;
524 
525 	srv->pdu.len = htobe16(srv->pdu.len);
526 
527 	msg.msg_name = NULL;
528 	msg.msg_namelen = 0;
529 	msg.msg_iov = iov;
530 	msg.msg_iovlen = __arraycount(iov);
531 	msg.msg_control = NULL;
532 	msg.msg_controllen = 0;
533 	msg.msg_flags = 0;
534 
535 	do {
536 		len = sendmsg(fd, &msg, 0);
537 	} while (len == -1 && errno == EINTR);
538 
539 	if (len == -1) {
540 		log_err("Could not send SDP response on %s socket. %s (%d)",
541 		    srv->fdidx[fd].control ? "control" : "L2CAP",
542 		    strerror(errno), errno);
543 
544 		return false;
545 	}
546 
547 	return true;
548 }
549 
550 /*
551  * Close descriptor and remove it from index
552  */
553 static void
server_close_fd(server_t * srv,int fd)554 server_close_fd(server_t *srv, int fd)
555 {
556 
557 	assert(FD_ISSET(fd, &srv->fdset));
558 	assert(srv->fdidx[fd].valid);
559 
560 	db_unselect(srv, fd);	/* release selected records */
561 	db_release(srv, fd);	/* expire owned records */
562 
563 	close(fd);
564 	FD_CLR(fd, &srv->fdset);
565 	srv->fdidx[fd].valid = false;
566 
567 	log_debug("client on fd#%d closed", fd);
568 
569 	if (fd == srv->fdmax) {
570 		while (fd > 0 && !srv->fdidx[fd].valid)
571 			fd--;
572 
573 		srv->fdmax = fd;
574 	}
575 }
576 
577 /*
578  * check credentials, return true when permitted to modify service records
579  */
580 static bool
server_auth_check(server_t * srv,void * data)581 server_auth_check(server_t *srv, void *data)
582 {
583 	struct sockcred *cred = data;
584 	struct group *grp;
585 	int n;
586 
587 	if (cred == NULL)
588 		return false;
589 
590 	if (cred->sc_uid == 0 || cred->sc_euid == 0)
591 		return true;
592 
593 	if (srv->sgroup == NULL)
594 		return false;
595 
596 	grp = getgrnam(srv->sgroup);
597 	if (grp == NULL) {
598 		log_err("No gid for group '%s'", srv->sgroup);
599 		srv->sgroup = NULL;
600 		return false;
601 	}
602 
603 	if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid)
604 		return true;
605 
606 	if (cred->sc_ngroups > MAX_GROUPS) {
607 		log_info("Credentials truncated, lost %d groups",
608 		    MAX_GROUPS - cred->sc_ngroups);
609 
610 		cred->sc_ngroups = MAX_GROUPS;
611 	}
612 
613 	for (n = 0 ; n < cred->sc_ngroups ; n++) {
614 		if (cred->sc_groups[n] == grp->gr_gid)
615 			return true;
616 	}
617 
618 	return false;
619 }
620