No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / sdpd / server.c
blob1c673e12ef50f7e8baf665dbbaaf224aeea3f6f8
1 /* $NetBSD: server.c,v 1.6 2009/04/18 13:53:59 lukem Exp $ */
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
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.
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.
31 /*-
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
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.
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.
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>
64 #include <sys/stat.h>
65 #include <sys/ucred.h>
66 #include <sys/un.h>
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>
79 #include "sdpd.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 */
89 #define MAX_GROUPS 20
92 * Initialize server
94 bool
95 server_init(server_t *srv, char const *control, char const *sgroup)
98 assert(srv != NULL);
99 assert(control != NULL);
101 memset(srv, 0, sizeof(srv));
102 FD_ZERO(&srv->fdset);
103 srv->sgroup = sgroup;
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;
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);
116 goto fail;
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;
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;
133 if (db_init(srv)
134 && server_open_control(srv, control)
135 && server_open_l2cap(srv))
136 return true;
138 fail:
139 server_shutdown(srv);
140 return false;
144 * Open local control socket
146 static bool
147 server_open_control(server_t *srv, char const *control)
149 struct sockaddr_un un;
150 int opt, fd;
152 if (unlink(control) == -1 && errno != ENOENT) {
153 log_crit("Could not unlink(%s). %s (%d)",
154 control, strerror(errno), errno);
156 return false;
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);
164 return false;
167 opt = 1;
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);
180 close(fd);
181 return false;
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);
188 close(fd);
189 return false;
192 if (listen(fd, 5) == -1) {
193 log_crit("Could not listen on control socket. %s (%d)",
194 strerror(errno), errno);
196 close(fd);
197 return false;
200 /* Add control descriptor to index */
201 if (fd > srv->fdmax)
202 srv->fdmax = fd;
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;
213 * Open L2CAP server socket
215 static bool
216 server_open_l2cap(server_t *srv)
218 struct sockaddr_bt sa;
219 int fd;
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);
226 return false;
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);
234 close(fd);
235 return false;
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);
248 close(fd);
249 return false;
252 if (listen(fd, 5) == -1) {
253 log_crit("Could not listen on L2CAP socket. %s (%d)",
254 strerror(errno), errno);
256 close(fd);
257 return false;
260 /* Add L2CAP descriptor to index */
261 if (fd > srv->fdmax)
262 srv->fdmax = fd;
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;
273 * Shutdown server
275 void
276 server_shutdown(server_t *srv)
278 record_t *r;
279 int fd;
281 assert(srv != NULL);
283 while ((r = LIST_FIRST(&srv->rlist)) != NULL) {
284 LIST_REMOVE(r, next);
285 free(r);
288 for (fd = 0; fd < srv->fdmax + 1; fd ++) {
289 if (srv->fdidx[fd].valid)
290 server_close_fd(srv, fd);
293 free(srv->fdidx);
294 free(srv->ctlbuf);
295 free(srv->ibuf);
296 free(srv->obuf);
298 memset(srv, 0, sizeof(*srv));
302 * Do one server iteration
304 bool
305 server_do(server_t *srv)
307 fd_set fdset;
308 int n, fd;
310 assert(srv != NULL);
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;
318 log_err("Could not select(%d, %p). %s (%d)",
319 srv->fdmax + 1, &fdset, strerror(errno), errno);
321 return false;
324 for (fd = 0; fd < srv->fdmax + 1 && n > 0; fd++) {
325 if (!FD_ISSET(fd, &fdset))
326 continue;
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);
335 n--;
338 return true;
343 * Accept new client connection and register it with index
345 static void
346 server_accept_client(server_t *srv, int fd)
348 struct sockaddr_bt sa;
349 socklen_t len;
350 int cfd;
351 uint16_t omtu;
353 do {
354 cfd = accept(fd, NULL, NULL);
355 } while (cfd == -1 && errno == EINTR);
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);
362 return;
365 if (cfd >= FD_SETSIZE) {
366 log_crit("File descriptor too large");
367 close(cfd);
368 return;
371 assert(!FD_ISSET(cfd, &srv->fdset));
372 assert(!srv->fdidx[cfd].valid);
374 memset(&sa, 0, sizeof(sa));
375 omtu = srv->omtu;
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");
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);
389 /* Add client descriptor to the index */
390 if (cfd > srv->fdmax)
391 srv->fdmax = cfd;
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
406 static bool
407 server_process_request(server_t *srv, int fd)
409 struct msghdr msg;
410 struct iovec iov[2];
411 struct cmsghdr *cmsg;
412 ssize_t len;
413 uint16_t error;
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;
424 msg.msg_name = NULL;
425 msg.msg_namelen = 0;
426 msg.msg_iov = iov;
427 msg.msg_iovlen = __arraycount(iov);
428 msg.msg_control = srv->ctlbuf;
429 msg.msg_controllen = srv->ctllen;
430 msg.msg_flags = 0;
432 do {
433 len = recvmsg(fd, &msg, 0);
434 } while (len == -1 && errno == EINTR);
436 if (len == -1) {
437 log_err("Could not receive SDP request on %s socket. %s (%d)",
438 srv->fdidx[fd].control ? "control" : "L2CAP",
439 strerror(errno), errno);
441 return false;
444 if (len == 0) {
445 log_info("Client on %s socket has disconnected",
446 srv->fdidx[fd].control ? "control" : "L2CAP");
448 return false;
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;
466 } else {
467 switch (srv->pdu.pid) {
468 case SDP_PDU_SERVICE_SEARCH_REQUEST:
469 error = service_search_request(srv, fd);
470 break;
472 case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
473 error = service_attribute_request(srv, fd);
474 break;
476 case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
477 error = service_search_attribute_request(srv, fd);
478 break;
480 #ifdef SDP_COMPAT
481 case SDP_PDU_SERVICE_REGISTER_REQUEST:
482 error = compat_register_request(srv, fd);
483 break;
485 case SDP_PDU_SERVICE_CHANGE_REQUEST:
486 error = compat_change_request(srv, fd);
487 break;
488 #endif
490 case SDP_PDU_RECORD_INSERT_REQUEST:
491 error = record_insert_request(srv, fd);
492 break;
494 case SDP_PDU_RECORD_UPDATE_REQUEST:
495 error = record_update_request(srv, fd);
496 break;
498 case SDP_PDU_RECORD_REMOVE_REQUEST:
499 error = record_remove_request(srv, fd);
500 break;
502 default:
503 error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
504 break;
508 if (error != 0) {
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);
523 msg.msg_name = NULL;
524 msg.msg_namelen = 0;
525 msg.msg_iov = iov;
526 msg.msg_iovlen = __arraycount(iov);
527 msg.msg_control = NULL;
528 msg.msg_controllen = 0;
529 msg.msg_flags = 0;
531 do {
532 len = sendmsg(fd, &msg, 0);
533 } while (len == -1 && errno == EINTR);
535 if (len == -1) {
536 log_err("Could not send SDP response on %s socket. %s (%d)",
537 srv->fdidx[fd].control ? "control" : "L2CAP",
538 strerror(errno), errno);
540 return false;
543 return true;
547 * Close descriptor and remove it from index
549 static void
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 */
559 close(fd);
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)
565 fd--;
567 srv->fdmax = fd;
572 * check credentials, return true when permitted to modify service records
574 static bool
575 server_auth_check(server_t *srv, void *data)
577 struct sockcred *cred = data;
578 struct group *grp;
579 int n;
581 if (cred == NULL)
582 return false;
584 if (cred->sc_uid == 0 || cred->sc_euid == 0)
585 return true;
587 if (srv->sgroup == NULL)
588 return false;
590 grp = getgrnam(srv->sgroup);
591 if (grp == NULL) {
592 log_err("No gid for group '%s'", srv->sgroup);
593 srv->sgroup = NULL;
594 return false;
597 if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid)
598 return true;
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)
609 return true;
612 return false;