From 33f5a902c54a3c48d2ad668c3399f8b5d3cbe1aa Mon Sep 17 00:00:00 2001 From: emax Date: Tue, 6 Dec 2005 17:56:36 +0000 Subject: [PATCH] Teach sdpd(8) to check peer's credentials before accepting request to register, remove or change services in the local database. For now only accept the request if the peer has effective user ID the same as 'root' user ID. MFC after: 1 week --- usr.sbin/bluetooth/sdpd/scr.c | 3 ++- usr.sbin/bluetooth/sdpd/sdpd.8 | 12 ++++++---- usr.sbin/bluetooth/sdpd/server.c | 40 +++++++++++++++++++++++++++++++- usr.sbin/bluetooth/sdpd/server.h | 3 ++- usr.sbin/bluetooth/sdpd/srr.c | 3 ++- usr.sbin/bluetooth/sdpd/sur.c | 3 ++- 6 files changed, 55 insertions(+), 9 deletions(-) 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 */