aboutsummaryrefslogtreecommitdiffstats
path: root/usermux.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2001-11-06 12:03:23 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2001-11-06 12:03:23 +0000
commita181e61ca0119b8c3fd2daa4b8d23add2cda3ed0 (patch)
tree57176d5ca8f96008180eac92518791ef22add726 /usermux.c
parent5e183482b09cec20f54ccb44e767a7fab51833e9 (diff)
downloadlibfuse-a181e61ca0119b8c3fd2daa4b8d23add2cda3ed0.tar.gz
bugfixes
Diffstat (limited to 'usermux.c')
-rw-r--r--usermux.c252
1 files changed, 252 insertions, 0 deletions
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 <fuse.h>
+
+#include <pthread.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <wait.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#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;
+}