+Workaround Red Hat kernel 2.4.18-14 containing precompiled 'mkdep'.
[lufs.git] / util / lufsmnt.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <limits.h>
6 #include <errno.h>
7 #include <mntent.h>
8 #include <paths.h>
9 #include <fcntl.h>
10 #include <string.h>
11 #include <pwd.h>
12
13 #include <sys/types.h>
14 #include <sys/mount.h>
15 #include <sys/stat.h>
16
17 #define ERROR(x...)     fprintf(stderr, x)
18
19 static void
20 help(){
21     printf("\n");
22     printf("Usage: lufsmnt mount-point [options]\n");
23     printf("This is a suid wrapper called by lufsd.\n");
24
25 }
26
27 static int
28 fullpath(char *path, char *full){
29     
30     full[0] = 0;
31     
32     if(strlen(path) >= PATH_MAX - 1)
33         return -1;
34
35     if(!realpath(path, full))
36         return -1;
37     else 
38         return 0;
39 }
40
41 static int
42 mount_ok(char *mp){
43     struct stat st;
44     
45     if(chdir(mp)){
46         ERROR("cannot chdir %s\n", mp);
47         return -1;
48     }
49         
50     if(stat(".", &st)){
51         ERROR("cannot stat %s\n", mp);
52         return -1;
53     }
54         
55     if(!S_ISDIR(st.st_mode)){
56         ERROR("%s is not a directory\n", mp);
57         return -1;
58     }
59
60     if((getuid()) && ((getuid() != st.st_uid) || ((st.st_mode & S_IRWXU) != S_IRWXU))){
61         ERROR("you don't have proper permissions to mount on %s\n", mp);
62         return -1;
63     }
64
65     return 0;
66 }
67
68 void
69 hide_pass(char *opts){
70     char *c;
71
72     if((c = strstr(opts, "password="))){
73         for(c = c + 9; (*c != 0) && (*c != ','); c++)
74             *c = '*';
75     }
76 }
77
78 int
79 get_opt(char *opts, const char *optname, char *buf, int buflen){
80     char *begin, *end;
81
82     for(begin = opts; (begin = strstr(begin, optname)); begin++){
83         if (begin > opts && begin[-1] != ',')
84             continue;
85         if (begin[strlen(optname)] != '=')
86             continue;
87         begin += strlen(optname) + 1;
88
89         if(!(end = strchr(begin, ','))){
90             end = begin + strlen(begin);
91         }
92         
93         if( end - begin >= buflen)
94             end = begin + buflen - 1;
95
96         memcpy(buf, begin, end - begin);
97         buf[end - begin] = 0;
98         return 1;
99     }
100     return 0;
101 }
102
103 /* From util-linux/mount/getusername.c */
104 const char *
105 getusername() {
106     const char *user = 0;
107     struct passwd *pw = getpwuid(getuid());
108
109     if (pw)
110         user = pw->pw_name;
111     return user;
112 }
113
114 int
115 main(int argc, char **argv){
116     char *mountpoint, *opts, *s;
117     static char fpath[PATH_MAX];
118     static char mfs[PATH_MAX];
119     static char mopts[PATH_MAX];
120     static char mntent_mnt_type[PATH_MAX];
121     struct mntent ment;
122     int fd;
123     FILE *mtab;
124     
125     if(argc != 3){
126         help();
127         exit(1);
128     }
129
130     if(geteuid()){
131         ERROR("%s needs to be installed suid root in order to be used by unprivileged users\n", argv[0]);
132         exit(1);
133     }
134     
135     mountpoint = argv[1];
136     opts = argv[2];
137
138     fullpath(mountpoint, fpath);
139     
140     if(mount_ok(fpath)){
141         exit(1);
142     }
143         
144     if (mount("none", fpath, "lufs", MS_NOSUID | MS_NODEV, opts) < 0){
145         ERROR("mount failed: %s\n", strerror(errno));
146         switch(errno){
147         case ENODEV:
148             ERROR("you don't have kernel lufs support (check whether the lufs module is available/loaded)\n");
149             break;
150         }
151         return errno;
152     }
153
154     snprintf(mopts, sizeof(mopts), "user=%s,", getusername());
155     hide_pass(opts);
156     if(strlen(mopts) + strlen(opts) < PATH_MAX)
157         strcat(mopts, opts);
158     while ((s = strstr(mopts, ",user")) && (s[strlen(",user")]==0 || s[strlen(",user")]==','))
159         memmove(s, s+strlen(",user"), strlen(s+strlen(",user"))+1);
160     mfs[0] = 0;
161     get_opt(opts, "fs", mfs, PATH_MAX);
162     get_opt(opts, "mntent.mnt_fsname", mfs, PATH_MAX);
163
164     ment.mnt_fsname = mfs;
165     ment.mnt_dir = fpath;
166     strcpy(mntent_mnt_type, "lufs");
167     get_opt(opts, "mntent.mnt_type", mntent_mnt_type, sizeof(mntent_mnt_type));
168     ment.mnt_type = mntent_mnt_type;
169     ment.mnt_opts = mopts;
170     ment.mnt_freq = 0;
171     ment.mnt_passno = 0;
172
173     if((fd = open(_PATH_MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) < 0){
174         ERROR("can't get "_PATH_MOUNTED"~ lock file\n");
175         return 1;
176     }
177     close(fd);
178     
179     if((mtab = setmntent(_PATH_MOUNTED, "a+")) == NULL){
180         ERROR("can't open "_PATH_MOUNTED"\n");
181         return 1;
182     }
183     
184     if(addmntent(mtab, &ment)){
185         ERROR("can't write mount entry\n");
186         return 1;
187     }
188     
189     if(fchmod(fileno(mtab), 0644) < 0){
190         ERROR("can't set [erms on "_PATH_MOUNTED"\n");
191         return 1;
192     }
193     
194     endmntent(mtab);
195     
196     if(unlink(_PATH_MOUNTED"~") < 0){
197         ERROR("can't remove "_PATH_MOUNTED"~\n");
198         return 1;
199     }
200     
201     return 0;
202 }
203