1 /* $NetBSD: server.c,v 1.8 2010/03/07 10:58:40 plunky 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.8 2010/03/07 10:58:40 plunky 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 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=%d) 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 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, 0, 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 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 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 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 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 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 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 if (fd == srv->fdmax) { 568 while (fd > 0 && !srv->fdidx[fd].valid) 569 fd--; 570 571 srv->fdmax = fd; 572 } 573 574 log_debug("client on fd#%d closed", fd); 575 } 576 577 /* 578 * check credentials, return true when permitted to modify service records 579 */ 580 static bool 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