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;
}
Beispiel #2
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, 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;
}
Beispiel #3
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;
}
Beispiel #4
0
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;
}