Initial import
[samba] / source / client / smbumount.c
1 /*
2  *  smbumount.c
3  *
4  *  Copyright (C) 1995-1998 by Volker Lendecke
5  *
6  */
7
8 #define SMBMOUNT_MALLOC 1
9
10 #include "includes.h"
11
12 #include <mntent.h>
13
14 #include <asm/types.h>
15 #include <asm/posix_types.h>
16 #include <linux/smb.h>
17 #include <linux/smb_mount.h>
18 #include <linux/smb_fs.h>
19
20 /* This is a (hopefully) temporary hack due to the fact that
21         sizeof( uid_t ) != sizeof( __kernel_uid_t ) under glibc.
22         This may change in the future and smb.h may get fixed in the
23         future.  In the mean time, it's ugly hack time - get over it.
24 */
25 #undef SMB_IOC_GETMOUNTUID
26 #define SMB_IOC_GETMOUNTUID             _IOR('u', 1, __kernel_uid_t)
27
28 #ifndef O_NOFOLLOW
29 #define O_NOFOLLOW     0400000
30 #endif
31
32 static void
33 usage(void)
34 {
35         printf("usage: smbumount mountpoint\n");
36 }
37
38 static int
39 umount_ok(const char *mount_point)
40 {
41         /* we set O_NOFOLLOW to prevent users playing games with symlinks to
42            umount filesystems they don't own */
43         int fid = open(mount_point, O_RDONLY|O_NOFOLLOW, 0);
44         __kernel_uid32_t mount_uid;
45         
46         if (fid == -1) {
47                 fprintf(stderr, "Could not open %s: %s\n",
48                         mount_point, strerror(errno));
49                 return -1;
50         }
51         
52         if (ioctl(fid, SMB_IOC_GETMOUNTUID32, &mount_uid) != 0) {
53                 __kernel_uid_t mount_uid16;
54                 if (ioctl(fid, SMB_IOC_GETMOUNTUID, &mount_uid16) != 0) {
55                         fprintf(stderr, "%s probably not smb-filesystem\n",
56                                 mount_point);
57                         return -1;
58                 }
59                 mount_uid = mount_uid16;
60         }
61
62         if ((getuid() != 0)
63             && (mount_uid != getuid())) {
64                 fprintf(stderr, "You are not allowed to umount %s\n",
65                         mount_point);
66                 return -1;
67         }
68
69         close(fid);
70         return 0;
71 }
72
73 /* Make a canonical pathname from PATH.  Returns a freshly malloced string.
74    It is up the *caller* to ensure that the PATH is sensible.  i.e.
75    canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
76    is not a legal pathname for ``/dev/fd0''  Anything we cannot parse
77    we return unmodified.   */
78 static char *
79 canonicalize (char *path)
80 {
81         char *canonical = malloc (PATH_MAX + 1);
82
83         if (!canonical) {
84                 fprintf(stderr, "Error! Not enough memory!\n");
85                 return NULL;
86         }
87
88         if (strlen(path) > PATH_MAX) {
89                 fprintf(stderr, "Mount point string too long\n");
90                 return NULL;
91         }
92
93         if (path == NULL)
94                 return NULL;
95   
96         if (realpath (path, canonical))
97                 return canonical;
98
99         strncpy (canonical, path, PATH_MAX);
100         canonical[PATH_MAX] = '\0';
101         return canonical;
102 }
103
104
105 int 
106 main(int argc, char *argv[])
107 {
108         int fd;
109         char* mount_point;
110         struct mntent *mnt;
111         FILE* mtab;
112         FILE* new_mtab;
113
114         if (argc != 2) {
115                 usage();
116                 exit(1);
117         }
118
119         if (geteuid() != 0) {
120                 fprintf(stderr, "smbumount must be installed suid root\n");
121                 exit(1);
122         }
123
124         mount_point = canonicalize(argv[1]);
125
126         if (mount_point == NULL)
127         {
128                 exit(1);
129         }
130
131         if (umount_ok(mount_point) != 0) {
132                 exit(1);
133         }
134
135         if (umount(mount_point) != 0) {
136                 fprintf(stderr, "Could not umount %s: %s\n",
137                         mount_point, strerror(errno));
138                 exit(1);
139         }
140
141         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
142         {
143                 fprintf(stderr, "Can't get "MOUNTED"~ lock file");
144                 return 1;
145         }
146         close(fd);
147         
148         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
149                 fprintf(stderr, "Can't open " MOUNTED ": %s\n",
150                         strerror(errno));
151                 return 1;
152         }
153
154 #define MOUNTED_TMP MOUNTED".tmp"
155
156         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
157                 fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
158                         strerror(errno));
159                 endmntent(mtab);
160                 return 1;
161         }
162
163         while ((mnt = getmntent(mtab)) != NULL) {
164                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
165                         addmntent(new_mtab, mnt);
166                 }
167         }
168
169         endmntent(mtab);
170
171         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
172                 fprintf(stderr, "Error changing mode of %s: %s\n",
173                         MOUNTED_TMP, strerror(errno));
174                 exit(1);
175         }
176
177         endmntent(new_mtab);
178
179         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
180                 fprintf(stderr, "Cannot rename %s to %s: %s\n",
181                         MOUNTED, MOUNTED_TMP, strerror(errno));
182                 exit(1);
183         }
184
185         if (unlink(MOUNTED"~") == -1)
186         {
187                 fprintf(stderr, "Can't remove "MOUNTED"~");
188                 return 1;
189         }
190
191         return 0;
192 }