static int do_mount(const char *mnt, char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) { int res; int flags = MS_NOSUID | MS_NODEV; char *optbuf; char *mnt_opts = NULL; const char *s; char *d; char *fsname = NULL; char *subtype = NULL; char *source = NULL; char *type = NULL; int check_empty = 1; int blkdev = 0; optbuf = (char *) malloc(strlen(opts) + 128); if (!optbuf) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; const char *subtype_str = "subtype="; for (len = 0; s[len]; len++) { if (s[len] == '\\' && s[len + 1]) len++; else if (s[len] == ',') break; } if (begins_with(s, fsname_str)) { if (!get_string_opt(s, len, fsname_str, &fsname)) goto err; } else if (begins_with(s, subtype_str)) { if (!get_string_opt(s, len, subtype_str, &subtype)) goto err; } else if (opt_eq(s, len, "blkdev")) { if (getuid() != 0) { fprintf(stderr, "%s: option blkdev is privileged\n", progname); goto err; } blkdev = 1; } else if (opt_eq(s, len, "nonempty")) { check_empty = 0; } else if (!begins_with(s, "fd=") && !begins_with(s, "rootmode=") && !begins_with(s, "user_id=") && !begins_with(s, "group_id=")) { int on; int flag; int skip_option = 0; if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); if (res == 0 && sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && (kmaj > 2 || (kmaj == 2 && kmin > 4))) { fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); skip_option = 1; } } if (getuid() != 0 && !user_allow_other && (opt_eq(s, len, "allow_other") || opt_eq(s, len, "allow_root"))) { fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); goto err; } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) flags |= flag; else flags &= ~flag; } else { memcpy(d, s, len); d += len; *d++ = ','; } } } s += len; if (*s) s++; } *d = '\0'; res = get_mnt_opts(flags, optbuf, &mnt_opts); if (res == -1) goto err; sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, rootmode, getuid(), getgid()); if (check_empty && fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) goto err; source = malloc((fsname ? strlen(fsname) : 0) + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); type = malloc((subtype ? strlen(subtype) : 0) + 32); if (!type || !source) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } if (subtype) sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); else strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) strcpy(source, fsname); else strcpy(source, subtype ? subtype : dev); res = mount(source, mnt, type, flags, optbuf); if (res == -1 && errno == ENODEV && subtype) { /* Probably missing subtype support */ strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) { if (!blkdev) sprintf(source, "%s#%s", subtype, fsname); } else { strcpy(source, type); } res = mount(source, mnt, type, flags, optbuf); } if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); res = mount(source, mnt, type, flags, optbuf); } if (res == -1) { int errno_save = errno; if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); else fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; } *sourcep = source; *typep = type; *mnt_optsp = mnt_opts; free(fsname); free(optbuf); return 0; err: free(fsname); free(subtype); free(source); free(type); free(mnt_opts); free(optbuf); return -1; }
static int do_mount(const char *mnt, char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) { int res; #ifdef __SOLARIS__ /* * In Solaris, nosuid is equivalent to nosetuid + nodevices. We only * have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if * we set that as a default, it restricts specifying just nosetuid * or nodevices; there is no way for the user to specify setuid + * nodevices or vice-verse. * On the chance that this is being run from root, we won't try * to add nosetuid or nodevices restrictions; this program must * be exec'd from the library, where we've already sanitized the * options. */ int flags = 0; #else int flags = MS_NOSUID | MS_NODEV; #endif /* __SOLARIS__ */ char *optbuf; char *mnt_opts = NULL; const char *s; char *d; char *fsname = NULL; char *subtype = NULL; char *source = NULL; char *type = NULL; int check_empty = 1; int blkdev = 0; optbuf = (char *) malloc(strlen(opts) + 128); if (!optbuf) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; const char *subtype_str = "subtype="; for (len = 0; s[len] && s[len] != ','; len++); if (begins_with(s, fsname_str)) { if (!get_string_opt(s, len, fsname_str, &fsname)) goto err; } else if (begins_with(s, subtype_str)) { if (!get_string_opt(s, len, subtype_str, &subtype)) goto err; } else if (opt_eq(s, len, "blkdev")) { if (getuid() != 0) { fprintf(stderr, "%s: option blkdev is privileged\n", progname); goto err; } blkdev = 1; } else if (opt_eq(s, len, "nonempty")) { check_empty = 0; } else if (!begins_with(s, "fd=") && !begins_with(s, "rootmode=") && !begins_with(s, "user_id=") && !begins_with(s, "group_id=")) { int on; int flag; int skip_option = 0; if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); if (res == 0 && sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && (kmaj > 2 || (kmaj == 2 && kmin > 4))) { fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); skip_option = 1; } } if (getuid() != 0 && !user_allow_other && (opt_eq(s, len, "allow_other") || opt_eq(s, len, "allow_root"))) { fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); goto err; } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) flags |= flag; else flags &= ~flag; } else { memcpy(d, s, len); d += len; *d++ = ','; } } } s += len; if (*s) s++; } *d = '\0'; res = get_mnt_opts(flags, optbuf, &mnt_opts); if (res == -1) goto err; sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, rootmode, getuid(), getgid()); if (check_empty && fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) goto err; source = malloc((fsname ? strlen(fsname) : 0) + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); type = malloc((subtype ? strlen(subtype) : 0) + 32); if (!type || !source) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } if (subtype) sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); else strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) strcpy(source, fsname); else strcpy(source, subtype ? subtype : dev); #ifdef __SOLARIS__ res = mount(source, mnt, MS_OPTIONSTR|flags, type, NULL, 0, optbuf, MAX_MNTOPT_STR); #else res = mount(source, mnt, type, flags, optbuf); #endif /* __SOLARIS__ */ #ifdef __SOLARIS__ if (res == -1 && errno == EINVAL && subtype) { #else if (res == -1 && errno == ENODEV && subtype) { #endif /* Probably missing subtype support */ strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) { if (!blkdev) sprintf(source, "%s#%s", subtype, fsname); } else { strcpy(source, type); } #ifdef __SOLARIS__ res = mount(source, mnt, MS_OPTIONSTR|flags, type, NULL, 0, optbuf, MAX_MNTOPT_STR); #else res = mount(source, mnt, type, flags, optbuf); #endif /* __SOLARIS__ */ } if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); #ifdef __SOLARIS__ res = mount(dev, mnt, MS_OPTIONSTR|flags, type, NULL, 0, optbuf, MAX_MNTOPT_STR); #else res = mount(source, mnt, type, flags, optbuf); #endif /* __SOLARIS__ */ } if (res == -1) { int errno_save = errno; if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); else fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; } else { *sourcep = source; *typep = type; *mnt_optsp = mnt_opts; } free(optbuf); return res; err: free(fsname); free(subtype); free(source); free(type); free(mnt_opts); free(optbuf); return -1; } static int check_version(const char *dev) { int res; int majorver; int minorver; const char *version_file; FILE *vf; if (strcmp(dev, FUSE_DEV_OLD) != 0) return 0; version_file = FUSE_VERSION_FILE_OLD; vf = fopen(version_file, "r"); if (vf == NULL) { fprintf(stderr, "%s: kernel interface too old\n", progname); return -1; } res = fscanf(vf, "%i.%i", &majorver, &minorver); fclose(vf); if (res != 2) { fprintf(stderr, "%s: error reading %s\n", progname, version_file); return -1; } if (majorver < 3) { fprintf(stderr, "%s: kernel interface too old\n", progname); return -1; } return 0; }
static int do_mount(const char *mnt, char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp) { int res; int flags = MS_NOSUID | MS_NODEV; char *optbuf; char *mnt_opts = NULL; const char *s; char *d; char *fsname = NULL; char *source = NULL; char *type = NULL; int blkdev = 0; optbuf = (char *) malloc(strlen(opts) + 128); if (!optbuf) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; for (len = 0; s[len] && s[len] != ','; len++); if (begins_with(s, fsname_str)) { if (!get_string_opt(s, len, fsname_str, &fsname)) goto err; } else if (opt_eq(s, len, "blkdev")) { blkdev = 1; } else if (!begins_with(s, "fd=") && !begins_with(s, "rootmode=") && !begins_with(s, "user_id=") && !begins_with(s, "group_id=")) { int on; int flag; int skip_option = 0; if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); if (res == 0 && sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && (kmaj > 2 || (kmaj == 2 && kmin > 4))) { fprintf(stderr, "%s: note: 'large_read' mount option is " "deprecated for %i.%i kernels\n", progname, kmaj, kmin); skip_option = 1; } } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) flags |= flag; else flags &= ~flag; } else { memcpy(d, s, len); d += len; *d++ = ','; } } } s += len; if (*s) s++; } *d = '\0'; res = get_mnt_opts(flags, optbuf, &mnt_opts); if (res == -1) goto err; sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, rootmode, getuid(), getgid()); source = malloc((fsname ? strlen(fsname) : 0) + strlen(dev) + 32); type = malloc(32); if (!type || !source) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) strcpy(source, fsname); else strcpy(source, dev); if (restore_privs()) goto err; res = mount(source, mnt, type, flags, optbuf); if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); res = mount(source, mnt, type, flags, optbuf); } if (drop_privs()) goto err; if (res == -1) { int errno_save = errno; if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); else { fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); if (errno_save == EPERM) fprintf(stderr, "User doesn't have privilege to mount. " "For more information\nplease see: " "http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n"); } goto err; } else { *sourcep = source; *typep = type; *mnt_optsp = mnt_opts; } out: free(fsname); free(optbuf); return res; err: free(source); free(type); free(mnt_opts); res = -1; goto out; }
static int do_mount(const char *mnt, const char **type, mode_t rootmode, int fd, const char *opts, const char *dev, char **fsnamep, char **mnt_optsp, off_t rootsize) { int res; int flags = MS_NOSUID | MS_NODEV; char *optbuf; char *mnt_opts = NULL; const char *s; char *d; char *fsname = NULL; int check_empty = 1; int blkdev = 0; optbuf = (char *) malloc(strlen(opts) + 128); if (!optbuf) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; for (len = 0; s[len] && s[len] != ','; len++); if (begins_with(s, fsname_str)) { unsigned fsname_str_len = strlen(fsname_str); if (fsname) free(fsname); fsname = (char *) malloc(len - fsname_str_len + 1); if (!fsname) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } memcpy(fsname, s + fsname_str_len, len - fsname_str_len); fsname[len - fsname_str_len] = '\0'; } else if (opt_eq(s, len, "blkdev")) { if (getuid() != 0) { fprintf(stderr, "%s: option blkdev is privileged\n", progname); goto err; } blkdev = 1; } else if (opt_eq(s, len, "nonempty")) { check_empty = 0; } else if (!begins_with(s, "fd=") && !begins_with(s, "rootmode=") && !begins_with(s, "user_id=") && !begins_with(s, "group_id=")) { int on; int flag; int skip_option = 0; if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); if (res == 0 && sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && (kmaj > 2 || (kmaj == 2 && kmin > 4))) { fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); skip_option = 1; } } if (getuid() != 0 && !user_allow_other && (opt_eq(s, len, "allow_other") || opt_eq(s, len, "allow_root"))) { fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); goto err; } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) flags |= flag; else flags &= ~flag; } else { memcpy(d, s, len); d += len; *d++ = ','; } } } s += len; if (*s) s++; } *d = '\0'; res = get_mnt_opts(flags, optbuf, &mnt_opts); if (res == -1) goto err; sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, rootmode, getuid(), getgid()); if (fsname == NULL) { fsname = strdup(dev); if (!fsname) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } } if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1) goto err; if (blkdev) *type = "fuseblk"; res = mount(fsname, mnt, *type, flags, optbuf); if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); res = mount(fsname, mnt, *type, flags, optbuf); } if (res == -1) { int errno_save = errno; if (blkdev && errno == ENODEV && !has_fuseblk()) fprintf(stderr, "%s: 'fuseblk' support missing; try the kernel module from fuse-2.6.0 or later\n", progname); else fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; } else { *fsnamep = fsname; *mnt_optsp = mnt_opts; } free(optbuf); return res; err: free(fsname); free(mnt_opts); free(optbuf); return -1; }