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\n"); 105 exit(1); 106 } 107 return strdup(path); 108} 109 110/* Check whether user is allowed to mount on the specified mount point. If it's 111 OK then we change into that directory - this prevents race conditions */ 112static int mount_ok(char *mount_point) 113{ 114 struct stat st; 115 116 if (chdir(mount_point) != 0) { 117 return -1; 118 } 119 120 if (stat(".", &st) != 0) { 121 return -1; 122 } 123 124 if (!S_ISDIR(st.st_mode)) { 125 errno = ENOTDIR; 126 return -1; 127 } 128 129 if ((getuid() != 0) && 130 ((getuid() != st.st_uid) || 131 ((st.st_mode & S_IRWXU) != S_IRWXU))) { 132 errno = EPERM; 133 return -1; 134 } 135 136 return 0; 137} 138 139/* Tries to mount using the appropriate format. For 2.2 the struct, 140 for 2.4 the ascii version. */ 141static int 142do_mount(char *share_name, unsigned int flags, struct smb_mount_data *data) 143{ 144 pstring opts; 145 struct utsname uts; 146 char *release, *major, *minor; 147 char *data1, *data2; 148 149 uname(&uts); 150 release = uts.release; 151 major = strtok(release, "."); 152 minor = strtok(NULL, "."); 153 if (major && minor && atoi(major) == 2 && atoi(minor) < 4) { 154 /* < 2.4, assume struct */ 155 data1 = (char *) data; 156 data2 = opts; 157 } else { 158 /* >= 2.4, assume ascii but fall back on struct */ 159 data1 = opts; 160 data2 = (char *) data; 161 } 162 163 slprintf(opts, sizeof(opts)-1, 164 "version=7,uid=%d,gid=%d,file_mode=0%o,dir_mode=0%o,%s", 165 data->uid, data->gid, data->file_mode, data->dir_mode,options); 166 if (mount(share_name, ".", "smbfs", flags, data1) == 0) 167 return 0; 168 return mount(share_name, ".", "smbfs", flags, data2); 169} 170 171 int main(int argc, char *argv[]) 172{ 173 char *mount_point, *share_name = NULL; 174 FILE *mtab; 175 int fd; 176 unsigned int flags; 177 struct smb_mount_data data; 178 struct mntent ment; 179 180 memset(&data, 0, sizeof(struct smb_mount_data)); 181 182 if (argc < 2) { 183 help(); 184 exit(1); 185 } 186 187 if (argv[1][0] == '-') { 188 help(); 189 exit(1); 190 } 191 192 if (getuid() != 0) { 193 user_mount = 1; 194 } 195 196 if (geteuid() != 0) { 197 fprintf(stderr, "smbmnt must be installed suid root for direct user mounts (%d,%d)\n", getuid(), geteuid()); 198 exit(1); 199 } 200 201 mount_uid = getuid(); 202 mount_gid = getgid(); 203 mount_fmask = umask(0); 204 umask(mount_fmask); 205 mount_fmask = ~mount_fmask; 206 207 mount_point = fullpath(argv[1]); 208 209 argv += 1; 210 argc -= 1; 211 212 if (mount_ok(mount_point) != 0) { 213 fprintf(stderr, "cannot mount on %s: %s\n", 214 mount_point, strerror(errno)); 215 exit(1); 216 } 217 218 data.version = SMB_MOUNT_VERSION; 219 220 /* getuid() gives us the real uid, who may umount the fs */ 221 data.mounted_uid = getuid(); 222 223 if (parse_args(argc, argv, &data, &share_name) != 0) { 224 help(); 225 return -1; 226 } 227 228 data.uid = mount_uid; 229 data.gid = mount_gid; 230 data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_fmask; 231 data.dir_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_dmask; 232 233 if (mount_dmask == 0) { 234 data.dir_mode = data.file_mode; 235 if ((data.dir_mode & S_IRUSR) != 0) 236 data.dir_mode |= S_IXUSR; 237 if ((data.dir_mode & S_IRGRP) != 0) 238 data.dir_mode |= S_IXGRP; 239 if ((data.dir_mode & S_IROTH) != 0) 240 data.dir_mode |= S_IXOTH; 241 } 242 243 flags = MS_MGC_VAL; 244 245 if (mount_ro) flags |= MS_RDONLY; 246 247 if (do_mount(share_name, flags, &data) < 0) { 248 switch (errno) { 249 case ENODEV: 250 fprintf(stderr, "ERROR: smbfs filesystem not supported by the kernel\n"); 251 break; 252 default: 253 perror("mount error"); 254 } 255 fprintf(stderr, "Please refer to the smbmnt(8) manual page\n"); 256 return -1; 257 } 258 259 ment.mnt_fsname = share_name ? share_name : "none"; 260 ment.mnt_dir = mount_point; 261 ment.mnt_type = "smbfs"; 262 ment.mnt_opts = ""; 263 ment.mnt_freq = 0; 264 ment.mnt_passno= 0; 265 266 mount_point = ment.mnt_dir; 267 268 if (mount_point == NULL) 269 { 270 fprintf(stderr, "Mount point too long\n"); 271 return -1; 272 } 273 274 if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) 275 { 276 fprintf(stderr, "Can't get "MOUNTED"~ lock file"); 277 return 1; 278 } 279 close(fd); 280 281 if ((mtab = setmntent(MOUNTED, "a+")) == NULL) 282 { 283 fprintf(stderr, "Can't open " MOUNTED); 284 return 1; 285 } 286 287 if (addmntent(mtab, &ment) == 1) 288 { 289 fprintf(stderr, "Can't write mount entry"); 290 return 1; 291 } 292 if (fchmod(fileno(mtab), 0644) == -1) 293 { 294 fprintf(stderr, "Can't set perms on "MOUNTED); 295 return 1; 296 } 297 endmntent(mtab); 298 299 if (unlink(MOUNTED"~") == -1) 300 { 301 fprintf(stderr, "Can't remove "MOUNTED"~"); 302 return 1; 303 } 304 305 return 0; 306} 307