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