#include "protocol-server.h"
#include "fserver.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define LOG(...) fprintf(stderr, __VA_ARGS__)
static
int
fserv_check_permissions(
LWMsgSession* session,
const char* path, OpenMode mode)
{
int ret = 0;
uid_t euid;
gid_t egid;
struct stat statbuf;
{
LOG("Unsupported authentication type on session %p\n", session);
ret = -1;
goto error;
}
if (status)
{
ret = -1;
goto error;
}
if (stat(path, &statbuf) == -1)
{
ret = errno;
goto error;
}
if ((mode & OPEN_MODE_READ))
{
int can_read =
((statbuf.st_uid == euid && statbuf.st_mode & S_IRUSR) ||
(statbuf.st_gid == egid && statbuf.st_mode & S_IRGRP) ||
(statbuf.st_mode & S_IROTH));
if (!can_read)
{
LOG("Permission denied for (uid = %i, gid = %i) to read %s\n",
(int) euid,
(int) egid,
path);
ret = EPERM;
goto error;
}
}
if ((mode & OPEN_MODE_WRITE))
{
int can_write =
((statbuf.st_uid == euid && statbuf.st_mode & S_IWUSR) ||
(statbuf.st_gid == egid && statbuf.st_mode & S_IWGRP) ||
(statbuf.st_mode & S_IWOTH));
if (!can_write)
{
LOG("Permission denied for (uid = %i, gid = %i) to write %s\n",
(int) euid,
(int) egid,
path);
ret = EPERM;
goto error;
}
}
LOG("Permission granted for (uid = %i, gid = %i) to open %s\n",
(int) euid,
(int) egid,
path);
error:
return ret;
}
static
void
fserv_free_handle(
void* _handle
)
{
FileHandle* handle = _handle;
if (handle->fd >= 0)
{
close(handle->fd);
}
free(handle);
}
fserv_open_srv(
void* data
)
{
OpenRequest* req = (OpenRequest*) in->
data;
FileHandle* handle = NULL;
StatusReply* sreply = NULL;
int flags = 0;
int fd = -1;
int ret;
LOG("fserv_open() of %s on session %p\n", req->path, session);
ret = fserv_check_permissions(session, req->path, req->mode);
if (ret)
{
sreply = malloc(sizeof(*sreply));
if (!handle)
{
goto error;
}
sreply->err = ret;
out->
tag = FSERV_ERROR_RES;
out->
data = (
void*) sreply;
}
else
{
if ((req->mode & OPEN_MODE_READ) && !(req->mode & OPEN_MODE_WRITE))
{
flags |= O_RDONLY;
}
if ((req->mode & OPEN_MODE_WRITE) && !(req->mode & OPEN_MODE_READ))
{
flags |= O_WRONLY;
}
if ((req->mode & OPEN_MODE_WRITE) && (req->mode & OPEN_MODE_READ))
{
flags |= O_RDWR;
}
if ((req->mode & OPEN_MODE_APPEND))
{
flags |= O_APPEND;
}
fd = open(req->path, flags);
if (fd >= 0)
{
handle = malloc(sizeof(*handle));
if (!handle)
{
goto error;
}
handle->fd = fd;
handle->mode = req->mode;
session,
"FileHandle",
handle,
fserv_free_handle,
&lwmsg_handle);
if (status)
{
goto error;
}
out->
tag = FSERV_OPEN_RES;
out->
data = lwmsg_handle;
handle = NULL;
LOG("Successfully opened %s as fd %i for session %p\n",
req->path, fd, session);
}
else
{
sreply = malloc(sizeof(*sreply));
if (!handle)
{
goto error;
}
sreply->err = errno;
out->
tag = FSERV_ERROR_RES;
out->
data = (
void*) sreply;
}
}
error:
if (handle)
{
fserv_free_handle(handle);
}
return status;
}
fserv_write_srv(
void* data
)
{
WriteRequest* req = (WriteRequest*) in->
data;
StatusReply* sreply = NULL;
FileHandle* handle = NULL;
int fd = -1;
session,
req->handle,
(void**)(void*) &handle);
if (status)
{
goto error;
}
fd = handle->fd;
LOG("fserv_write() of %lu bytes to fd %i on session %p\n",
(unsigned long) req->size, fd, session);
if (write(fd, req->data, req->size) == -1)
{
sreply = malloc(sizeof(*sreply));
if (!sreply)
{
goto error;
}
sreply->err = errno;
out->
tag = FSERV_ERROR_RES;
}
else
{
out->
tag = FSERV_VOID_RES;
}
out->
data = (
void*) sreply;
error:
return status;
}
fserv_read_srv(
void* data
)
{
ReadRequest* req = (ReadRequest*) in->
data;
StatusReply* sreply = NULL;
ReadReply* rreply = NULL;
FileHandle* handle = NULL;
int fd = -1;
int ret = 0;
session,
req->handle,
(void**)(void*) &handle);
if (status)
{
goto error;
}
fd = handle->fd;
LOG("fserv_read() of %lu bytes from fd %i on session %p\n",
(unsigned long) req->size, fd, session);
rreply = malloc(sizeof(*rreply));
if (!rreply)
{
goto error;
}
rreply->data = malloc(req->size);
if (!rreply->data)
{
goto error;
}
ret = read(fd, rreply->data, req->size);
if (ret == -1)
{
int err = errno;
free(rreply->data);
free(rreply);
sreply = malloc(sizeof(*sreply));
if (!sreply)
{
goto error;
}
sreply->err = err;
out->
tag = FSERV_ERROR_RES;
out->
data = (
void*) sreply;
}
else if (ret == 0)
{
free(rreply->data);
rreply->data = NULL;
rreply->size = 0;
out->
tag = FSERV_READ_RES;
out->
data = (
void*) rreply;
}
else
{
rreply->size = ret;
out->
tag = FSERV_READ_RES;
out->
data = (
void*) rreply;
}
error:
return status;
}
fserv_close_srv(
void* data
)
{
FileHandle* handle = NULL;
StatusReply* sreply = NULL;
LOG("fserv_close() on fd %i for session %p\n", handle->fd, session);
session,
(void**)(void*) &handle);
if (status)
{
goto error;
}
if (status)
{
goto error;
}
if (close(handle->fd) == -1)
{
sreply = malloc(sizeof(*sreply));
if (!sreply)
{
goto error;
}
sreply->err = errno;
out->
tag = FSERV_ERROR_RES;
}
else
{
out->
tag = FSERV_VOID_RES;
}
error:
return status;
}
{
};
fserver_get_dispatch(void)
{
return fserv_dispatch;
}