From a181e61ca0119b8c3fd2daa4b8d23add2cda3ed0 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 6 Nov 2001 12:03:23 +0000 Subject: bugfixes --- usermux.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 usermux.c (limited to 'usermux.c') diff --git a/usermux.c b/usermux.c new file mode 100644 index 0000000..4caacb9 --- /dev/null +++ b/usermux.c @@ -0,0 +1,252 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOUNTDIR "/mnt/avfs" + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static struct fuse *um_fuse; +static const char *um_dir; + +#define MAX_USERS 100 +static uid_t users[MAX_USERS]; +static size_t numusers = 0; + +void avfs_main(struct fuse *fuse); + +static void reset_signal_handlers() +{ + struct sigaction sa; + + sa.sa_handler = SIG_DFL; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; + + sigaction(SIGCHLD, &sa, NULL); +} + + +static void start_avfs(uid_t uid) +{ + int res; + char *userdir; + struct fuse *user_fuse; + struct passwd pw_buf; + struct passwd *pw; + char buf[1024]; + + res = getpwuid_r(uid, &pw_buf, buf, sizeof(buf), &pw); + if(pw == NULL) + return; + + user_fuse = fuse_new(0); + + userdir = g_strdup_printf("%s/%010u", MOUNTDIR, uid); + mkdir(userdir, 0755); + chown(userdir, pw->pw_uid, pw->pw_gid); + res = fuse_mount(user_fuse, userdir); + g_free(userdir); + + if(res == -1) + return; + + res = fork(); + if(res == 0) { + reset_signal_handlers(); + + initgroups(pw->pw_name, pw->pw_gid); + setgid(pw->pw_gid); + setuid(pw->pw_uid); + + avfs_main(user_fuse); + exit(0); + } + + fuse_destroy(user_fuse); +} + + +static int find_user(const char *userstr, uid_t *uid) +{ + size_t i; + char *end; + + *uid = strtol(userstr, &end, 10); + if(*end != '\0') + return 0; + + pthread_mutex_lock(&lock); + for(i = 0; i < numusers; i++) { + if(users[i] == *uid) { + pthread_mutex_unlock(&lock); + return 1; + } + } + if(numusers == MAX_USERS) { + memmove(users, users + sizeof(users[0]), + (MAX_USERS - 1) * sizeof(users[0])); + numusers --; + } + + users[numusers++] = *uid; + pthread_mutex_unlock(&lock); + + start_avfs(*uid); + + return 1; +} + +static void root_attr(struct stat *stbuf) +{ + stbuf->st_mode = S_IFDIR | 0555; + stbuf->st_nlink = 2 + numusers; + stbuf->st_size = MAX_USERS; + stbuf->st_blksize = 1024; +} + +static int um_getattr(struct fuse_cred *cred, const char *path, + struct stat *stbuf) +{ + uid_t uid; + memset(stbuf, 0, sizeof(*stbuf)); + + if(strcmp(path, "/") == 0) { + root_attr(stbuf); + return 0; + } + + if(!find_user(path+1, &uid)) + return -ENOENT; + + stbuf->st_mode = S_IFLNK | 0777; + stbuf->st_nlink = 1; + stbuf->st_size = strlen(MOUNTDIR) + 1 + 10; + stbuf->st_blksize = 1024; + stbuf->st_uid = uid; + + return 0; +} + +static int um_readlink(struct fuse_cred *cred, const char *path, char *buf, + size_t size) +{ + uid_t uid; + + if(!find_user(path+1, &uid)) + return -ENOENT; + + snprintf(buf, size, "%s/%010u", MOUNTDIR, uid); + return 0; +} + +static int um_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h, + fuse_dirfil_t filler) +{ + size_t i; + + if(strcmp(path, "/") != 0) + return 0; + + filler(h, ".", 0); + filler(h, "..", 0); + + pthread_mutex_lock(&lock); + for(i = 0; i < numusers; i++) { + char buf[32]; + + sprintf(buf, "%u", users[i]); + filler(h, buf, 0); + } + pthread_mutex_unlock(&lock); + + return 0; +} + + +static void exit_handler() +{ + exit(0); +} + +static void child_handler() +{ + int status; + wait(&status); +} + +static void set_signal_handlers() +{ + struct sigaction sa; + + sa.sa_handler = exit_handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; + + if (sigaction(SIGHUP, &sa, NULL) == -1 || + sigaction(SIGINT, &sa, NULL) == -1 || + sigaction(SIGTERM, &sa, NULL) == -1) { + + perror("Cannot set exit signal handlers"); + exit(1); + } + + sa.sa_handler = SIG_IGN; + + if(sigaction(SIGPIPE, &sa, NULL) == -1) { + perror("Cannot set ignored signals"); + exit(1); + } + + sa.sa_handler = child_handler; + if(sigaction(SIGCHLD, &sa, NULL) == -1) { + perror("Cannot set child signal handler"); + exit(1); + } +} + +static void cleanup() +{ + fuse_unmount(um_fuse); + fuse_destroy(um_fuse); +} + +static struct fuse_operations um_oper = { + getattr: um_getattr, + getdir: um_getdir, + readlink: um_readlink, +}; + +int main(int argc, char *argv[]) +{ + int res; + if(argc != 2) { + fprintf(stderr, "usage: %s mount_dir\n", argv[0]); + exit(1); + } + + um_dir = argv[1]; + + set_signal_handlers(); + atexit(cleanup); + + um_fuse = fuse_new(0); + res = fuse_mount(um_fuse, um_dir); + if(res == -1) + exit(1); + + fuse_set_operations(um_fuse, &um_oper); + fuse_loop(um_fuse); + + return 0; +} -- cgit v1.2.3