fcd803a57a34b946c19b8c0c1d651d4f1ef67178
[jra/samba/.git] / source3 / client / smbmnt.c
1 /*
2  *  smbmnt.c
3  *
4  *  Copyright (C) 1995-1998 by Paal-Kr. Engstad and Volker Lendecke
5  *  extensively modified by Tridge
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *  
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *  
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define SMBMOUNT_MALLOC 1
24
25 #include "includes.h"
26
27 #include <mntent.h>
28 #include <sys/utsname.h>
29
30 #include <asm/types.h>
31 #include <asm/posix_types.h>
32 #include <linux/smb.h>
33 #include <linux/smb_mount.h>
34 #include <asm/unistd.h>
35
36 #ifndef MS_MGC_VAL
37 /* This may look strange but MS_MGC_VAL is what we are looking for and
38         is what we need from <linux/fs.h> under libc systems and is
39         provided in standard includes on glibc systems.  So...  We
40         switch on what we need...  */
41 #include <linux/fs.h>
42 #endif
43
44 static uid_t mount_uid;
45 static gid_t mount_gid;
46 static int mount_ro;
47 static unsigned mount_fmask;
48 static unsigned mount_dmask;
49 static int user_mount;
50 static char *options;
51
52 static void
53 help(void)
54 {
55         printf("\n");
56         printf("Usage: smbmnt mount-point [options]\n");
57         printf("Version %s\n\n",SAMBA_VERSION_STRING);
58         printf("-s share       share name on server\n"
59                "-r             mount read-only\n"
60                "-u uid         mount as uid\n"
61                "-g gid         mount as gid\n"
62                "-f mask        permission mask for files\n"
63                "-d mask        permission mask for directories\n"
64                "-o options     name=value, list of options\n"
65                "-h             print this help text\n");
66 }
67
68 static int
69 parse_args(int argc, char *argv[], struct smb_mount_data *data, char **share)
70 {
71         int opt;
72
73         while ((opt = getopt (argc, argv, "s:u:g:rf:d:o:")) != EOF)
74         {
75                 switch (opt)
76                 {
77                 case 's':
78                         *share = optarg;
79                         break;
80                 case 'u':
81                         if (!user_mount) {
82                                 mount_uid = strtol(optarg, NULL, 0);
83                         }
84                         break;
85                 case 'g':
86                         if (!user_mount) {
87                                 mount_gid = strtol(optarg, NULL, 0);
88                         }
89                         break;
90                 case 'r':
91                         mount_ro = 1;
92                         break;
93                 case 'f':
94                         mount_fmask = strtol(optarg, NULL, 8);
95                         break;
96                 case 'd':
97                         mount_dmask = strtol(optarg, NULL, 8);
98                         break;
99                 case 'o':
100                         options = optarg;
101                         break;
102                 default:
103                         return -1;
104                 }
105         }
106         return 0;
107         
108 }
109
110 static char *
111 fullpath(const char *p)
112 {
113         char path[PATH_MAX+1];
114
115         if (strlen(p) > PATH_MAX) {
116                 return NULL;
117         }
118
119         if (realpath(p, path) == NULL) {
120                 fprintf(stderr,"Failed to find real path for mount point %s: %s\n",
121                         p, strerror(errno));
122                 exit(1);
123         }
124         return strdup(path);
125 }
126
127 /* Check whether user is allowed to mount on the specified mount point. If it's
128    OK then we change into that directory - this prevents race conditions */
129 static int mount_ok(char *mount_point)
130 {
131         struct stat st;
132
133         if (chdir(mount_point) != 0) {
134                 return -1;
135         }
136
137         if (stat(".", &st) != 0) {
138                 return -1;
139         }
140
141         if (!S_ISDIR(st.st_mode)) {
142                 errno = ENOTDIR;
143                 return -1;
144         }
145
146         if ((getuid() != 0) && 
147             ((getuid() != st.st_uid) || 
148              ((st.st_mode & S_IRWXU) != S_IRWXU))) {
149                 errno = EPERM;
150                 return -1;
151         }
152
153         return 0;
154 }
155
156 /* Tries to mount using the appropriate format. For 2.2 the struct,
157    for 2.4 the ascii version. */
158 static int
159 do_mount(char *share_name, unsigned int flags, struct smb_mount_data *data)
160 {
161         pstring opts;
162         struct utsname uts;
163         char *release, *major, *minor;
164         char *data1, *data2;
165
166         uname(&uts);
167         release = uts.release;
168         major = strtok(release, ".");
169         minor = strtok(NULL, ".");
170         if (major && minor && atoi(major) == 2 && atoi(minor) < 4) {
171                 /* < 2.4, assume struct */
172                 data1 = (char *) data;
173                 data2 = opts;
174         } else {
175                 /* >= 2.4, assume ascii but fall back on struct */
176                 data1 = opts;
177                 data2 = (char *) data;
178         }
179
180         slprintf(opts, sizeof(opts)-1,
181                  "version=7,uid=%d,gid=%d,file_mode=0%o,dir_mode=0%o,%s",
182                  mount_uid, mount_gid, data->file_mode, data->dir_mode,options);
183         if (mount(share_name, ".", "smbfs", flags, data1) == 0)
184                 return 0;
185         return mount(share_name, ".", "smbfs", flags, data2);
186 }
187
188  int main(int argc, char *argv[])
189 {
190         char *mount_point, *share_name = NULL;
191         FILE *mtab;
192         int fd;
193         unsigned int flags;
194         struct smb_mount_data data;
195         struct mntent ment;
196
197         memset(&data, 0, sizeof(struct smb_mount_data));
198
199         if (argc < 2) {
200                 help();
201                 exit(1);
202         }
203
204         if (argv[1][0] == '-') {
205                 help();
206                 exit(1);
207         }
208
209         if (getuid() != 0) {
210                 user_mount = 1;
211         }
212
213         if (geteuid() != 0) {
214                 fprintf(stderr, "smbmnt must be installed suid root for direct user mounts (%d,%d)\n", getuid(), geteuid());
215                 exit(1);
216         }
217
218         mount_uid = getuid();
219         mount_gid = getgid();
220         mount_fmask = umask(0);
221         umask(mount_fmask);
222         mount_fmask = ~mount_fmask;
223
224         mount_point = fullpath(argv[1]);
225
226         argv += 1;
227         argc -= 1;
228
229         if (mount_ok(mount_point) != 0) {
230                 fprintf(stderr, "cannot mount on %s: %s\n",
231                         mount_point, strerror(errno));
232                 exit(1);
233         }
234
235         data.version = SMB_MOUNT_VERSION;
236
237         /* getuid() gives us the real uid, who may umount the fs */
238         data.mounted_uid = getuid();
239
240         if (parse_args(argc, argv, &data, &share_name) != 0) {
241                 help();
242                 return -1;
243         }
244
245         data.uid = mount_uid;    // truncates to 16-bits here!!!
246         data.gid = mount_gid;
247         data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_fmask;
248         data.dir_mode  = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_dmask;
249
250         if (mount_dmask == 0) {
251                 data.dir_mode = data.file_mode;
252                 if ((data.dir_mode & S_IRUSR) != 0)
253                         data.dir_mode |= S_IXUSR;
254                 if ((data.dir_mode & S_IRGRP) != 0)
255                         data.dir_mode |= S_IXGRP;
256                 if ((data.dir_mode & S_IROTH) != 0)
257                         data.dir_mode |= S_IXOTH;
258         }
259
260         flags = MS_MGC_VAL | MS_NOSUID | MS_NODEV;
261
262         if (mount_ro) flags |= MS_RDONLY;
263
264         if (do_mount(share_name, flags, &data) < 0) {
265                 switch (errno) {
266                 case ENODEV:
267                         fprintf(stderr, "ERROR: smbfs filesystem not supported by the kernel\n");
268                         break;
269                 default:
270                         perror("mount error");
271                 }
272                 fprintf(stderr, "Please refer to the smbmnt(8) manual page\n");
273                 return -1;
274         }
275
276         ment.mnt_fsname = share_name ? share_name : "none";
277         ment.mnt_dir = mount_point;
278         ment.mnt_type = "smbfs";
279         ment.mnt_opts = "";
280         ment.mnt_freq = 0;
281         ment.mnt_passno= 0;
282
283         mount_point = ment.mnt_dir;
284
285         if (mount_point == NULL)
286         {
287                 fprintf(stderr, "Mount point too long\n");
288                 return -1;
289         }
290         
291         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
292         {
293                 fprintf(stderr, "Can't get "MOUNTED"~ lock file");
294                 return 1;
295         }
296         close(fd);
297         
298         if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
299         {
300                 fprintf(stderr, "Can't open " MOUNTED);
301                 return 1;
302         }
303
304         if (addmntent(mtab, &ment) == 1)
305         {
306                 fprintf(stderr, "Can't write mount entry");
307                 return 1;
308         }
309         if (fchmod(fileno(mtab), 0644) == -1)
310         {
311                 fprintf(stderr, "Can't set perms on "MOUNTED);
312                 return 1;
313         }
314         endmntent(mtab);
315
316         if (unlink(MOUNTED"~") == -1)
317         {
318                 fprintf(stderr, "Can't remove "MOUNTED"~");
319                 return 1;
320         }
321
322         return 0;
323 }