MFC: 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.
This commit is contained in:
parent
fc03c2855d
commit
b1877750af
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -29,14 +29,18 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <bluetooth.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <sdp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user