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 44static uid_t mount_uid; 45static gid_t mount_gid; 46static int mount_ro; 47static unsigned mount_fmask; 48static unsigned mount_dmask; 49static int user_mount; 50static char *options; 51 52static void 53help(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 68static int 69parse_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 110static char * 111fullpath(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 */ 129static 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. */ 158static int 159do_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} 324