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:
emax 2005-12-13 00:38:28 +00:00
parent fc03c2855d
commit b1877750af
6 changed files with 55 additions and 9 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */