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