Workaround FUSE/Linux-kernel to try ourselves to modprobe FUSE on ENODEV.
[captive.git] / src / client / fuse / fusermount.c
1 /*
2     FUSE: Filesystem in Userspace
3     Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
4
5     This program can be distributed under the terms of the GNU GPL.
6     See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9
10 /*
11  * NOTE: This program should be part of (or be called from) /bin/mount
12  *
13  * Unless that is done, operations on /etc/mtab are not under lock, and so
14  * data in this file may be lost. (I will _not_ reimplement that locking,
15  * and anyway that should be done in libc, if possible.  But probably it
16  * isn't).
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <getopt.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <pwd.h>
30 #include <mntent.h>
31 #include <dirent.h>
32 #include <sys/param.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35 #include <sys/mount.h>
36 #include <sys/fsuid.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <sys/utsname.h>
40 #include <sys/sysmacros.h>
41
42 /* Captive */
43 #include <captive/client.h>
44 #include <linux/kdev_t.h>
45 #include <linux/major.h>
46 #include <grp.h>
47
48 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD"
49
50 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
51 #define FUSE_DEV_NEW "/dev/fuse"
52 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
53 #define FUSE_CONF "/etc/fuse.conf"
54
55 static const char *progname;
56
57 static int user_allow_other = 0;
58 static int mount_max = 1000;
59
60 static const char *get_user_name(void)
61 {
62     struct passwd *pw = getpwuid(getuid());
63     if (pw != NULL && pw->pw_name != NULL)
64         return pw->pw_name;
65     else {
66         fprintf(stderr, "%s: could not determine username\n", progname);
67         return NULL;
68     }
69 }
70
71 static uid_t oldfsuid;
72 static gid_t oldfsgid;
73
74 static void drop_privs(void)
75 {
76     if (getuid() != 0) {
77         oldfsuid = setfsuid(getuid());
78         oldfsgid = setfsgid(getgid());
79     }
80 }
81
82 static void restore_privs(void)
83 {
84     if (getuid() != 0) {
85         setfsuid(oldfsuid);
86         setfsgid(oldfsgid);
87     }
88 }
89
90 static int do_unmount(const char *mnt, int quiet, int lazy)
91 {
92     int res = umount2(mnt, lazy ? 2 : 0);
93     if (res == -1) {
94         if (!quiet)
95             fprintf(stderr, "%s: failed to unmount %s: %s\n",
96                     progname, mnt, strerror(errno));
97     }
98     return res;
99 }
100
101 #ifndef IGNORE_MTAB
102 /* use a lock file so that multiple fusermount processes don't try and
103    modify the mtab file at once! */
104 static int lock_mtab(void)
105 {
106     const char *mtab_lock = _PATH_MOUNTED ".fuselock";
107     int mtablock;
108     int res;
109
110     mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
111     if (mtablock >= 0) {
112         res = lockf(mtablock, F_LOCK, 0);
113         if (res < 0)
114             fprintf(stderr, "%s: error getting lock", progname);
115     } else
116         fprintf(stderr, "%s: unable to open fuse lock file\n", progname);
117
118     return mtablock;
119 }
120
121 static void unlock_mtab(int mtablock)
122 {
123     if (mtablock >= 0) {
124         int trash0=lockf(mtablock, F_ULOCK, 0);
125         close(mtablock);
126     }
127 }
128
129 /* Glibc addmntent() doesn't encode '\n', misencodes '\t' as '\n'
130    (version 2.3.2), and encodes '\\' differently as mount(8).  So
131    let's not allow those characters, they are not all that usual in
132    filenames. */
133 static int check_name(const char *name)
134 {
135     char *s;
136     for (s = "\n\t\\"; *s; s++) {
137         if (strchr(name, *s)) {
138             fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n",
139                     progname, *s);
140             return -1;
141         }
142     }
143     return 0;
144 }
145
146 static int add_mount(const char *fsname, const char *mnt, const char *type,
147                      const char *opts)
148 {
149     int res;
150     const char *mtab = _PATH_MOUNTED;
151     struct mntent ent;
152     FILE *fp;
153
154     if (check_name(fsname) == -1 || check_name(mnt) == -1 || 
155         check_name(type) == -1 || check_name(opts) == -1)
156         return -1;
157
158     fp = setmntent(mtab, "a");
159     if (fp == NULL) {
160         fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
161                 strerror(errno));
162         return -1;
163     }
164
165     ent.mnt_fsname = (char *) fsname;
166     ent.mnt_dir = (char *) mnt;
167     ent.mnt_type = (char *) type;
168     ent.mnt_opts = (char *) opts;
169     ent.mnt_freq = 0;
170     ent.mnt_passno = 0;
171     res = addmntent(fp, &ent);
172     if (res != 0) {
173         fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
174                 mtab, strerror(errno));
175         return -1;
176     }
177
178     endmntent(fp);
179     return 0;
180 }
181
182 static int remove_mount(const char *mnt, int quiet, const char *mtab,
183                         const char *mtab_new)
184 {
185     int res;
186     struct mntent *entp;
187     FILE *fp;
188     FILE *newfp;
189     const char *user = NULL;
190     char uidstr[32];
191     unsigned uidlen = 0;
192     int found;
193
194     fp = setmntent(mtab, "r");
195     if (fp == NULL) {
196         fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
197                 strerror(errno));
198         return -1;
199     }
200
201     newfp = setmntent(mtab_new, "w");
202     if (newfp == NULL) {
203         fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,
204                 strerror(errno));
205         return -1;
206     }
207
208     if (getuid() != 0) {
209         user = get_user_name();
210         if (user == NULL)
211             return -1;
212
213         uidlen = sprintf(uidstr, "%u", getuid());
214     }
215
216     found = 0;
217     while ((entp = getmntent(fp)) != NULL) {
218         int removed = 0;
219         if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
220            strcmp(entp->mnt_type, "fuse") == 0) {
221             if (user == NULL)
222                 removed = 1;
223             else {
224                 char *p = strstr(entp->mnt_opts, "user=");
225                 if (p && (p == entp->mnt_opts || *(p-1) == ',') &&
226                     strcmp(p + 5, user) == 0)
227                     removed = 1;
228                 /* /etc/mtab is a link pointing to /proc/mounts: */
229                 else if ((p = strstr(entp->mnt_opts, "user_id=")) &&
230                          (p == entp->mnt_opts || *(p-1) == ',') &&
231                          strncmp(p + 8, uidstr, uidlen) == 0 &&
232                          (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0'))
233                     removed = 1;
234             }
235         }
236         if (removed)
237             found = 1;
238         else {
239             res = addmntent(newfp, entp);
240             if (res != 0) {
241                 fprintf(stderr, "%s: failed to add entry to %s: %s\n",
242                         progname, mtab_new, strerror(errno));
243             }
244         }
245     }
246
247     endmntent(fp);
248     endmntent(newfp);
249
250     if (!found) {
251         if (!quiet)
252             fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
253                     mnt, mtab);
254         unlink(mtab_new);
255         return -1;
256     }
257
258     return 0;
259 }
260
261 static int count_fuse_fs(void)
262 {
263     struct mntent *entp;
264     int count = 0;
265     const char *mtab = _PATH_MOUNTED;
266     FILE *fp = setmntent(mtab, "r");
267     if (fp == NULL) {
268         fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
269                 strerror(errno));
270         return -1;
271     }
272     while ((entp = getmntent(fp)) != NULL) {
273         if (strcmp(entp->mnt_type, "fuse") == 0)
274             count ++;
275     }
276     endmntent(fp);
277     return count;
278 }
279
280 static int unmount_rename(const char *mnt, int quiet, int lazy,
281                           const char *mtab, const char *mtab_new)
282 {
283     int res;
284     struct stat sbuf;
285
286     drop_privs();
287     res = do_unmount(mnt, quiet, lazy);
288     restore_privs();
289     if (res == -1)
290         return -1;
291
292     if (stat(mtab, &sbuf) == 0) {
293         int trash0=chown(mtab_new, sbuf.st_uid, sbuf.st_gid);
294                                 }
295
296     res = rename(mtab_new, mtab);
297     if (res == -1) {
298         fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
299                 mtab_new, mtab, strerror(errno));
300         return -1;
301     }
302     return 0;
303 }
304
305 static int unmount_fuse(const char *mnt, int quiet, int lazy)
306 {
307     int res;
308     const char *mtab = _PATH_MOUNTED;
309     const char *mtab_new = _PATH_MOUNTED "~fuse~";
310
311     res = remove_mount(mnt, quiet, mtab, mtab_new);
312     if (res == -1)
313         return -1;
314
315     res = unmount_rename(mnt, quiet, lazy, mtab, mtab_new);
316     if (res == -1) {
317         unlink(mtab_new);
318         return -1;
319     }
320     return 0;
321 }
322 #else /* IGNORE_MTAB */
323 static int lock_mtab()
324 {
325     return 0;
326 }
327
328 static void unlock_mtab(int mtablock)
329 {
330     (void) mtablock;
331 }
332
333 static int count_fuse_fs()
334 {
335     return 0;
336 }
337
338 static int add_mount(const char *fsname, const char *mnt, const char *type,
339                      const char *opts)
340 {
341     (void) fsname;
342     (void) mnt;
343     (void) type;
344     (void) opts;
345     return 0;
346 }
347
348 static int unmount_fuse(const char *mnt, int quiet, int lazy)
349 {
350     return do_unmount(mnt, quiet, lazy);
351 }
352 #endif /* IGNORE_MTAB */
353
354 static void strip_line(char *line)
355 {
356     char *s = strchr(line, '#');
357     if (s != NULL)
358         s[0] = '\0';
359     for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
360     s[1] = '\0';
361     for (s = line; isspace((unsigned char) *s); s++);
362     if (s != line)
363         memmove(line, s, strlen(s)+1);
364 }
365
366 static void parse_line(char *line, int linenum)
367 {
368     int tmp;
369     if (strcmp(line, "user_allow_other") == 0)
370         user_allow_other = 1;
371     else if (sscanf(line, "mount_max = %i", &tmp) == 1)
372         mount_max = tmp;
373     else if(line[0])
374         fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
375                 progname, FUSE_CONF, linenum, line);
376 }
377
378 static void read_conf(void)
379 {
380     FILE *fp = fopen(FUSE_CONF, "r");
381     if (fp != NULL) {
382         int linenum = 1;
383         char line[256];
384         int isnewline = 1;
385         while (fgets(line, sizeof(line), fp) != NULL) {
386             if (isnewline) {
387                 if (line[strlen(line)-1] == '\n') {
388                     strip_line(line);
389                     parse_line(line, linenum);
390                 } else {
391                     fprintf(stderr, "%s: reading %s: line %i too long\n",
392                             progname, FUSE_CONF, linenum);
393                     isnewline = 0;
394                 }
395             } else if(line[strlen(line)-1] == '\n')
396                 isnewline = 1;
397             if (isnewline)
398                 linenum ++;
399         }
400         fclose(fp);
401     } else if (errno != ENOENT) {
402         fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
403                 strerror(errno));
404     }
405 }
406
407 static int begins_with(const char *s, const char *beg)
408 {
409     if (strncmp(s, beg, strlen(beg)) == 0)
410         return 1;
411     else
412         return 0;
413 }
414
415 struct mount_flags {
416     const char *opt;
417     unsigned long flag;
418     int on;
419     int safe;
420 };
421
422 static struct mount_flags mount_flags[] = {
423     {"rw",      MS_RDONLY,      0, 1},
424     {"ro",      MS_RDONLY,      1, 1},
425     {"suid",    MS_NOSUID,      0, 0},
426     {"nosuid",  MS_NOSUID,      1, 1},
427     {"dev",     MS_NODEV,       0, 0},
428     {"nodev",   MS_NODEV,       1, 1},
429     {"exec",    MS_NOEXEC,      0, 1},
430     {"noexec",  MS_NOEXEC,      1, 1},
431     {"async",   MS_SYNCHRONOUS, 0, 1},
432     {"sync",    MS_SYNCHRONOUS, 1, 1},
433     {"atime",   MS_NOATIME,     0, 1},
434     {"noatime", MS_NOATIME,     1, 1},
435     {NULL,      0,              0, 0}
436 };
437
438 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
439 {
440     int i;
441
442     for (i = 0; mount_flags[i].opt != NULL; i++) {
443         const char *opt = mount_flags[i].opt;
444         if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
445             *on = mount_flags[i].on;
446             *flag = mount_flags[i].flag;
447             if (!mount_flags[i].safe && getuid() != 0) {
448                 *flag = 0;
449                 fprintf(stderr, "%s: unsafe option %s ignored\n",
450                         progname, opt);
451             }
452             return 1;
453         }
454     }
455     return 0;
456 }
457
458 static int add_option(char **optsp, const char *opt, unsigned expand)
459 {
460     char *newopts;
461     if (*optsp == NULL)
462         newopts = strdup(opt);
463     else {
464         unsigned oldsize = strlen(*optsp);
465         unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
466         newopts = (char *) realloc(*optsp, newsize);
467         if (newopts)
468             sprintf(newopts + oldsize, ",%s", opt);
469     }
470     if (newopts == NULL) {
471         fprintf(stderr, "%s: failed to allocate memory\n", progname);
472         return -1;
473     }
474     *optsp = newopts;
475     return 0;
476 }
477
478 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
479 {
480     int i;
481     int l;
482
483     if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
484         return -1;
485
486     for (i = 0; mount_flags[i].opt != NULL; i++) {
487         if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
488             add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
489             return -1;
490     }
491
492     if (add_option(mnt_optsp, opts, 0) == -1)
493         return -1;
494     /* remove comma from end of opts*/
495     l = strlen(*mnt_optsp);
496     if ((*mnt_optsp)[l-1] == ',')
497         (*mnt_optsp)[l-1] = '\0';
498     if (getuid() != 0) {
499         const char *user = get_user_name();
500         if (user == NULL)
501             return -1;
502
503         if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
504             return -1;
505         strcat(*mnt_optsp, user);
506     }
507     return 0;
508 }
509
510 static int opt_eq(const char *s, unsigned len, const char *opt)
511 {
512     if(strlen(opt) == len && strncmp(s, opt, len) == 0)
513         return 1;
514     else
515         return 0;
516 }
517
518 static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
519                                   off_t rootsize)
520 {
521     int isempty = 1;
522
523     if (S_ISDIR(rootmode)) {
524         struct dirent *ent;
525         DIR *dp = opendir(mnt);
526         if (dp == NULL) {
527             fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",
528                     progname, strerror(errno));
529             return -1;
530         }
531         while ((ent = readdir(dp)) != NULL) {
532             if (strcmp(ent->d_name, ".") != 0 &&
533                 strcmp(ent->d_name, "..") != 0) {
534                 isempty = 0;
535                 break;
536             }
537         }
538         closedir(dp);
539     } else if (rootsize)
540         isempty = 0;
541
542     if (!isempty) {
543         fprintf(stderr, "%s: mountpoint is not empty\n", progname);
544         fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
545         return -1;
546     }
547     return 0;
548 }
549
550 static int do_mount(const char *mnt, const char *type, mode_t rootmode,
551                     int fd, const char *opts, const char *dev, char **fsnamep,
552                     char **mnt_optsp, off_t rootsize)
553 {
554     int res;
555     int flags = MS_NOSUID | MS_NODEV;
556     char *optbuf;
557     char *mnt_opts = NULL;
558     const char *s;
559     char *d;
560     char *fsname = NULL;
561     int check_empty = 1;
562
563     optbuf = (char *) malloc(strlen(opts) + 128);
564     if (!optbuf) {
565         fprintf(stderr, "%s: failed to allocate memory\n", progname);
566         return -1;
567     }
568
569     for (s = opts, d = optbuf; *s;) {
570         unsigned len;
571         const char *fsname_str = "fsname=";
572         for (len = 0; s[len] && s[len] != ','; len++);
573         if (begins_with(s, fsname_str)) {
574             unsigned fsname_str_len = strlen(fsname_str);
575             if (fsname)
576                 free(fsname);
577             fsname = (char *) malloc(len - fsname_str_len + 1);
578             if (!fsname) {
579                 fprintf(stderr, "%s: failed to allocate memory\n", progname);
580                 goto err;
581             }
582             memcpy(fsname, s + fsname_str_len, len - fsname_str_len);
583             fsname[len - fsname_str_len] = '\0';
584         } else if (opt_eq(s, len, "nonempty")) {
585             check_empty = 0;
586         } else if (!begins_with(s, "fd=") &&
587                    !begins_with(s, "rootmode=") &&
588                    !begins_with(s, "user_id=") &&
589                    !begins_with(s, "group_id=")) {
590             int on;
591             int flag;
592             int skip_option = 0;
593             if (opt_eq(s, len, "large_read")) {
594                 struct utsname utsname;
595                 unsigned kmaj, kmin;
596                 res = uname(&utsname);
597                 if (res == 0 &&
598                     sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
599                     (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
600                     fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
601                     skip_option = 1;
602                 }
603             }
604             if (getuid() != 0 && !user_allow_other &&
605                 (opt_eq(s, len, "allow_other") ||
606                  opt_eq(s, len, "allow_root"))) {
607                 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
608                 goto err;
609             }
610             if (!skip_option) {
611                 if (find_mount_flag(s, len, &on, &flag)) {
612                     if (on)
613                         flags |= flag;
614                     else
615                         flags  &= ~flag;
616                 } else {
617                     memcpy(d, s, len);
618                     d += len;
619                     *d++ = ',';
620                 }
621             }
622         }
623         s += len;
624         if (*s)
625             s++;
626     }
627     *d = '\0';
628     res = get_mnt_opts(flags, optbuf, &mnt_opts);
629     if (res == -1)
630         goto err;
631
632     sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
633             fd, rootmode, getuid(), getgid());
634     if (fsname == NULL) {
635         fsname = strdup(dev);
636         if (!fsname) {
637             fprintf(stderr, "%s: failed to allocate memory\n", progname);
638             goto err;
639         }
640     }
641
642     if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
643         goto err;
644
645     res = mount(fsname, mnt, type, flags, optbuf);
646     if (res == -1 && errno == EINVAL) {
647         /* It could be an old version not supporting group_id */
648         sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid());
649         res = mount(fsname, mnt, type, flags, optbuf);
650     }
651     if (res == -1) {
652         fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
653         goto err;
654     } else {
655         *fsnamep = fsname;
656         *mnt_optsp = mnt_opts;
657     }
658     free(optbuf);
659
660     return res;
661
662  err:
663     free(fsname);
664     free(mnt_opts);
665     free(optbuf);
666     return -1;
667 }
668
669 static int check_version(const char *dev)
670 {
671     int res;
672     int majorver;
673     int minorver;
674     const char *version_file;
675     FILE *vf;
676
677     if (strcmp(dev, FUSE_DEV_OLD) != 0)
678         return 0;
679
680     version_file = FUSE_VERSION_FILE_OLD;
681     vf = fopen(version_file, "r");
682     if (vf == NULL) {
683         fprintf(stderr, "%s: kernel interface too old\n", progname);
684         return -1;
685     }
686     res = fscanf(vf, "%i.%i", &majorver, &minorver);
687     fclose(vf);
688     if (res != 2) {
689         fprintf(stderr, "%s: error reading %s\n", progname, version_file);
690         return -1;
691     }
692      if (majorver < 3) {
693         fprintf(stderr, "%s: kernel interface too old\n", progname);
694         return -1;
695     }
696     return 0;
697 }
698
699 static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
700                       int *mountpoint_fd)
701 {
702     int res;
703     const char *mnt = *mntp;
704     const char *origmnt = mnt;
705
706     res = lstat(mnt, stbuf);
707     if (res == -1) {
708         fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
709                 progname, mnt, strerror(errno));
710         return -1;
711     }
712
713     /* No permission checking is done for root */
714     if (getuid() == 0)
715         return 0;
716
717     if (S_ISDIR(stbuf->st_mode)) {
718         *currdir_fd = open(".", O_RDONLY);
719         if (*currdir_fd == -1) {
720             fprintf(stderr, "%s: failed to open current directory: %s\n",
721                     progname, strerror(errno));
722             return -1;
723         }
724         res = chdir(mnt);
725         if (res == -1) {
726             fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
727                     progname, strerror(errno));
728             return -1;
729         }
730         mnt = *mntp = ".";
731         res = lstat(mnt, stbuf);
732         if (res == -1) {
733             fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
734                     progname, origmnt, strerror(errno));
735             return -1;
736         }
737
738         if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
739             fprintf(stderr, "%s: mountpoint %s not owned by user\n",
740                     progname, origmnt);
741             return -1;
742         }
743
744         res = access(mnt, W_OK);
745         if (res == -1) {
746             fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
747                     progname, origmnt);
748             return -1;
749         }
750     } else if (S_ISREG(stbuf->st_mode)) {
751         static char procfile[256];
752         *mountpoint_fd = open(mnt, O_WRONLY);
753         if (*mountpoint_fd == -1) {
754             fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt,
755                     strerror(errno));
756             return -1;
757         }
758         res = fstat(*mountpoint_fd, stbuf);
759         if (res == -1) {
760             fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
761                     progname, mnt, strerror(errno));
762             return -1;
763         }
764         if (!S_ISREG(stbuf->st_mode)) {
765             fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
766                     progname, mnt);
767             return -1;
768         }
769
770         sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
771         *mntp = procfile;
772     } else {
773         fprintf(stderr,
774                 "%s: mountpoint %s is not a directory or a regular file\n",
775                 progname, mnt);
776         return -1;
777     }
778
779
780     return 0;
781 }
782
783 static int try_open(const char *dev, char **devp, int silent)
784 {
785     int fd = open(dev, O_RDWR);
786     /* Captive */
787     if (fd == -1 && errno == ENOENT && !strcmp(dev, FUSE_DEV_NEW)
788         && !mknod(dev, 0660 | S_IFCHR, MKDEV(MISC_MAJOR, 229))) {
789         struct group *group;
790
791         fprintf(stderr, "%s: Notice: Created FUSE device: %s\n", progname, dev);
792         if ((group = getgrnam("fuse")) && !chown(dev, 0, group->gr_gid))
793             fd = open(dev, O_RDWR);
794     }
795     if (fd == -1 && errno == ENODEV) {
796         const char *cmd = "/sbin/modprobe fuse";
797
798         if (!system(cmd))
799             fprintf(stderr, "%s: Notice: Loaded Linux kernel module FUSE: %s\n",
800                     progname, cmd);
801         else
802             fprintf(stderr, "%s: Warning: \"%s\" cannot be opened and even failed: %s\n",
803                     progname, dev, cmd);
804         fd = open(dev, O_RDWR);
805     }
806     if (fd != -1) {
807         *devp = strdup(dev);
808         if (*devp == NULL) {
809             fprintf(stderr, "%s: failed to allocate memory\n", progname);
810             close(fd);
811             fd = -1;
812         }
813     } else if (errno == ENODEV)
814         return -2;
815     else if (!silent) {
816         fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
817                 strerror(errno));
818     }
819     return fd;
820 }
821
822 static int try_open_fuse_device(char **devp)
823 {
824     int fd;
825     int err;
826
827     drop_privs();
828     fd = try_open(FUSE_DEV_NEW, devp, 0);
829     restore_privs();
830     if (fd >= 0)
831         return fd;
832
833     err = fd;
834     fd = try_open(FUSE_DEV_OLD, devp, 1);
835     if (fd >= 0)
836         return fd;
837
838     return err;
839 }
840
841 static int open_fuse_device(char **devp)
842 {
843     int fd = try_open_fuse_device(devp);
844     if (fd >= 0)
845         return fd;
846
847     if (fd == -2)
848         fprintf(stderr,
849                 "%s: fuse device not found, try 'modprobe fuse' first\n",
850                 progname);
851     return -1;
852 }
853
854
855 static int mount_fuse(const char *mnt, const char *opts)
856 {
857     int res;
858     int fd;
859     char *dev;
860     const char *type = "fuse";
861     struct stat stbuf;
862     char *fsname = NULL;
863     char *mnt_opts = NULL;
864     const char *real_mnt = mnt;
865     int currdir_fd = -1;
866     int mountpoint_fd = -1;
867     int mtablock = -1;
868
869     fd = open_fuse_device(&dev);
870     if (fd == -1)
871         return -1;
872
873     if (geteuid() == 0) {
874         mtablock = lock_mtab();
875         if (mtablock < 0) {
876             close(fd);
877             return -1;
878         }
879     }
880
881     drop_privs();
882     read_conf();
883
884     if (getuid() != 0 && mount_max != -1) {
885         int mount_count = count_fuse_fs();
886         if (mount_count >= mount_max) {
887             fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
888             close(fd);
889             unlock_mtab(mtablock);
890             return -1;
891         }
892     }
893
894     res = check_version(dev);
895     if (res != -1) {
896         res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
897         restore_privs();
898         if (res != -1)
899             res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
900                            dev, &fsname, &mnt_opts, stbuf.st_size);
901     } else
902         restore_privs();
903
904     if (currdir_fd != -1) {
905         int trash0=fchdir(currdir_fd);
906         close(currdir_fd);
907     }
908     if (mountpoint_fd != -1)
909         close(mountpoint_fd);
910
911     if (res == -1) {
912         close(fd);
913         unlock_mtab(mtablock);
914         return -1;
915     }
916
917     if (geteuid() == 0) {
918         res = add_mount(fsname, mnt, type, mnt_opts);
919         unlock_mtab(mtablock);
920         if (res == -1) {
921             umount2(mnt, 2); /* lazy umount */
922             close(fd);
923             return -1;
924         }
925     }
926
927     free(fsname);
928     free(mnt_opts);
929     free(dev);
930
931     return fd;
932 }
933
934 static char *resolve_path(const char *orig)
935 {
936     char buf[PATH_MAX];
937     char *copy;
938     char *dst;
939     char *end;
940     char *lastcomp;
941     const char *toresolv;
942
943     if (!orig[0]) {
944         fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
945         return NULL;
946     }
947
948     copy = strdup(orig);
949     if (copy == NULL) {
950         fprintf(stderr, "%s: failed to allocate memory\n", progname);
951         return NULL;
952     }
953
954     toresolv = copy;
955     lastcomp = NULL;
956     for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
957     if (end[0] != '/') {
958         char *tmp;
959         end[1] = '\0';
960         tmp = strrchr(copy, '/');
961         if (tmp == NULL) {
962             lastcomp = copy;
963             toresolv = ".";
964         } else {
965             lastcomp = tmp + 1;
966             if (tmp == copy)
967                 toresolv = "/";
968         }
969         if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
970             lastcomp = NULL;
971             toresolv = copy;
972         }
973         else if (tmp)
974             tmp[0] = '\0';
975     }
976     if (realpath(toresolv, buf) == NULL) {
977         fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
978                 strerror(errno));
979         free(copy);
980         return NULL;
981     }
982     if (lastcomp == NULL)
983         dst = strdup(buf);
984     else {
985         dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
986         if (dst) {
987             unsigned buflen = strlen(buf);
988             if (buflen && buf[buflen-1] == '/')
989                 sprintf(dst, "%s%s", buf, lastcomp);
990             else
991                 sprintf(dst, "%s/%s", buf, lastcomp);
992         }
993     }
994     free(copy);
995     if (dst == NULL)
996         fprintf(stderr, "%s: failed to allocate memory\n", progname);
997     return dst;
998 }
999
1000 static int send_fd(int sock_fd, int fd)
1001 {
1002     int retval;
1003     struct msghdr msg;
1004     struct cmsghdr *p_cmsg;
1005     struct iovec vec;
1006     char cmsgbuf[CMSG_SPACE(sizeof(fd))];
1007     int *p_fds;
1008     char sendchar = 0;
1009
1010     msg.msg_control = cmsgbuf;
1011     msg.msg_controllen = sizeof(cmsgbuf);
1012     p_cmsg = CMSG_FIRSTHDR(&msg);
1013     p_cmsg->cmsg_level = SOL_SOCKET;
1014     p_cmsg->cmsg_type = SCM_RIGHTS;
1015     p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1016     p_fds = (int *) CMSG_DATA(p_cmsg);
1017     *p_fds = fd;
1018     msg.msg_controllen = p_cmsg->cmsg_len;
1019     msg.msg_name = NULL;
1020     msg.msg_namelen = 0;
1021     msg.msg_iov = &vec;
1022     msg.msg_iovlen = 1;
1023     msg.msg_flags = 0;
1024     /* "To pass file descriptors or credentials you need to send/read at
1025      * least one byte" (man 7 unix) */
1026     vec.iov_base = &sendchar;
1027     vec.iov_len = sizeof(sendchar);
1028     while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1029     if (retval != 1) {
1030         perror("sending file descriptor");
1031         return -1;
1032     }
1033     return 0;
1034 }
1035
1036 static void usage(void)
1037 {
1038     fprintf(stderr,
1039             "%s: [options] mountpoint\n"
1040             "Options:\n"
1041             " -h                print help\n"
1042             " -v                print version\n"
1043             " -o opt[,opt...]   mount options\n"
1044             " -u                unmount\n"
1045             " -q                quiet\n"
1046             " -z                lazy unmount\n",
1047             progname);
1048     exit(1);
1049 }
1050
1051 static void show_version(void)
1052 {
1053     printf("%s\n", PACKAGE_STRING);
1054     exit(0);
1055 }
1056
1057 int main(int argc, char *argv[])
1058 {
1059     int ch;
1060     int fd;
1061     int res;
1062     char *origmnt;
1063     char *mnt;
1064     static int unmount = 0;
1065     static int lazy = 0;
1066     static int quiet = 0;
1067     char *commfd;
1068     int cfd;
1069     const char *opts = "";
1070
1071     static const struct option long_opts[] = {
1072         {"unmount", no_argument, NULL, 'u'},
1073         {"lazy",    no_argument, NULL, 'z'},
1074         {"quiet",   no_argument, NULL, 'q'},
1075         {"help",    no_argument, NULL, 'h'},
1076         {"version", no_argument, NULL, 'v'},
1077         {0, 0, 0, 0}};
1078
1079     /* Captive */
1080     captive_standalone_init();
1081
1082     progname = strdup(argv[0]);
1083     if (progname == NULL) {
1084         fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1085         exit(1);
1086     }
1087
1088     while ((ch = getopt_long(argc, argv, "hvo:uzq", long_opts, NULL)) != -1) {
1089         switch (ch) {
1090         case 'h':
1091             usage();
1092             break;
1093
1094         case 'v':
1095             show_version();
1096             break;
1097
1098         case 'o':
1099             opts = optarg;
1100             break;
1101
1102         case 'u':
1103             unmount = 1;
1104             break;
1105
1106         case 'z':
1107             lazy = 1;
1108             break;
1109
1110         case 'q':
1111             quiet = 1;
1112             break;
1113
1114         default:
1115             exit(1);
1116         }
1117     }
1118
1119     if (lazy && !unmount) {
1120         fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1121         exit(1);
1122     }
1123
1124     if (optind >= argc) {
1125         fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1126         exit(1);
1127     }
1128
1129     origmnt = argv[optind];
1130
1131     drop_privs();
1132     mnt = resolve_path(origmnt);
1133     restore_privs();
1134     if (mnt == NULL)
1135         exit(1);
1136
1137     umask(033);
1138     if (unmount) {
1139         if (geteuid() == 0) {
1140             int mtablock = lock_mtab();
1141             res = unmount_fuse(mnt, quiet, lazy);
1142             unlock_mtab(mtablock);
1143         } else
1144             res = do_unmount(mnt, quiet, lazy);
1145         if (res == -1)
1146             exit(1);
1147         return 0;
1148     }
1149
1150     commfd = getenv(FUSE_COMMFD_ENV);
1151     if (commfd == NULL) {
1152         fprintf(stderr, "%s: old style mounting not supported\n", progname);
1153         exit(1);
1154     }
1155
1156     fd = mount_fuse(mnt, opts);
1157     if (fd == -1)
1158         exit(1);
1159
1160     cfd = atoi(commfd);
1161     res = send_fd(cfd, fd);
1162     if (res == -1)
1163         exit(1);
1164
1165     return 0;
1166 }