From: Anicka Bernathova Date: Fri, 29 Aug 2008 15:55:35 +0000 (+0200) Subject: started work on locking mailboxes X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=39568271f0cf04774e74e5c403cf1391f81ce2c0;p=umpf.git started work on locking mailboxes --- diff --git a/Makefile b/Makefile index beb1a6e..3597642 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ LDLIBS=-lpcre brum: brum.c cond.tab.o int.o lex.o ham.o lists.o gcc -o $@ $^ $(LDLIBS) +lock: lex.o cond.tab.o + cond.tab.o: cond.tab.c lex.o lex.o: lex.c cond.tab.c @@ -21,4 +23,4 @@ cond.tab.c: cond.y bison -dvt cond.y clean: - rm -rf cond.tab.[ch] cond.output cond brum *.o + rm -rf cond.tab.[ch] cond.output cond brum *.o core diff --git a/lock.c b/lock.c new file mode 100644 index 0000000..b7e3ef4 --- /dev/null +++ b/lock.c @@ -0,0 +1,159 @@ +#include +#include +#include + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "brum.h" + +#define LOCK_MAX_TRIES 30 + +static void +random_sleep(unsigned int about, unsigned int offset) +{ + int myrand; + + if (about == 0 || offset > about) + die("random sleep: Bad input data: %d +- %d", about, offset); + + myrand = random() % offset * (random()%2?1:-1); + + usleep(about * 1000000 + myrand * 500000); +} + +static char* +cat(char* l, char* r) +{ + char* res = xmalloc(strlen(l) + strlen (r) + 1); + strcpy(res, l); + strcat(res, r); + + return res; +} + +/* FIXME: what about privileges? */ +static int +dot_lock(char* path) +{ + int i; + int fd; + int res = -1; + char* lockfile = cat(path, ".lock"); + + for (i = 0; i < LOCK_MAX_TRIES; i++){ + if ((fd = open(lockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) + >= 0) { + close(fd); + break; + } + + if (errno != EEXIST) + break; + + /* FIXME: deal with old locks */ + + random_sleep(1, 1); + } + + free(lockfile); + return res; +} + +static void +dot_unlock(char* path) +{ + char* lockfile = cat(path, ".lock"); + + unlink(lockfile); + + free(lockfile); +} + +int +open_mailbox(char* path, int use_default_mailbox) +{ + int fd; + + /* attempt to dot_lock first */ + if (dot_lock(path)) + return -1; + + /* if OK, try to open the file: + either we are saving to default mailbox (no problem here) + or we are saving somewhere else (no need to be privileged) + */ + if (use_default_mailbox){ + /* get our preciousss out of pocket */ + gid_t ruid, euid, suid; + getresgid(&ruid, &euid, &suid); + setresgid(ruid, suid, suid); + + /* we are not going to create default mailbox */ + fd = open(path, O_RDWR); + if (fd < 0) + return -1; + + /* hide it again */ + setresgid(ruid, ruid, suid); + } else { + fd = open(path, O_RDWR); + if (fd < 0 && errno == ENOENT){ + fd = open(path, O_RDWR | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR); + if (fd < 0) + return -1; + + } else if (fd < 0) + return -1; + } + + /* fcntl then */ + struct flock mb_lock; + memset(&mb_lock, 0, sizeof(struct flock)); + mb_lock.l_type = F_WRLCK; + mb_lock.l_whence = SEEK_SET; + + if (fcntl(fd, F_GETLK, &mb_lock) < 0){ + close(fd); + dot_unlock(path); + return -1; + } + + return fd; +} + +void +close_mailbox(int fd, char* path) +{ + struct flock mb_lock; + memset(&mb_lock, 0, sizeof(struct flock)); + mb_lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &mb_lock); + close(fd); + dot_unlock(path); +} + +int +main(int argc, char** argv) +{ + /* FIXME: move somewhere */ + int fd; + gid_t ruid, euid, suid; + if (argc < 2) + return 1; + char* mb = argv[1]; + getresgid(&ruid, &euid, &suid); + setresgid(ruid, ruid, euid); + fd = open_mailbox(mb, 1); + printf("%d\n", fd); + if (fd < 0) + return 1; + + close_mailbox(fd, mb); + + return 0; +}