Home | History | Annotate | Line # | Download | only in sdpd
server.c revision 1.8
      1  1.8   plunky /*	$NetBSD: server.c,v 1.8 2010/03/07 10:58:40 plunky 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.7   plunky /*-
     32  1.7   plunky  * 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.8   plunky __RCSID("$NetBSD: server.c,v 1.8 2010/03/07 10:58:40 plunky 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.7   plunky 
     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.7   plunky 
     79  1.7   plunky #include "sdpd.h"
     80  1.7   plunky 
     81  1.7   plunky static bool	server_open_control	(server_t *, char const *);
     82  1.7   plunky static bool	server_open_l2cap	(server_t *);
     83  1.7   plunky static void	server_accept_client	(server_t *, int);
     84  1.7   plunky static bool	server_process_request	(server_t *, int);
     85  1.7   plunky static void	server_close_fd		(server_t *, int);
     86  1.7   plunky static bool	server_auth_check	(server_t *, void *);
     87  1.7   plunky 
     88  1.7   plunky /* number of groups we allocate space for in cmsg */
     89  1.7   plunky #define MAX_GROUPS	20
     90  1.1  gdamore 
     91  1.1  gdamore /*
     92  1.1  gdamore  * Initialize server
     93  1.1  gdamore  */
     94  1.7   plunky bool
     95  1.7   plunky 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.7   plunky 	FD_ZERO(&srv->fdset);
    103  1.3   plunky 	srv->sgroup = sgroup;
    104  1.1  gdamore 
    105  1.7   plunky 	srv->fdmax = -1;
    106  1.7   plunky 	srv->fdidx = calloc(FD_SETSIZE, sizeof(fd_idx_t));
    107  1.7   plunky 	if (srv->fdidx == NULL) {
    108  1.7   plunky 		log_crit("Failed to allocate fd index");
    109  1.7   plunky 		goto fail;
    110  1.7   plunky 	}
    111  1.7   plunky 
    112  1.7   plunky 	srv->ctllen = CMSG_SPACE(SOCKCREDSIZE(MAX_GROUPS));
    113  1.7   plunky 	srv->ctlbuf = malloc(srv->ctllen);
    114  1.7   plunky 	if (srv->ctlbuf == NULL) {
    115  1.7   plunky 		log_crit("Malloc cmsg buffer (len=%d) failed.", srv->ctllen);
    116  1.7   plunky 		goto fail;
    117  1.7   plunky 	}
    118  1.7   plunky 
    119  1.7   plunky 	srv->imtu = SDP_LOCAL_MTU - sizeof(sdp_pdu_t);
    120  1.7   plunky 	srv->ibuf = malloc(srv->imtu);
    121  1.7   plunky 	if (srv->ibuf == NULL) {
    122  1.7   plunky 		log_crit("Malloc input buffer (imtu=%d) failed.", srv->imtu);
    123  1.7   plunky 		goto fail;
    124  1.7   plunky 	}
    125  1.7   plunky 
    126  1.7   plunky 	srv->omtu = L2CAP_MTU_DEFAULT - sizeof(sdp_pdu_t);
    127  1.7   plunky 	srv->obuf = malloc(srv->omtu);
    128  1.7   plunky 	if (srv->obuf == NULL) {
    129  1.7   plunky 		log_crit("Malloc output buffer (omtu=%d) failed.", srv->omtu);
    130  1.7   plunky 		goto fail;
    131  1.7   plunky 	}
    132  1.7   plunky 
    133  1.7   plunky 	if (db_init(srv)
    134  1.7   plunky 	    && server_open_control(srv, control)
    135  1.7   plunky 	    && server_open_l2cap(srv))
    136  1.7   plunky 		return true;
    137  1.7   plunky 
    138  1.7   plunky fail:
    139  1.7   plunky 	server_shutdown(srv);
    140  1.7   plunky 	return false;
    141  1.7   plunky }
    142  1.7   plunky 
    143  1.7   plunky /*
    144  1.7   plunky  * Open local control socket
    145  1.7   plunky  */
    146  1.7   plunky static bool
    147  1.7   plunky server_open_control(server_t *srv, char const *control)
    148  1.7   plunky {
    149  1.7   plunky 	struct sockaddr_un	un;
    150  1.7   plunky 	int			opt, fd;
    151  1.7   plunky 
    152  1.7   plunky 	if (unlink(control) == -1 && errno != ENOENT) {
    153  1.1  gdamore 		log_crit("Could not unlink(%s). %s (%d)",
    154  1.7   plunky 		    control, strerror(errno), errno);
    155  1.7   plunky 
    156  1.7   plunky 		return false;
    157  1.1  gdamore 	}
    158  1.1  gdamore 
    159  1.7   plunky 	fd = socket(PF_LOCAL, SOCK_STREAM, 0);
    160  1.7   plunky 	if (fd == -1) {
    161  1.1  gdamore 		log_crit("Could not create control socket. %s (%d)",
    162  1.7   plunky 		    strerror(errno), errno);
    163  1.7   plunky 
    164  1.7   plunky 		return false;
    165  1.1  gdamore 	}
    166  1.1  gdamore 
    167  1.1  gdamore 	opt = 1;
    168  1.7   plunky 	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.7   plunky 	if (bind(fd, (struct sockaddr *) &un, sizeof(un)) == -1) {
    177  1.1  gdamore 		log_crit("Could not bind control socket. %s (%d)",
    178  1.7   plunky 		    strerror(errno), errno);
    179  1.7   plunky 
    180  1.7   plunky 		close(fd);
    181  1.7   plunky 		return false;
    182  1.1  gdamore 	}
    183  1.1  gdamore 
    184  1.7   plunky 	if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) {
    185  1.7   plunky 		log_crit("Could not set permissions on control socket. %s (%d)",
    186  1.7   plunky 		    strerror(errno), errno);
    187  1.7   plunky 
    188  1.7   plunky 		close(fd);
    189  1.7   plunky 		return false;
    190  1.1  gdamore 	}
    191  1.1  gdamore 
    192  1.7   plunky 	if (listen(fd, 5) == -1) {
    193  1.1  gdamore 		log_crit("Could not listen on control socket. %s (%d)",
    194  1.7   plunky 		    strerror(errno), errno);
    195  1.7   plunky 
    196  1.7   plunky 		close(fd);
    197  1.7   plunky 		return false;
    198  1.1  gdamore 	}
    199  1.1  gdamore 
    200  1.7   plunky 	/* Add control descriptor to index */
    201  1.7   plunky 	if (fd > srv->fdmax)
    202  1.7   plunky 		srv->fdmax = fd;
    203  1.7   plunky 
    204  1.7   plunky 	FD_SET(fd, &srv->fdset);
    205  1.7   plunky 	srv->fdidx[fd].valid = true;
    206  1.7   plunky 	srv->fdidx[fd].server = true;
    207  1.7   plunky 	srv->fdidx[fd].control = true;
    208  1.7   plunky 	srv->fdidx[fd].priv = false;
    209  1.7   plunky 	return true;
    210  1.7   plunky }
    211  1.7   plunky 
    212  1.7   plunky /*
    213  1.7   plunky  * Open L2CAP server socket
    214  1.7   plunky  */
    215  1.7   plunky static bool
    216  1.7   plunky server_open_l2cap(server_t *srv)
    217  1.7   plunky {
    218  1.7   plunky 	struct sockaddr_bt	sa;
    219  1.7   plunky 	int			fd;
    220  1.7   plunky 
    221  1.7   plunky 	fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
    222  1.7   plunky 	if (fd == -1) {
    223  1.1  gdamore 		log_crit("Could not create L2CAP socket. %s (%d)",
    224  1.7   plunky 		    strerror(errno), errno);
    225  1.7   plunky 
    226  1.7   plunky 		return false;
    227  1.1  gdamore 	}
    228  1.1  gdamore 
    229  1.7   plunky         if (setsockopt(fd, BTPROTO_L2CAP, SO_L2CAP_IMTU,
    230  1.7   plunky 	    &srv->imtu, sizeof(srv->imtu)) == -1) {
    231  1.7   plunky 		log_crit("Could not set L2CAP Incoming MTU. %s (%d)",
    232  1.7   plunky 		    strerror(errno), errno);
    233  1.7   plunky 
    234  1.7   plunky 		close(fd);
    235  1.7   plunky 		return false;
    236  1.1  gdamore         }
    237  1.1  gdamore 
    238  1.7   plunky 	memset(&sa, 0, sizeof(sa));
    239  1.7   plunky 	sa.bt_len = sizeof(sa);
    240  1.7   plunky 	sa.bt_family = AF_BLUETOOTH;
    241  1.7   plunky 	sa.bt_psm = L2CAP_PSM_SDP;
    242  1.7   plunky 	bdaddr_copy(&sa.bt_bdaddr, BDADDR_ANY);
    243  1.1  gdamore 
    244  1.7   plunky 	if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
    245  1.1  gdamore 		log_crit("Could not bind L2CAP socket. %s (%d)",
    246  1.7   plunky 		    strerror(errno), errno);
    247  1.7   plunky 
    248  1.7   plunky 		close(fd);
    249  1.7   plunky 		return false;
    250  1.1  gdamore 	}
    251  1.1  gdamore 
    252  1.7   plunky 	if (listen(fd, 5) == -1) {
    253  1.1  gdamore 		log_crit("Could not listen on L2CAP socket. %s (%d)",
    254  1.7   plunky 		    strerror(errno), errno);
    255  1.7   plunky 
    256  1.7   plunky 		close(fd);
    257  1.7   plunky 		return false;
    258  1.1  gdamore 	}
    259  1.1  gdamore 
    260  1.7   plunky 	/* Add L2CAP descriptor to index */
    261  1.7   plunky 	if (fd > srv->fdmax)
    262  1.7   plunky 		srv->fdmax = fd;
    263  1.7   plunky 
    264  1.7   plunky 	FD_SET(fd, &srv->fdset);
    265  1.7   plunky 	srv->fdidx[fd].valid = true;
    266  1.7   plunky 	srv->fdidx[fd].server = true;
    267  1.7   plunky 	srv->fdidx[fd].control = false;
    268  1.7   plunky 	srv->fdidx[fd].priv = false;
    269  1.7   plunky 	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.7   plunky server_shutdown(server_t *srv)
    277  1.1  gdamore {
    278  1.7   plunky 	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.7   plunky 	while ((r = LIST_FIRST(&srv->rlist)) != NULL) {
    284  1.7   plunky 		LIST_REMOVE(r, next);
    285  1.7   plunky 		free(r);
    286  1.7   plunky 	}
    287  1.7   plunky 
    288  1.7   plunky 	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.7   plunky 	}
    292  1.1  gdamore 
    293  1.1  gdamore 	free(srv->fdidx);
    294  1.7   plunky 	free(srv->ctlbuf);
    295  1.7   plunky 	free(srv->ibuf);
    296  1.7   plunky 	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.7   plunky bool
    305  1.7   plunky server_do(server_t *srv)
    306  1.1  gdamore {
    307  1.1  gdamore 	fd_set	fdset;
    308  1.7   plunky 	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.7   plunky 	n = select(srv->fdmax + 1, &fdset, NULL, NULL, NULL);
    314  1.7   plunky 	if (n == -1) {
    315  1.1  gdamore 		if (errno == EINTR)
    316  1.7   plunky 			return true;
    317  1.1  gdamore 
    318  1.1  gdamore 		log_err("Could not select(%d, %p). %s (%d)",
    319  1.7   plunky 		    srv->fdmax + 1, &fdset, strerror(errno), errno);
    320  1.1  gdamore 
    321  1.7   plunky 		return false;
    322  1.1  gdamore 	}
    323  1.1  gdamore 
    324  1.7   plunky 	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.7   plunky 		else if (!server_process_request(srv, fd))
    333  1.1  gdamore 			server_close_fd(srv, fd);
    334  1.7   plunky 
    335  1.7   plunky 		n--;
    336  1.1  gdamore 	}
    337  1.1  gdamore 
    338  1.7   plunky 	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.7   plunky server_accept_client(server_t *srv, int fd)
    347  1.1  gdamore {
    348  1.7   plunky 	struct sockaddr_bt	sa;
    349  1.7   plunky 	socklen_t		len;
    350  1.7   plunky 	int			cfd;
    351  1.7   plunky 	uint16_t		omtu;
    352  1.1  gdamore 
    353  1.1  gdamore 	do {
    354  1.1  gdamore 		cfd = accept(fd, NULL, NULL);
    355  1.7   plunky 	} while (cfd == -1 && errno == EINTR);
    356  1.1  gdamore 
    357  1.7   plunky 	if (cfd == -1) {
    358  1.1  gdamore 		log_err("Could not accept connection on %s socket. %s (%d)",
    359  1.7   plunky 		    srv->fdidx[fd].control ? "control" : "L2CAP",
    360  1.7   plunky 		    strerror(errno), errno);
    361  1.7   plunky 
    362  1.7   plunky 		return;
    363  1.7   plunky 	}
    364  1.7   plunky 
    365  1.7   plunky 	if (cfd >= FD_SETSIZE) {
    366  1.7   plunky 		log_crit("File descriptor too large");
    367  1.7   plunky 		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.7   plunky 	memset(&sa, 0, sizeof(sa));
    375  1.7   plunky 	omtu = srv->omtu;
    376  1.7   plunky 
    377  1.1  gdamore 	if (!srv->fdidx[fd].control) {
    378  1.7   plunky 		len = sizeof(sa);
    379  1.7   plunky 		if (getsockname(cfd, (struct sockaddr *)&sa, &len) == -1)
    380  1.7   plunky 			log_warning("getsockname failed, using BDADDR_ANY");
    381  1.7   plunky 
    382  1.7   plunky 		len = sizeof(omtu);
    383  1.7   plunky 	        if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &len) == -1)
    384  1.7   plunky 			log_warning("Could not get L2CAP OMTU, using %d", omtu);
    385  1.7   plunky 		else
    386  1.7   plunky 			omtu -= sizeof(sdp_pdu_t);
    387  1.1  gdamore 	}
    388  1.1  gdamore 
    389  1.7   plunky 	/* Add client descriptor to the index */
    390  1.7   plunky 	if (cfd > srv->fdmax)
    391  1.7   plunky 		srv->fdmax = cfd;
    392  1.1  gdamore 
    393  1.1  gdamore 	FD_SET(cfd, &srv->fdset);
    394  1.7   plunky 	srv->fdidx[cfd].valid = true;
    395  1.7   plunky 	srv->fdidx[cfd].server = false;
    396  1.1  gdamore 	srv->fdidx[cfd].control = srv->fdidx[fd].control;
    397  1.7   plunky 	srv->fdidx[cfd].priv = false;
    398  1.7   plunky 	srv->fdidx[cfd].omtu = (omtu > srv->omtu) ? srv->omtu : omtu;
    399  1.7   plunky 	srv->fdidx[cfd].offset = 0;
    400  1.7   plunky 	bdaddr_copy(&srv->fdidx[cfd].bdaddr, &sa.bt_bdaddr);
    401  1.8   plunky 
    402  1.8   plunky 	log_debug("new %s client on fd#%d",
    403  1.8   plunky 	    srv->fdidx[cfd].control ? "control" : "L2CAP", cfd);
    404  1.1  gdamore }
    405  1.1  gdamore 
    406  1.1  gdamore /*
    407  1.1  gdamore  * Process request from the client
    408  1.1  gdamore  */
    409  1.7   plunky static bool
    410  1.7   plunky server_process_request(server_t *srv, int fd)
    411  1.1  gdamore {
    412  1.1  gdamore 	struct msghdr	msg;
    413  1.7   plunky 	struct iovec	iov[2];
    414  1.1  gdamore 	struct cmsghdr	*cmsg;
    415  1.7   plunky 	ssize_t		len;
    416  1.7   plunky 	uint16_t	error;
    417  1.1  gdamore 
    418  1.1  gdamore 	assert(FD_ISSET(fd, &srv->fdset));
    419  1.1  gdamore 	assert(srv->fdidx[fd].valid);
    420  1.1  gdamore 	assert(!srv->fdidx[fd].server);
    421  1.1  gdamore 
    422  1.7   plunky 	iov[0].iov_base = &srv->pdu;
    423  1.7   plunky 	iov[0].iov_len = sizeof(srv->pdu);
    424  1.7   plunky 	iov[1].iov_base = srv->ibuf;
    425  1.7   plunky 	iov[1].iov_len = srv->imtu;
    426  1.1  gdamore 
    427  1.1  gdamore 	msg.msg_name = NULL;
    428  1.1  gdamore 	msg.msg_namelen = 0;
    429  1.7   plunky 	msg.msg_iov = iov;
    430  1.7   plunky 	msg.msg_iovlen = __arraycount(iov);
    431  1.7   plunky 	msg.msg_control = srv->ctlbuf;
    432  1.7   plunky 	msg.msg_controllen = srv->ctllen;
    433  1.1  gdamore 	msg.msg_flags = 0;
    434  1.1  gdamore 
    435  1.1  gdamore 	do {
    436  1.1  gdamore 		len = recvmsg(fd, &msg, 0);
    437  1.7   plunky 	} while (len == -1 && errno == EINTR);
    438  1.7   plunky 
    439  1.7   plunky 	if (len == -1) {
    440  1.7   plunky 		log_err("Could not receive SDP request on %s socket. %s (%d)",
    441  1.7   plunky 		    srv->fdidx[fd].control ? "control" : "L2CAP",
    442  1.7   plunky 		    strerror(errno), errno);
    443  1.1  gdamore 
    444  1.7   plunky 		return false;
    445  1.1  gdamore 	}
    446  1.7   plunky 
    447  1.1  gdamore 	if (len == 0) {
    448  1.1  gdamore 		log_info("Client on %s socket has disconnected",
    449  1.7   plunky 		    srv->fdidx[fd].control ? "control" : "L2CAP");
    450  1.7   plunky 
    451  1.7   plunky 		return false;
    452  1.1  gdamore 	}
    453  1.1  gdamore 
    454  1.7   plunky 	if (msg.msg_flags & MSG_TRUNC)
    455  1.7   plunky 		log_info("Truncated message on %s socket",
    456  1.7   plunky 		    srv->fdidx[fd].control ? "control" : "L2CAP");
    457  1.5   plunky 
    458  1.7   plunky 	if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
    459  1.1  gdamore 	    && cmsg->cmsg_level == SOL_SOCKET
    460  1.1  gdamore 	    && cmsg->cmsg_type == SCM_CREDS
    461  1.3   plunky 	    && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0)))
    462  1.7   plunky 		srv->fdidx[fd].priv = server_auth_check(srv, CMSG_DATA(cmsg));
    463  1.2   plunky 
    464  1.7   plunky 	srv->pdu.len = be16toh(srv->pdu.len);
    465  1.7   plunky 
    466  1.7   plunky 	if ((uint32_t)len < sizeof(srv->pdu)
    467  1.7   plunky 	    || (uint32_t)len != sizeof(srv->pdu) + srv->pdu.len) {
    468  1.7   plunky 		error = SDP_ERROR_CODE_INVALID_PDU_SIZE;
    469  1.7   plunky 	} else {
    470  1.7   plunky 		switch (srv->pdu.pid) {
    471  1.1  gdamore 		case SDP_PDU_SERVICE_SEARCH_REQUEST:
    472  1.7   plunky 			error = service_search_request(srv, fd);
    473  1.1  gdamore 			break;
    474  1.1  gdamore 
    475  1.1  gdamore 		case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
    476  1.7   plunky 			error = service_attribute_request(srv, fd);
    477  1.1  gdamore 			break;
    478  1.1  gdamore 
    479  1.1  gdamore 		case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
    480  1.7   plunky 			error = service_search_attribute_request(srv, fd);
    481  1.1  gdamore 			break;
    482  1.1  gdamore 
    483  1.7   plunky #ifdef SDP_COMPAT
    484  1.1  gdamore 		case SDP_PDU_SERVICE_REGISTER_REQUEST:
    485  1.7   plunky 			error = compat_register_request(srv, fd);
    486  1.1  gdamore 			break;
    487  1.1  gdamore 
    488  1.1  gdamore 		case SDP_PDU_SERVICE_CHANGE_REQUEST:
    489  1.7   plunky 			error = compat_change_request(srv, fd);
    490  1.1  gdamore 			break;
    491  1.7   plunky #endif
    492  1.1  gdamore 
    493  1.7   plunky 		case SDP_PDU_RECORD_INSERT_REQUEST:
    494  1.7   plunky 			error = record_insert_request(srv, fd);
    495  1.1  gdamore 			break;
    496  1.1  gdamore 
    497  1.7   plunky 		case SDP_PDU_RECORD_UPDATE_REQUEST:
    498  1.7   plunky 			error = record_update_request(srv, fd);
    499  1.1  gdamore 			break;
    500  1.1  gdamore 
    501  1.7   plunky 		case SDP_PDU_RECORD_REMOVE_REQUEST:
    502  1.7   plunky 			error = record_remove_request(srv, fd);
    503  1.1  gdamore 			break;
    504  1.1  gdamore 
    505  1.1  gdamore 		default:
    506  1.1  gdamore 			error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    507  1.1  gdamore 			break;
    508  1.1  gdamore 		}
    509  1.1  gdamore 	}
    510  1.1  gdamore 
    511  1.1  gdamore 	if (error != 0) {
    512  1.7   plunky 		srv->fdidx[fd].offset = 0;
    513  1.7   plunky 		db_unselect(srv, fd);
    514  1.7   plunky 		srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
    515  1.7   plunky 		srv->pdu.len = sizeof(error);
    516  1.7   plunky 		be16enc(srv->obuf, error);
    517  1.8   plunky 		log_debug("sending ErrorResponse (error=0x%04x)", error);
    518  1.1  gdamore 	}
    519  1.1  gdamore 
    520  1.7   plunky 	iov[0].iov_base = &srv->pdu;
    521  1.7   plunky 	iov[0].iov_len = sizeof(srv->pdu);
    522  1.7   plunky 	iov[1].iov_base = srv->obuf;
    523  1.7   plunky 	iov[1].iov_len = srv->pdu.len;
    524  1.7   plunky 
    525  1.7   plunky 	srv->pdu.len = htobe16(srv->pdu.len);
    526  1.1  gdamore 
    527  1.7   plunky 	msg.msg_name = NULL;
    528  1.7   plunky 	msg.msg_namelen = 0;
    529  1.7   plunky 	msg.msg_iov = iov;
    530  1.7   plunky 	msg.msg_iovlen = __arraycount(iov);
    531  1.7   plunky 	msg.msg_control = NULL;
    532  1.7   plunky 	msg.msg_controllen = 0;
    533  1.7   plunky 	msg.msg_flags = 0;
    534  1.1  gdamore 
    535  1.7   plunky 	do {
    536  1.7   plunky 		len = sendmsg(fd, &msg, 0);
    537  1.7   plunky 	} while (len == -1 && errno == EINTR);
    538  1.1  gdamore 
    539  1.7   plunky 	if (len == -1) {
    540  1.7   plunky 		log_err("Could not send SDP response on %s socket. %s (%d)",
    541  1.7   plunky 		    srv->fdidx[fd].control ? "control" : "L2CAP",
    542  1.7   plunky 		    strerror(errno), errno);
    543  1.1  gdamore 
    544  1.7   plunky 		return false;
    545  1.7   plunky 	}
    546  1.1  gdamore 
    547  1.7   plunky 	return true;
    548  1.1  gdamore }
    549  1.1  gdamore 
    550  1.1  gdamore /*
    551  1.1  gdamore  * Close descriptor and remove it from index
    552  1.1  gdamore  */
    553  1.1  gdamore static void
    554  1.7   plunky server_close_fd(server_t *srv, int fd)
    555  1.1  gdamore {
    556  1.1  gdamore 
    557  1.1  gdamore 	assert(FD_ISSET(fd, &srv->fdset));
    558  1.1  gdamore 	assert(srv->fdidx[fd].valid);
    559  1.1  gdamore 
    560  1.7   plunky 	db_unselect(srv, fd);	/* release selected records */
    561  1.7   plunky 	db_release(srv, fd);	/* expire owned records */
    562  1.7   plunky 
    563  1.1  gdamore 	close(fd);
    564  1.1  gdamore 	FD_CLR(fd, &srv->fdset);
    565  1.7   plunky 	srv->fdidx[fd].valid = false;
    566  1.1  gdamore 
    567  1.7   plunky 	if (fd == srv->fdmax) {
    568  1.7   plunky 		while (fd > 0 && !srv->fdidx[fd].valid)
    569  1.7   plunky 			fd--;
    570  1.1  gdamore 
    571  1.7   plunky 		srv->fdmax = fd;
    572  1.1  gdamore 	}
    573  1.8   plunky 
    574  1.8   plunky 	log_debug("client on fd#%d closed", fd);
    575  1.1  gdamore }
    576  1.3   plunky 
    577  1.7   plunky /*
    578  1.7   plunky  * check credentials, return true when permitted to modify service records
    579  1.7   plunky  */
    580  1.7   plunky static bool
    581  1.7   plunky server_auth_check(server_t *srv, void *data)
    582  1.3   plunky {
    583  1.7   plunky 	struct sockcred *cred = data;
    584  1.3   plunky 	struct group *grp;
    585  1.3   plunky 	int n;
    586  1.3   plunky 
    587  1.3   plunky 	if (cred == NULL)
    588  1.7   plunky 		return false;
    589  1.3   plunky 
    590  1.3   plunky 	if (cred->sc_uid == 0 || cred->sc_euid == 0)
    591  1.7   plunky 		return true;
    592  1.3   plunky 
    593  1.3   plunky 	if (srv->sgroup == NULL)
    594  1.7   plunky 		return false;
    595  1.3   plunky 
    596  1.3   plunky 	grp = getgrnam(srv->sgroup);
    597  1.3   plunky 	if (grp == NULL) {
    598  1.3   plunky 		log_err("No gid for group '%s'", srv->sgroup);
    599  1.3   plunky 		srv->sgroup = NULL;
    600  1.7   plunky 		return false;
    601  1.3   plunky 	}
    602  1.3   plunky 
    603  1.3   plunky 	if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid)
    604  1.7   plunky 		return true;
    605  1.7   plunky 
    606  1.7   plunky 	if (cred->sc_ngroups > MAX_GROUPS) {
    607  1.7   plunky 		log_info("Credentials truncated, lost %d groups",
    608  1.7   plunky 		    MAX_GROUPS - cred->sc_ngroups);
    609  1.7   plunky 
    610  1.7   plunky 		cred->sc_ngroups = MAX_GROUPS;
    611  1.7   plunky 	}
    612  1.3   plunky 
    613  1.3   plunky 	for (n = 0 ; n < cred->sc_ngroups ; n++) {
    614  1.3   plunky 		if (cred->sc_groups[n] == grp->gr_gid)
    615  1.7   plunky 			return true;
    616  1.3   plunky 	}
    617  1.3   plunky 
    618  1.7   plunky 	return false;
    619  1.3   plunky }
    620