1 /* $NetBSD: server.c,v 1.6 2009/04/18 13:53:59 lukem Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
32 * Copyright (c) 2009 The NetBSD Foundation, Inc.
33 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
57 * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $
60 #include <sys/cdefs.h>
61 __RCSID("$NetBSD: server.c,v 1.6 2009/04/18 13:53:59 lukem Exp $");
63 #include <sys/select.h>
65 #include <sys/ucred.h>
69 #include <bluetooth.h>
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 *);
88 /* number of groups we allocate space for in cmsg */
95 server_init(server_t
*srv
, char const *control
, char const *sgroup
)
99 assert(control
!= NULL
);
101 memset(srv
, 0, sizeof(srv
));
102 FD_ZERO(&srv
->fdset
);
103 srv
->sgroup
= sgroup
;
106 srv
->fdidx
= calloc(FD_SETSIZE
, sizeof(fd_idx_t
));
107 if (srv
->fdidx
== NULL
) {
108 log_crit("Failed to allocate fd index");
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=%d) failed.", srv
->ctllen
);
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
);
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
);
134 && server_open_control(srv
, control
)
135 && server_open_l2cap(srv
))
139 server_shutdown(srv
);
144 * Open local control socket
147 server_open_control(server_t
*srv
, char const *control
)
149 struct sockaddr_un un
;
152 if (unlink(control
) == -1 && errno
!= ENOENT
) {
153 log_crit("Could not unlink(%s). %s (%d)",
154 control
, strerror(errno
), errno
);
159 fd
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
161 log_crit("Could not create control socket. %s (%d)",
162 strerror(errno
), errno
);
168 if (setsockopt(fd
, 0, LOCAL_CREDS
, &opt
, sizeof(opt
)) == -1)
169 log_crit("Warning: No credential checks on control socket");
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
));
176 if (bind(fd
, (struct sockaddr
*) &un
, sizeof(un
)) == -1) {
177 log_crit("Could not bind control socket. %s (%d)",
178 strerror(errno
), errno
);
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
);
192 if (listen(fd
, 5) == -1) {
193 log_crit("Could not listen on control socket. %s (%d)",
194 strerror(errno
), errno
);
200 /* Add control descriptor to index */
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;
213 * Open L2CAP server socket
216 server_open_l2cap(server_t
*srv
)
218 struct sockaddr_bt sa
;
221 fd
= socket(PF_BLUETOOTH
, SOCK_SEQPACKET
, BTPROTO_L2CAP
);
223 log_crit("Could not create L2CAP socket. %s (%d)",
224 strerror(errno
), errno
);
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
);
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
);
244 if (bind(fd
, (struct sockaddr
*) &sa
, sizeof(sa
)) == -1) {
245 log_crit("Could not bind L2CAP socket. %s (%d)",
246 strerror(errno
), errno
);
252 if (listen(fd
, 5) == -1) {
253 log_crit("Could not listen on L2CAP socket. %s (%d)",
254 strerror(errno
), errno
);
260 /* Add L2CAP descriptor to index */
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;
276 server_shutdown(server_t
*srv
)
283 while ((r
= LIST_FIRST(&srv
->rlist
)) != NULL
) {
284 LIST_REMOVE(r
, next
);
288 for (fd
= 0; fd
< srv
->fdmax
+ 1; fd
++) {
289 if (srv
->fdidx
[fd
].valid
)
290 server_close_fd(srv
, fd
);
298 memset(srv
, 0, sizeof(*srv
));
302 * Do one server iteration
305 server_do(server_t
*srv
)
312 memcpy(&fdset
, &srv
->fdset
, sizeof(fdset
));
313 n
= select(srv
->fdmax
+ 1, &fdset
, NULL
, NULL
, NULL
);
318 log_err("Could not select(%d, %p). %s (%d)",
319 srv
->fdmax
+ 1, &fdset
, strerror(errno
), errno
);
324 for (fd
= 0; fd
< srv
->fdmax
+ 1 && n
> 0; fd
++) {
325 if (!FD_ISSET(fd
, &fdset
))
328 assert(srv
->fdidx
[fd
].valid
);
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
);
343 * Accept new client connection and register it with index
346 server_accept_client(server_t
*srv
, int fd
)
348 struct sockaddr_bt sa
;
354 cfd
= accept(fd
, NULL
, NULL
);
355 } while (cfd
== -1 && errno
== EINTR
);
358 log_err("Could not accept connection on %s socket. %s (%d)",
359 srv
->fdidx
[fd
].control
? "control" : "L2CAP",
360 strerror(errno
), errno
);
365 if (cfd
>= FD_SETSIZE
) {
366 log_crit("File descriptor too large");
371 assert(!FD_ISSET(cfd
, &srv
->fdset
));
372 assert(!srv
->fdidx
[cfd
].valid
);
374 memset(&sa
, 0, sizeof(sa
));
377 if (!srv
->fdidx
[fd
].control
) {
379 if (getsockname(cfd
, (struct sockaddr
*)&sa
, &len
) == -1)
380 log_warning("getsockname failed, using BDADDR_ANY");
383 if (getsockopt(cfd
, BTPROTO_L2CAP
, SO_L2CAP_OMTU
, &omtu
, &len
) == -1)
384 log_warning("Could not get L2CAP OMTU, using %d", omtu
);
386 omtu
-= sizeof(sdp_pdu_t
);
389 /* Add client descriptor to the index */
390 if (cfd
> srv
->fdmax
)
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
);
404 * Process request from the client
407 server_process_request(server_t
*srv
, int fd
)
411 struct cmsghdr
*cmsg
;
415 assert(FD_ISSET(fd
, &srv
->fdset
));
416 assert(srv
->fdidx
[fd
].valid
);
417 assert(!srv
->fdidx
[fd
].server
);
419 iov
[0].iov_base
= &srv
->pdu
;
420 iov
[0].iov_len
= sizeof(srv
->pdu
);
421 iov
[1].iov_base
= srv
->ibuf
;
422 iov
[1].iov_len
= srv
->imtu
;
427 msg
.msg_iovlen
= __arraycount(iov
);
428 msg
.msg_control
= srv
->ctlbuf
;
429 msg
.msg_controllen
= srv
->ctllen
;
433 len
= recvmsg(fd
, &msg
, 0);
434 } while (len
== -1 && errno
== EINTR
);
437 log_err("Could not receive SDP request on %s socket. %s (%d)",
438 srv
->fdidx
[fd
].control
? "control" : "L2CAP",
439 strerror(errno
), errno
);
445 log_info("Client on %s socket has disconnected",
446 srv
->fdidx
[fd
].control
? "control" : "L2CAP");
451 if (msg
.msg_flags
& MSG_TRUNC
)
452 log_info("Truncated message on %s socket",
453 srv
->fdidx
[fd
].control
? "control" : "L2CAP");
455 if ((cmsg
= CMSG_FIRSTHDR(&msg
)) != NULL
456 && cmsg
->cmsg_level
== SOL_SOCKET
457 && cmsg
->cmsg_type
== SCM_CREDS
458 && cmsg
->cmsg_len
>= CMSG_LEN(SOCKCREDSIZE(0)))
459 srv
->fdidx
[fd
].priv
= server_auth_check(srv
, CMSG_DATA(cmsg
));
461 srv
->pdu
.len
= be16toh(srv
->pdu
.len
);
463 if ((uint32_t)len
< sizeof(srv
->pdu
)
464 || (uint32_t)len
!= sizeof(srv
->pdu
) + srv
->pdu
.len
) {
465 error
= SDP_ERROR_CODE_INVALID_PDU_SIZE
;
467 switch (srv
->pdu
.pid
) {
468 case SDP_PDU_SERVICE_SEARCH_REQUEST
:
469 error
= service_search_request(srv
, fd
);
472 case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST
:
473 error
= service_attribute_request(srv
, fd
);
476 case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST
:
477 error
= service_search_attribute_request(srv
, fd
);
481 case SDP_PDU_SERVICE_REGISTER_REQUEST
:
482 error
= compat_register_request(srv
, fd
);
485 case SDP_PDU_SERVICE_CHANGE_REQUEST
:
486 error
= compat_change_request(srv
, fd
);
490 case SDP_PDU_RECORD_INSERT_REQUEST
:
491 error
= record_insert_request(srv
, fd
);
494 case SDP_PDU_RECORD_UPDATE_REQUEST
:
495 error
= record_update_request(srv
, fd
);
498 case SDP_PDU_RECORD_REMOVE_REQUEST
:
499 error
= record_remove_request(srv
, fd
);
503 error
= SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX
;
509 srv
->fdidx
[fd
].offset
= 0;
510 db_unselect(srv
, fd
);
511 srv
->pdu
.pid
= SDP_PDU_ERROR_RESPONSE
;
512 srv
->pdu
.len
= sizeof(error
);
513 be16enc(srv
->obuf
, error
);
516 iov
[0].iov_base
= &srv
->pdu
;
517 iov
[0].iov_len
= sizeof(srv
->pdu
);
518 iov
[1].iov_base
= srv
->obuf
;
519 iov
[1].iov_len
= srv
->pdu
.len
;
521 srv
->pdu
.len
= htobe16(srv
->pdu
.len
);
526 msg
.msg_iovlen
= __arraycount(iov
);
527 msg
.msg_control
= NULL
;
528 msg
.msg_controllen
= 0;
532 len
= sendmsg(fd
, &msg
, 0);
533 } while (len
== -1 && errno
== EINTR
);
536 log_err("Could not send SDP response on %s socket. %s (%d)",
537 srv
->fdidx
[fd
].control
? "control" : "L2CAP",
538 strerror(errno
), errno
);
547 * Close descriptor and remove it from index
550 server_close_fd(server_t
*srv
, int fd
)
553 assert(FD_ISSET(fd
, &srv
->fdset
));
554 assert(srv
->fdidx
[fd
].valid
);
556 db_unselect(srv
, fd
); /* release selected records */
557 db_release(srv
, fd
); /* expire owned records */
560 FD_CLR(fd
, &srv
->fdset
);
561 srv
->fdidx
[fd
].valid
= false;
563 if (fd
== srv
->fdmax
) {
564 while (fd
> 0 && !srv
->fdidx
[fd
].valid
)
572 * check credentials, return true when permitted to modify service records
575 server_auth_check(server_t
*srv
, void *data
)
577 struct sockcred
*cred
= data
;
584 if (cred
->sc_uid
== 0 || cred
->sc_euid
== 0)
587 if (srv
->sgroup
== NULL
)
590 grp
= getgrnam(srv
->sgroup
);
592 log_err("No gid for group '%s'", srv
->sgroup
);
597 if (cred
->sc_gid
== grp
->gr_gid
|| cred
->sc_egid
== grp
->gr_gid
)
600 if (cred
->sc_ngroups
> MAX_GROUPS
) {
601 log_info("Credentials truncated, lost %d groups",
602 MAX_GROUPS
- cred
->sc_ngroups
);
604 cred
->sc_ngroups
= MAX_GROUPS
;
607 for (n
= 0 ; n
< cred
->sc_ngroups
; n
++) {
608 if (cred
->sc_groups
[n
] == grp
->gr_gid
)