| 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 2 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 | } | 
|---|