1/* 2 * smbmnt.c 3 * 4 * Copyright (C) 1995-1998 by Paal-Kr. Engstad and Volker Lendecke 5 * extensively modified by Tridge 6 * 7 */ 8 9#include "includes.h" 10 11#include <mntent.h> 12#include <sys/utsname.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 <asm/unistd.h> 19 20#ifndef MS_MGC_VAL 21/* This may look strange but MS_MGC_VAL is what we are looking for and 22 is what we need from <linux/fs.h> under libc systems and is 23 provided in standard includes on glibc systems. So... We 24 switch on what we need... */ 25#include <linux/fs.h> 26#endif 27 28static uid_t mount_uid; 29static gid_t mount_gid; 30static int mount_ro; 31static unsigned mount_fmask; 32static unsigned mount_dmask; 33static int user_mount; 34static char *options; 35 36static void 37help(void) 38{ 39 printf("\n"); 40 printf("Usage: smbmnt mount-point [options]\n"); 41 printf("Version %s\n\n",SAMBA_VERSION_STRING); 42 printf("-s share share name on server\n" 43 "-r mount read-only\n" 44 "-u uid mount as uid\n" 45 "-g gid mount as gid\n" 46 "-f mask permission mask for files\n" 47 "-d mask permission mask for directories\n" 48 "-o options name=value, list of options\n" 49 "-h print this help text\n"); 50} 51 52static int 53parse_args(int argc, char *argv[], struct smb_mount_data *data, char **share) 54{ 55 int opt; 56 57 while ((opt = getopt (argc, argv, "s:u:g:rf:d:o:")) != EOF) 58 { 59 switch (opt) 60 { 61 case 's': 62 *share = optarg; 63 break; 64 case 'u': 65 if (!user_mount) { 66 mount_uid = strtol(optarg, NULL, 0); 67 } 68 break; 69 case 'g': 70 if (!user_mount) { 71 mount_gid = strtol(optarg, NULL, 0); 72 } 73 break; 74 case 'r': 75 mount_ro = 1; 76 break; 77 case 'f': 78 mount_fmask = strtol(optarg, NULL, 8); 79 break; 80 case 'd': 81 mount_dmask = strtol(optarg, NULL, 8); 82 break; 83 case 'o': 84 options = optarg; 85 break; 86 default: 87 return -1; 88 } 89 } 90 return 0; 91 92} 93 94static char * 95fullpath(const char *p) 96{ 97 char path[PATH_MAX+1]; 98 99 if (strlen(p) > PATH_MAX) { 100 return NULL; 101 } 102 103 if (realpath(p, path) == NULL) { 104 fprintf(stderr,"Failed to find real path for mount point %s: %s\n", 105 p, strerror(errno)); 106 exit(1); 107 } 108 return strdup(path); 109} 110 111/* Check whether user is allowed to mount on the specified mount point. If it's 112 OK then we change into that directory - this prevents race conditions */ 113static int mount_ok(char *mount_point) 114{ 115 struct stat st; 116 117 if (chdir(mount_point) != 0) { 118 return -1; 119 } 120 121 if (stat(".", &st) != 0) { 122 return -1; 123 } 124 125 if (!S_ISDIR(st.st_mode)) { 126 errno = ENOTDIR; 127 return -1; 128 } 129 130 if ((getuid() != 0) && 131 ((getuid() != st.st_uid) || 132 ((st.st_mode & S_IRWXU) != S_IRWXU))) { 133 errno = EPERM; 134 return -1; 135 } 136 137 return 0; 138} 139 140/* Tries to mount using the appropriate format. For 2.2 the struct, 141 for 2.4 the ascii version. */ 142static int 143do_mount(char *share_name, unsigned int flags, struct smb_mount_data *data) 144{ 145 pstring opts; 146 struct utsname uts; 147 char *release, *major, *minor; 148 char *data1, *data2; 149 150 uname(&uts); 151 release = uts.release; 152 major = strtok(release, "."); 153 minor = strtok(NULL, "."); 154 if (major && minor && atoi(major) == 2 && atoi(minor) < 4) { 155 /* < 2.4, assume struct */ 156 data1 = (char *) data; 157 data2 = opts; 158 } else { 159 /* >= 2.4, assume ascii but fall back on struct */ 160 data1 = opts; 161 data2 = (char *) data; 162 } 163 164 slprintf(opts, sizeof(opts)-1, 165 "version=7,uid=%d,gid=%d,file_mode=0%o,dir_mode=0%o,%s", 166 mount_uid, mount_gid, data->file_mode, data->dir_mode,options); 167 if (mount(share_name, ".", "smbfs", flags, data1) == 0) 168 return 0; 169 return mount(share_name, ".", "smbfs", flags, data2); 170} 171 172 int main(int argc, char *argv[]) 173{ 174 char *mount_point, *share_name = NULL; 175 FILE *mtab; 176 int fd; 177 unsigned int flags; 178 struct smb_mount_data data; 179 struct mntent ment; 180 181 memset(&data, 0, sizeof(struct smb_mount_data)); 182 183 if (argc < 2) { 184 help(); 185 exit(1); 186 } 187 188 if (argv[1][0] == '-') { 189 help(); 190 exit(1); 191 } 192 193 if (getuid() != 0) { 194 user_mount = 1; 195 } 196 197 if (geteuid() != 0) { 198 fprintf(stderr, "smbmnt must be installed suid root for direct user mounts (%d,%d)\n", getuid(), geteuid()); 199 exit(1); 200 } 201 202 mount_uid = getuid(); 203 mount_gid = getgid(); 204 mount_fmask = umask(0); 205 umask(mount_fmask); 206 mount_fmask = ~mount_fmask; 207 208 mount_point = fullpath(argv[1]); 209 210 argv += 1; 211 argc -= 1; 212 213 if (mount_ok(mount_point) != 0) { 214 fprintf(stderr, "cannot mount on %s: %s\n", 215 mount_point, strerror(errno)); 216 exit(1); 217 } 218 219 data.version = SMB_MOUNT_VERSION; 220 221 /* getuid() gives us the real uid, who may umount the fs */ 222 data.mounted_uid = getuid(); 223 224 if (parse_args(argc, argv, &data, &share_name) != 0) { 225 help(); 226 return -1; 227 } 228 229 data.uid = mount_uid; // truncates to 16-bits here!!! 230 data.gid = mount_gid; 231 data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_fmask; 232 data.dir_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_dmask; 233 234 if (mount_dmask == 0) { 235 data.dir_mode = data.file_mode; 236 if ((data.dir_mode & S_IRUSR) != 0) 237 data.dir_mode |= S_IXUSR; 238 if ((data.dir_mode & S_IRGRP) != 0) 239 data.dir_mode |= S_IXGRP; 240 if ((data.dir_mode & S_IROTH) != 0) 241 data.dir_mode |= S_IXOTH; 242 } 243 244 flags = MS_MGC_VAL | MS_NOSUID | MS_NODEV; 245 246 if (mount_ro) flags |= MS_RDONLY; 247 248 if (do_mount(share_name, flags, &data) < 0) { 249 switch (errno) { 250 case ENODEV: 251 fprintf(stderr, "ERROR: smbfs filesystem not supported by the kernel\n"); 252 break; 253 default: 254 perror("mount error"); 255 } 256 fprintf(stderr, "Please refer to the smbmnt(8) manual page\n"); 257 return -1; 258 } 259 260 ment.mnt_fsname = share_name ? share_name : "none"; 261 ment.mnt_dir = mount_point; 262 ment.mnt_type = "smbfs"; 263 ment.mnt_opts = ""; 264 ment.mnt_freq = 0; 265 ment.mnt_passno= 0; 266 267 mount_point = ment.mnt_dir; 268 269 if (mount_point == NULL) 270 { 271 fprintf(stderr, "Mount point too long\n"); 272 return -1; 273 } 274 275 if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) 276 { 277 fprintf(stderr, "Can't get "MOUNTED"~ lock file"); 278 return 1; 279 } 280 close(fd); 281 282 if ((mtab = setmntent(MOUNTED, "a+")) == NULL) 283 { 284 fprintf(stderr, "Can't open " MOUNTED); 285 return 1; 286 } 287 288 if (addmntent(mtab, &ment) == 1) 289 { 290 fprintf(stderr, "Can't write mount entry"); 291 return 1; 292 } 293 if (fchmod(fileno(mtab), 0644) == -1) 294 { 295 fprintf(stderr, "Can't set perms on "MOUNTED); 296 return 1; 297 } 298 endmntent(mtab); 299 300 if (unlink(MOUNTED"~") == -1) 301 { 302 fprintf(stderr, "Can't remove "MOUNTED"~"); 303 return 1; 304 } 305 306 return 0; 307} 308