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
30static void
31usage(void)
32{
33        printf("usage: smbumount mountpoint\n");
34}
35
36static int
37umount_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_uid32_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_GETMOUNTUID32, &mount_uid) != 0) {
51                __kernel_uid_t mount_uid16;
52                if (ioctl(fid, SMB_IOC_GETMOUNTUID, &mount_uid16) != 0) {
53                        fprintf(stderr, "%s probably not smb-filesystem\n",
54                                mount_point);
55                        return -1;
56                }
57                mount_uid = mount_uid16;
58        }
59
60        if ((getuid() != 0)
61            && (mount_uid != getuid())) {
62                fprintf(stderr, "You are not allowed to umount %s\n",
63                        mount_point);
64                return -1;
65        }
66
67        close(fid);
68        return 0;
69}
70
71/* Make a canonical pathname from PATH.  Returns a freshly malloced string.
72   It is up the *caller* to ensure that the PATH is sensible.  i.e.
73   canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
74   is not a legal pathname for ``/dev/fd0''  Anything we cannot parse
75   we return unmodified.   */
76static char *
77canonicalize (char *path)
78{
79	char *canonical = malloc (PATH_MAX + 1);
80
81	if (!canonical) {
82		fprintf(stderr, "Error! Not enough memory!\n");
83		return NULL;
84	}
85
86	if (strlen(path) > PATH_MAX) {
87		fprintf(stderr, "Mount point string too long\n");
88		return NULL;
89	}
90
91	if (path == NULL)
92		return NULL;
93
94	if (realpath (path, canonical))
95		return canonical;
96
97	strncpy (canonical, path, PATH_MAX);
98	canonical[PATH_MAX] = '\0';
99	return canonical;
100}
101
102
103int
104main(int argc, char *argv[])
105{
106        int fd;
107        char* mount_point;
108        struct mntent *mnt;
109        FILE* mtab;
110        FILE* new_mtab;
111
112        if (argc != 2) {
113                usage();
114                exit(1);
115        }
116
117        if (geteuid() != 0) {
118                fprintf(stderr, "smbumount must be installed suid root\n");
119                exit(1);
120        }
121
122        mount_point = canonicalize(argv[1]);
123
124	if (mount_point == NULL)
125	{
126		exit(1);
127	}
128
129        if (umount_ok(mount_point) != 0) {
130                exit(1);
131        }
132
133        if (umount(mount_point) != 0) {
134                fprintf(stderr, "Could not umount %s: %s\n",
135                        mount_point, strerror(errno));
136                exit(1);
137        }
138
139        if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
140        {
141                fprintf(stderr, "Can't get "MOUNTED"~ lock file");
142                return 1;
143        }
144        close(fd);
145
146        if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
147                fprintf(stderr, "Can't open " MOUNTED ": %s\n",
148                        strerror(errno));
149                return 1;
150        }
151
152#define MOUNTED_TMP MOUNTED".tmp"
153
154        if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
155                fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
156                        strerror(errno));
157                endmntent(mtab);
158                return 1;
159        }
160
161        while ((mnt = getmntent(mtab)) != NULL) {
162                if (strcmp(mnt->mnt_dir, mount_point) != 0) {
163                        addmntent(new_mtab, mnt);
164                }
165        }
166
167        endmntent(mtab);
168
169        if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
170                fprintf(stderr, "Error changing mode of %s: %s\n",
171                        MOUNTED_TMP, strerror(errno));
172                exit(1);
173        }
174
175        endmntent(new_mtab);
176
177        if (rename(MOUNTED_TMP, MOUNTED) < 0) {
178                fprintf(stderr, "Cannot rename %s to %s: %s\n",
179                        MOUNTED, MOUNTED_TMP, strerror(errno));
180                exit(1);
181        }
182
183        if (unlink(MOUNTED"~") == -1)
184        {
185                fprintf(stderr, "Can't remove "MOUNTED"~");
186                return 1;
187        }
188
189	return 0;
190}
191