@@ -1,7 +1,8 @@ #define FUSE_USE_VERSION 26 +#include #include #include #include #include #include @@ -299,10 +300,42 @@ return(1); } return(ctx->uid); } + +/* + * Determine the GID for the user making the current FUSE filesystem request. + * This will be used to lookup the user's home directory so we can search for + * locally modified files. + */ +static gid_t appfs_get_fsgid(void) { + struct fuse_context *ctx; + + if (!appfs_fuse_started) { + return(getgid()); + } + + ctx = fuse_get_context(); + if (ctx == NULL) { + /* Unable to lookup user for some reason */ + /* Return an unprivileged user ID */ + return(1); + } + + return(ctx->gid); +} + +static void appfs_simulate_user_fs_enter(void) { + setfsuid(appfs_get_fsuid()); + setfsgid(appfs_get_fsgid()); +} + +static void appfs_simulate_user_fs_leave(void) { + setfsuid(0); + setfsgid(0); +} /* * Look up the home directory for a given UID * Returns a C string containing the user's home directory or NULL if * the user's home directory does not exist or is not correctly @@ -359,25 +392,46 @@ * Tcl interface to get the home directory for the user making the "current" * FUSE I/O request */ static int tcl_appfs_get_homedir(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { char *homedir; + Tcl_Obj *homedir_obj; + uid_t fsuid; + static __thread Tcl_Obj *last_homedir_obj = NULL; + static __thread uid_t last_fsuid = -1; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return(TCL_ERROR); } - homedir = appfs_get_homedir(appfs_get_fsuid()); + fsuid = appfs_get_fsuid(); - if (homedir == NULL) { - return(TCL_ERROR); + if (fsuid == last_fsuid && last_homedir_obj != NULL) { + homedir_obj = last_homedir_obj; + } else { + if (last_homedir_obj != NULL) { + Tcl_DecrRefCount(last_homedir_obj); + } + + homedir = appfs_get_homedir(appfs_get_fsuid()); + + if (homedir == NULL) { + return(TCL_ERROR); + } + + homedir_obj = Tcl_NewStringObj(homedir, -1); + + free(homedir); + + last_homedir_obj = homedir_obj; + last_fsuid = fsuid; + + Tcl_IncrRefCount(last_homedir_obj); } - Tcl_SetObjResult(interp, Tcl_NewStringObj(homedir, -1)); - - free(homedir); + Tcl_SetObjResult(interp, homedir_obj); return(TCL_OK); } /* @@ -630,10 +684,11 @@ stbuf->st_ctime = pathinfo.time; stbuf->st_atime = pathinfo.time; stbuf->st_ino = pathinfo.inode; stbuf->st_mode = 0; stbuf->st_uid = appfs_get_fsuid(); + stbuf->st_gid = appfs_get_fsgid(); switch (pathinfo.type) { case APPFS_PATHTYPE_DIRECTORY: stbuf->st_mode = S_IFDIR | 0555; stbuf->st_nlink = 2 + pathinfo.typeinfo.dir.childcount; @@ -744,27 +799,36 @@ interp = appfs_TclInterp(); if (interp == NULL) { return(-EIO); } + + appfs_simulate_user_fs_enter(); tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, mode); if (tcl_ret != TCL_OK) { + appfs_simulate_user_fs_leave(); + APPFS_DEBUG("::appfs::openpath(%s, %s) failed.", path, mode); APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); return(-EIO); } real_path = Tcl_GetStringResult(interp); if (real_path == NULL) { + appfs_simulate_user_fs_leave(); + return(-EIO); } APPFS_DEBUG("Translated request to open %s to opening %s (mode = \"%s\")", path, real_path, mode); fh = open(real_path, fi->flags, 0600); + + appfs_simulate_user_fs_leave(); + if (fh < 0) { return(-EIO); } fi->fh = fh; @@ -826,17 +890,23 @@ } if ((mode & S_IFBLK) == S_IFBLK) { return(-EPERM); } + + appfs_simulate_user_fs_enter(); real_path = appfs_prepare_to_create(path); if (real_path == NULL) { + appfs_simulate_user_fs_leave(); + return(-EIO); } mknod_ret = mknod(real_path, mode, device); + + appfs_simulate_user_fs_leave(); free(real_path); if (mknod_ret != 0) { return(errno * -1); @@ -856,17 +926,23 @@ } if ((mode & S_IFBLK) == S_IFBLK) { return(-EPERM); } + + appfs_simulate_user_fs_enter(); real_path = appfs_prepare_to_create(path); if (real_path == NULL) { + appfs_simulate_user_fs_leave(); + return(-EIO); } fd = creat(real_path, mode); + + appfs_simulate_user_fs_leave(); free(real_path); if (fd < 0) { return(errno * -1); @@ -885,12 +961,16 @@ real_path = appfs_localpath(path); if (real_path == NULL) { return(-EIO); } + + appfs_simulate_user_fs_enter(); truncate_ret = truncate(real_path, size); + + appfs_simulate_user_fs_leave(); free(real_path); if (truncate_ret != 0) { return(errno * -1); @@ -907,12 +987,17 @@ interp = appfs_TclInterp(); if (interp == NULL) { return(-EIO); } + + appfs_simulate_user_fs_enter(); tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::unlinkpath", path); + + appfs_simulate_user_fs_leave(); + if (tcl_ret != TCL_OK) { APPFS_DEBUG("::appfs::unlinkpath(%s) failed.", path); APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); return(-EIO); @@ -924,17 +1009,23 @@ static int appfs_fuse_mkdir(const char *path, mode_t mode) { char *real_path; int mkdir_ret; APPFS_DEBUG("Enter (path = %s, ...)", path); + + appfs_simulate_user_fs_enter(); real_path = appfs_prepare_to_create(path); if (real_path == NULL) { + appfs_simulate_user_fs_leave(); + return(-EIO); } mkdir_ret = mkdir(real_path, mode); + + appfs_simulate_user_fs_leave(); free(real_path); if (mkdir_ret != 0) { if (errno != EEXIST) { @@ -954,25 +1045,33 @@ interp = appfs_TclInterp(); if (interp == NULL) { return(-EIO); } + + appfs_simulate_user_fs_enter(); tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::openpath", path, "write"); if (tcl_ret != TCL_OK) { + appfs_simulate_user_fs_leave(); + APPFS_DEBUG("::appfs::openpath(%s, %s) failed.", path, "write"); APPFS_DEBUG("Tcl Error is: %s", Tcl_GetStringResult(interp)); return(-EIO); } real_path = Tcl_GetStringResult(interp); if (real_path == NULL) { + appfs_simulate_user_fs_leave(); + return(-EIO); } chmod_ret = chmod(real_path, mode); + + appfs_simulate_user_fs_leave(); return(chmod_ret); } /*