diff --git a/usr.sbin/bluetooth/sdpd/scr.c b/usr.sbin/bluetooth/sdpd/scr.c index f6f482d55fbb..d0c9ec5f29d6 100644 --- a/usr.sbin/bluetooth/sdpd/scr.c +++ b/usr.sbin/bluetooth/sdpd/scr.c @@ -58,7 +58,8 @@ server_prepare_service_change_response(server_p srv, int32_t fd) * value32 - handle 4 bytes */ - if (!srv->fdidx[fd].control || req_end - req < 4) + if (!srv->fdidx[fd].control || + !srv->fdidx[fd].priv || req_end - req < 4) return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); /* Get handle */ diff --git a/usr.sbin/bluetooth/sdpd/sdpd.8 b/usr.sbin/bluetooth/sdpd/sdpd.8 index 571e9088f680..0844e30ee15d 100644 --- a/usr.sbin/bluetooth/sdpd/sdpd.8 +++ b/usr.sbin/bluetooth/sdpd/sdpd.8 @@ -110,10 +110,14 @@ possible to specify which services should be to which Bluetooth device. Such assignment should be done at service registration time. .Pp -Access rights on the control socket define which application can register, -remove or change the service. -The application must be able to write to and read from the control socket -in order to perform any query to the Service Database via control socket. +Requests to register, remove or change service can only be made via the +control socket. +The +.Nm +daemon will check peer's credentials and will only accept the request if +the application has the same effective user ID as the +.Dq Li root +user ID. .Pp The .Nm diff --git a/usr.sbin/bluetooth/sdpd/server.c b/usr.sbin/bluetooth/sdpd/server.c index 14b2041cf220..d07b54917fe6 100644 --- a/usr.sbin/bluetooth/sdpd/server.c +++ b/usr.sbin/bluetooth/sdpd/server.c @@ -29,14 +29,18 @@ * $FreeBSD$ */ +#include #include +#include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -96,6 +100,13 @@ server_init(server_p srv, char const *control) return (-1); } + if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < 0) { + log_crit("Could not change permissions on control socket. " \ + "%s (%d)", strerror(errno), errno); + close(unsock); + return (-1); + } + if (listen(unsock, 10) < 0) { log_crit("Could not listen on control socket. %s (%d)", strerror(errno), errno); @@ -185,6 +196,7 @@ server_init(server_p srv, char const *control) srv->fdidx[unsock].valid = 1; srv->fdidx[unsock].server = 1; srv->fdidx[unsock].control = 1; + srv->fdidx[unsock].priv = 0; srv->fdidx[unsock].rsp_cs = 0; srv->fdidx[unsock].rsp_size = 0; srv->fdidx[unsock].rsp_limit = 0; @@ -195,6 +207,7 @@ server_init(server_p srv, char const *control) srv->fdidx[l2sock].valid = 1; srv->fdidx[l2sock].server = 1; srv->fdidx[l2sock].control = 0; + srv->fdidx[l2sock].priv = 0; srv->fdidx[l2sock].rsp_cs = 0; srv->fdidx[l2sock].rsp_size = 0; srv->fdidx[l2sock].rsp_limit = 0; @@ -276,7 +289,7 @@ static void server_accept_client(server_p srv, int32_t fd) { uint8_t *rsp = NULL; - int32_t cfd, size; + int32_t cfd, size, priv; uint16_t omtu; do { @@ -293,6 +306,8 @@ server_accept_client(server_p srv, int32_t fd) assert(!FD_ISSET(cfd, &srv->fdset)); assert(!srv->fdidx[cfd].valid); + priv = 0; + if (!srv->fdidx[fd].control) { /* Get local BD_ADDR */ size = sizeof(srv->req_sa); @@ -326,6 +341,28 @@ server_accept_client(server_p srv, int32_t fd) return; } } else { + struct xucred cr; + struct passwd *pw; + + /* Get peer's credentials */ + memset(&cr, 0, sizeof(cr)); + size = sizeof(cr); + + if (getsockopt(cfd, 0, LOCAL_PEERCRED, &cr, &size) < 0) { + log_err("Could not get peer's credentials. %s (%d)", + strerror(errno), errno); + close(cfd); + return; + } + + /* Check credentials */ + pw = getpwuid(cr.cr_uid); + if (pw != NULL) + priv = (strcmp(pw->pw_name, "root") == 0); + else + log_warning("Could not verify credentials for uid %d", + cr.cr_uid); + memcpy(&srv->req_sa.l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(srv->req_sa.l2cap_bdaddr)); @@ -351,6 +388,7 @@ server_accept_client(server_p srv, int32_t fd) srv->fdidx[cfd].valid = 1; srv->fdidx[cfd].server = 0; srv->fdidx[cfd].control = srv->fdidx[fd].control; + srv->fdidx[cfd].priv = priv; srv->fdidx[cfd].rsp_cs = 0; srv->fdidx[cfd].rsp_size = 0; srv->fdidx[cfd].rsp_limit = 0; diff --git a/usr.sbin/bluetooth/sdpd/server.h b/usr.sbin/bluetooth/sdpd/server.h index 6f8f08860768..d7ef55e20244 100644 --- a/usr.sbin/bluetooth/sdpd/server.h +++ b/usr.sbin/bluetooth/sdpd/server.h @@ -41,7 +41,8 @@ struct fd_idx unsigned valid : 1; /* descriptor is valid */ unsigned server : 1; /* descriptor is listening */ unsigned control : 1; /* descriptor is a control socket */ - unsigned reserved : 2; + unsigned priv : 1; /* descriptor is privileged */ + unsigned reserved : 1; unsigned rsp_cs : 11; /* response continuation state */ uint16_t rsp_size; /* response size */ uint16_t rsp_limit; /* response limit */ diff --git a/usr.sbin/bluetooth/sdpd/srr.c b/usr.sbin/bluetooth/sdpd/srr.c index a1f3ded86339..fd636d56d446 100644 --- a/usr.sbin/bluetooth/sdpd/srr.c +++ b/usr.sbin/bluetooth/sdpd/srr.c @@ -65,7 +65,8 @@ server_prepare_service_register_response(server_p srv, int32_t fd) * bdaddr - BD_ADDR 6 bytes */ - if (!srv->fdidx[fd].control || req_end - req < 8) + if (!srv->fdidx[fd].control || + !srv->fdidx[fd].priv || req_end - req < 8) return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); /* Get ServiceClass UUID */ diff --git a/usr.sbin/bluetooth/sdpd/sur.c b/usr.sbin/bluetooth/sdpd/sur.c index 6d7f778aa51a..143eaf3dbec9 100644 --- a/usr.sbin/bluetooth/sdpd/sur.c +++ b/usr.sbin/bluetooth/sdpd/sur.c @@ -58,7 +58,8 @@ server_prepare_service_unregister_response(server_p srv, int32_t fd) * value32 - uuid 4 bytes */ - if (!srv->fdidx[fd].control || req_end - req < 4) + if (!srv->fdidx[fd].control || + !srv->fdidx[fd].priv || req_end - req < 4) return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); /* Get handle */