1 /* $NetBSD: server.c,v 1.7 2009/05/12 10:05:07 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.7 2009/05/12 10:05:07 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 403 /* 404 * Process request from the client 405 */ 406 static bool 407 server_process_request(server_t *srv, int fd) 408 { 409 struct msghdr msg; 410 struct iovec iov[2]; 411 struct cmsghdr *cmsg; 412 ssize_t len; 413 uint16_t error; 414 415 assert(FD_ISSET(fd, &srv->fdset)); 416 assert(srv->fdidx[fd].valid); 417 assert(!srv->fdidx[fd].server); 418 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; 423 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; 431 432 do { 433 len = recvmsg(fd, &msg, 0); 434 } while (len == -1 && errno == EINTR); 435 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); 440 441 return false; 442 } 443 444 if (len == 0) { 445 log_info("Client on %s socket has disconnected", 446 srv->fdidx[fd].control ? "control" : "L2CAP"); 447 448 return false; 449 } 450 451 if (msg.msg_flags & MSG_TRUNC) 452 log_info("Truncated message on %s socket", 453 srv->fdidx[fd].control ? "control" : "L2CAP"); 454 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)); 460 461 srv->pdu.len = be16toh(srv->pdu.len); 462 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; 471 472 case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST: 473 error = service_attribute_request(srv, fd); 474 break; 475 476 case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST: 477 error = service_search_attribute_request(srv, fd); 478 break; 479 480 #ifdef SDP_COMPAT 481 case SDP_PDU_SERVICE_REGISTER_REQUEST: 482 error = compat_register_request(srv, fd); 483 break; 484 485 case SDP_PDU_SERVICE_CHANGE_REQUEST: 486 error = compat_change_request(srv, fd); 487 break; 488 #endif 489 490 case SDP_PDU_RECORD_INSERT_REQUEST: 491 error = record_insert_request(srv, fd); 492 break; 493 494 case SDP_PDU_RECORD_UPDATE_REQUEST: 495 error = record_update_request(srv, fd); 496 break; 497 498 case SDP_PDU_RECORD_REMOVE_REQUEST: 499 error = record_remove_request(srv, fd); 500 break; 501 502 default: 503 error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 504 break; 505 } 506 } 507 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); 514 } 515 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; 520 521 srv->pdu.len = htobe16(srv->pdu.len); 522 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; 530 531 do { 532 len = sendmsg(fd, &msg, 0); 533 } while (len == -1 && errno == EINTR); 534 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); 539 540 return false; 541 } 542 543 return true; 544 } 545 546 /* 547 * Close descriptor and remove it from index 548 */ 549 static void 550 server_close_fd(server_t *srv, int fd) 551 { 552 553 assert(FD_ISSET(fd, &srv->fdset)); 554 assert(srv->fdidx[fd].valid); 555 556 db_unselect(srv, fd); /* release selected records */ 557 db_release(srv, fd); /* expire owned records */ 558 559 close(fd); 560 FD_CLR(fd, &srv->fdset); 561 srv->fdidx[fd].valid = false; 562 563 if (fd == srv->fdmax) { 564 while (fd > 0 && !srv->fdidx[fd].valid) 565 fd--; 566 567 srv->fdmax = fd; 568 } 569 } 570 571 /* 572 * check credentials, return true when permitted to modify service records 573 */ 574 static bool 575 server_auth_check(server_t *srv, void *data) 576 { 577 struct sockcred *cred = data; 578 struct group *grp; 579 int n; 580 581 if (cred == NULL) 582 return false; 583 584 if (cred->sc_uid == 0 || cred->sc_euid == 0) 585 return true; 586 587 if (srv->sgroup == NULL) 588 return false; 589 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; 595 } 596 597 if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid) 598 return true; 599 600 if (cred->sc_ngroups > MAX_GROUPS) { 601 log_info("Credentials truncated, lost %d groups", 602 MAX_GROUPS - cred->sc_ngroups); 603 604 cred->sc_ngroups = MAX_GROUPS; 605 } 606 607 for (n = 0 ; n < cred->sc_ngroups ; n++) { 608 if (cred->sc_groups[n] == grp->gr_gid) 609 return true; 610 } 611 612 return false; 613 } 614