From 629d9f948c532482ebe1f4ca102336bcd7b3b520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Re=CC=A8kawek?= Date: Tue, 4 Jun 2024 18:38:06 +0200 Subject: [PATCH] Support read-only mode. --- src/Makefile | 2 +- src/auth.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ src/auth.h | 13 ++++++++++++ src/datagram.c | 20 ++++++++++++++++-- src/datagram.h | 1 + src/main.c | 34 ++++++++++++++++++++++--------- src/tnfs_file.c | 13 +++++++++--- 7 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 src/auth.c create mode 100644 src/auth.h diff --git a/src/Makefile b/src/Makefile index 264485d..a80d787 100644 --- a/src/Makefile +++ b/src/Makefile @@ -32,7 +32,7 @@ ifdef USAGELOG endif CFLAGS=$(FLAGS) $(EXFLAGS) $(LOGFLAGS) -OBJS=main.o datagram.o event_common.o log.o session.o endian.o directory.o errortable.o tnfs_file.o chroot.o fileinfo.o stats.o $(EXOBJS) +OBJS=main.o datagram.o event_common.o log.o session.o endian.o directory.o errortable.o tnfs_file.o chroot.o fileinfo.o stats.o auth.o $(EXOBJS) all: $(OBJS) $(CC) -o ../bin/$(EXEC) $(OBJS) $(LIBS) diff --git a/src/auth.c b/src/auth.c new file mode 100644 index 0000000..a2210da --- /dev/null +++ b/src/auth.c @@ -0,0 +1,54 @@ +#include "auth.h" +#include "tnfs.h" +#include "tnfs_file.h" + +int RW_CMDS[] = +{ + TNFS_MKDIR, + TNFS_RMDIR, + TNFS_WRITEBLOCK, + TNFS_UNLINKFILE, + TNFS_CHMODFILE, + TNFS_RENAMEFILE, + -1, +}; + +int RW_FLAGS = + TNFS_O_WRONLY | + TNFS_O_RDWR | + TNFS_O_APPEND | + TNFS_O_CREAT | + TNFS_O_TRUNC | + TNFS_O_EXCL; + +bool read_only; + +void auth_init(bool _read_only) +{ + read_only = _read_only; +} + +bool is_cmd_allowed(uint8_t cmd) +{ + if (!read_only) + { + return true; + } + for (int i = 0; RW_CMDS[i] != -1; i++) + { + if (RW_CMDS[i] == cmd) + { + return false; + } + } + return true; +} + +bool is_open_allowed(char *filename, int flags) +{ + if (!read_only) + { + return true; + } + return (flags & RW_FLAGS) == 0; +} diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 0000000..85513e2 --- /dev/null +++ b/src/auth.h @@ -0,0 +1,13 @@ +#ifndef _READONLY_H +#define _READONLY_H + +#include +#include + +void auth_init(bool enable_writes); + +bool is_cmd_allowed(uint8_t cmd); + +bool is_open_allowed(char *filename, int flags); + +#endif diff --git a/src/datagram.c b/src/datagram.c index c90cf0d..29c892c 100644 --- a/src/datagram.c +++ b/src/datagram.c @@ -25,6 +25,7 @@ TNFS daemon datagram handler */ #include +#include #include #include #include @@ -51,9 +52,11 @@ TNFS daemon datagram handler #include "directory.h" #include "tnfs_file.h" #include "event.h" +#include "auth.h" -int sockfd; /* UDP global socket file descriptor */ -int tcplistenfd; /* TCP listening socket file descriptor */ +int sockfd; /* UDP global socket file descriptor */ +int tcplistenfd; /* TCP listening socket file descriptor */ +bool write_support; /* Whether writes should be enabled. */ tnfs_cmdfunc dircmd[NUM_DIRCMDS] = {&tnfs_opendir, &tnfs_readdir, &tnfs_closedir, @@ -378,6 +381,12 @@ void tnfs_decode(struct sockaddr_in *cliaddr, int cli_fd, int rxbytes, unsigned TNFSMSGLOG(&hdr, "REQUEST cmd=0x%02x %s", hdr.cmd, get_cmd_name(hdr.cmd)); #endif + if (!is_cmd_allowed(hdr.cmd)) + { + tnfs_notpermitted(&hdr); + return; + } + /* The MOUNT command is the only one that doesn't need an * established session (since MOUNT is actually what will * establish the session) */ @@ -463,6 +472,13 @@ void tnfs_badcommand(Header *hdr, Session *sess) tnfs_send(sess, hdr, NULL, 0); } +void tnfs_notpermitted(Header *hdr) +{ + TNFSMSGLOG(hdr, "Command %s is not permitted", get_cmd_name(hdr->cmd)); + hdr->status = TNFS_EPERM; + tnfs_send(NULL, hdr, NULL, 0); +} + void tnfs_send(Session *sess, Header *hdr, unsigned char *msg, int msgsz) { struct sockaddr_in cliaddr; diff --git a/src/datagram.h b/src/datagram.h index 3c96ab7..8f58666 100644 --- a/src/datagram.h +++ b/src/datagram.h @@ -54,6 +54,7 @@ void tnfs_decode(struct sockaddr_in *cliaddr, int cli_fd, int rxbytes, unsigned char *rxbuf); void tnfs_invalidsession(Header *hdr); void tnfs_badcommand(Header *hdr, Session *sess); +void tnfs_notpermitted(Header *hdr); void tnfs_send(Session *sess, Header *hdr, unsigned char *msg, int msgsz); void tnfs_resend(Session *sess, struct sockaddr_in *cliaddr, int cli_fd); #endif diff --git a/src/main.c b/src/main.c index 1fb5f46..fe422d5 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ * * */ +#include #include #include #include @@ -35,6 +36,7 @@ #include "errortable.h" #include "chroot.h" #include "log.h" +#include "auth.h" /* declare the main() - it won't be used elsewhere so I'll not bother * with putting it in a .h file */ @@ -47,14 +49,15 @@ int main(int argc, char **argv) char *uvalue = NULL; char *gvalue = NULL; #endif + bool read_only = false; char *pvalue = NULL; if(argc >= 2) { #ifdef ENABLE_CHROOT - while((opt = getopt(argc, argv, "u:g:p:")) != -1) + while((opt = getopt(argc, argv, "ru:g:p:")) != -1) #else - while((opt = getopt(argc, argv, "p:")) != -1) + while((opt = getopt(argc, argv, "rp:")) != -1) #endif { switch(opt) @@ -63,6 +66,9 @@ int main(int argc, char **argv) case 'p': pvalue = optarg; break; + case 'r': + read_only = true; + break; #ifdef ENABLE_CHROOT case 'u': uvalue = optarg; @@ -83,9 +89,9 @@ int main(int argc, char **argv) else { #ifdef ENABLE_CHROOT - LOG("Usage: tnfsd [-u -g -p ]\n"); + LOG("Usage: tnfsd [-u -g -p ] -r\n"); #else - LOG("Usage: tnfsd [-p ]\n"); + LOG("Usage: tnfsd [-p ] -r\n"); #endif exit(-1); } @@ -139,13 +145,21 @@ int main(int argc, char **argv) const char *version = "24.0522.1"; LOG("Starting tnfsd version %s on port %d using root directory \"%s\"\n", version, port, argv[optind]); + if (read_only) + { + LOG("The server runs in read-only mode. TNFS clients can only list and download files.\n"); + } + else + { + LOG("The server runs in read-write mode. TNFS clients can upload and modify files. Use -r to enable read-only mode.\n"); + } - tnfs_init(); /* initialize structures etc. */ - tnfs_init_errtable(); /* initialize error lookup table */ - tnfs_event_init(); - tnfs_sockinit(port); /* initialize communications */ - tnfs_mainloop(); /* run */ - tnfs_event_close(); + tnfs_init(); /* initialize structures etc. */ + tnfs_init_errtable(); /* initialize error lookup table */ + tnfs_event_init(); /* initialize event system */ + tnfs_sockinit(port); /* initialize communications */ + auth_init(read_only); /* initialize authentication */ + tnfs_mainloop(); /* run */ return 0; } diff --git a/src/tnfs_file.c b/src/tnfs_file.c index 750cbca..12315f1 100644 --- a/src/tnfs_file.c +++ b/src/tnfs_file.c @@ -50,6 +50,7 @@ #include "endian.h" #include "bsdcompat.h" #include "log.h" +#include "auth.h" char fnbuf[MAX_FILEPATH]; unsigned char iobuf[MAX_IOSZ + 2]; /* 2 bytes added for the size param */ @@ -95,13 +96,19 @@ void tnfs_open(Header *hdr, Session *s, unsigned char *buf, int bufsz) return; } + flags = *buf + (*(buf + 1) * 256); + mode = *(buf + 2) + (*(buf + 3) * 256); + + if (!is_open_allowed(fnbuf, flags)) + { + tnfs_notpermitted(hdr); + return; + } + for (i = 0; i < MAX_FD_PER_CONN; i++) { if (s->fd[i] == 0) { - flags = *buf + (*(buf + 1) * 256); - mode = *(buf + 2) + (*(buf + 3) * 256); - #ifdef WITH_ZIP fd = zipopen(fnbuf, tnfs_make_mode(flags), mode); #else