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