#include <mntent.h>
#include <fcntl.h>
#include <limits.h>
+#include <fstab.h>
#include "mount.h"
#define MOUNT_CIFS_VERSION_MAJOR "1"
-#define MOUNT_CIFS_VERSION_MINOR "12"
+#define MOUNT_CIFS_VERSION_MINOR "13"
#ifndef MOUNT_CIFS_VENDOR_SUFFIX
#ifdef _SAMBA_BUILD_
#define MS_BIND 4096
#endif
-#define MAX_UNC_LEN 1024
+/* private flags - clear these before passing to kernel */
+#define MS_USERS 0x40000000
+#define MS_USER 0x80000000
-#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
+#define MAX_UNC_LEN 1024
#ifndef SAFE_FREE
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
/* currently maximum length of IPv6 address string */
#define MAX_ADDRESS_LEN INET6_ADDRSTRLEN
+/*
+ * By default, mount.cifs follows the conventions set forth by /bin/mount
+ * for user mounts. That is, it requires that the mount be listed in
+ * /etc/fstab with the "user" option when run as an unprivileged user and
+ * mount.cifs is setuid root.
+ *
+ * Older versions of mount.cifs however were "looser" in this regard. When
+ * made setuid root, a user could run mount.cifs directly and mount any share
+ * on a directory owned by that user.
+ *
+ * The legacy behavior is now disabled by default. To reenable it, set the
+ * following #define to true.
+ */
+#define CIFS_LEGACY_SETUID_CHECK 0
+
+/*
+ * When an unprivileged user runs a setuid mount.cifs, we set certain mount
+ * flags by default. These defaults can be changed here.
+ */
+#define CIFS_SETUID_FLAGS (MS_NOSUID|MS_NODEV)
+
const char *thisprogram;
int verboseflag = 0;
int fakemnt = 0;
static char * mountpassword = NULL;
char * domain_name = NULL;
char * prefixpath = NULL;
+const char *cifs_fstype = "cifs";
/* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
* don't link to libreplace so need them here. */
}
#endif
+/*
+ * If an unprivileged user is doing the mounting then we need to ensure
+ * that the entry is in /etc/fstab.
+ */
+static int
+check_mountpoint(const char *progname, char *mountpoint)
+{
+ int err;
+ struct stat statbuf;
+
+ /* does mountpoint exist and is it a directory? */
+ err = stat(".", &statbuf);
+ if (err) {
+ fprintf(stderr, "%s: failed to stat %s: %s\n", progname,
+ mountpoint, strerror(errno));
+ return EX_USAGE;
+ }
+
+ if (!S_ISDIR(statbuf.st_mode)) {
+ fprintf(stderr, "%s: %s is not a directory!", progname,
+ mountpoint);
+ return EX_USAGE;
+ }
+
+#if CIFS_LEGACY_SETUID_CHECK
+ /* do extra checks on mountpoint for legacy setuid behavior */
+ if (!getuid() || geteuid())
+ return 0;
+
+ if (statbuf.st_uid != getuid()) {
+ fprintf(stderr, "%s: %s is not owned by user\n", progname,
+ mountpoint);
+ return EX_USAGE;
+ }
+
+ if ((statbuf.st_mode & S_IRWXU) != S_IRWXU) {
+ fprintf(stderr, "%s: invalid permissions on %s\n", progname,
+ mountpoint);
+ return EX_USAGE;
+ }
+#endif /* CIFS_LEGACY_SETUID_CHECK */
+
+ return 0;
+}
+
+#if CIFS_LEGACY_SETUID_CHECK
+static int
+check_fstab(const char *progname, char *mountpoint, char *devname,
+ char **options)
+{
+ return 0;
+}
+#else /* CIFS_LEGACY_SETUID_CHECK */
+static int
+check_fstab(const char *progname, char *mountpoint, char *devname,
+ char **options)
+{
+ FILE *fstab;
+ struct mntent *mnt;
+
+ /* make sure this mount is listed in /etc/fstab */
+ fstab = setmntent(_PATH_FSTAB, "r");
+ if (!fstab) {
+ fprintf(stderr, "Couldn't open %s for reading!\n",
+ _PATH_FSTAB);
+ return EX_FILEIO;
+ }
+
+ while((mnt = getmntent(fstab))) {
+ if (!strcmp(mountpoint, mnt->mnt_dir))
+ break;
+ }
+ endmntent(fstab);
+
+ if (mnt == NULL || strcmp(mnt->mnt_fsname, devname)) {
+ fprintf(stderr, "%s: permission denied: no match for "
+ "%s found in %s\n", progname, mountpoint,
+ _PATH_FSTAB);
+ return EX_USAGE;
+ }
+
+ /*
+ * 'mount' munges the options from fstab before passing them
+ * to us. It is non-trivial to test that we have the correct
+ * set of options. We don't want to trust what the user
+ * gave us, so just take whatever is in /etc/fstab.
+ */
+ free(*options);
+ *options = strdup(mnt->mnt_opts);
+ return 0;
+}
+#endif /* CIFS_LEGACY_SETUID_CHECK */
+
/* BB finish BB
cifs_umount
static char * check_for_domain(char **);
-static void mount_cifs_usage(void)
+static void mount_cifs_usage(FILE *stream)
{
- printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
- printf("\nMount the remote target, specified as a UNC name,");
- printf(" to a local directory.\n\nOptions:\n");
- printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
- printf("\nLess commonly used options:");
- printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
- printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
- printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
- printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
- printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
- printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
- printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
- printf("\n\nRarely used options:");
- printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
- printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
- printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
- printf("\n\tin6_addr");
- printf("\n\nOptions are described in more detail in the manual page");
- printf("\n\tman 8 mount.cifs\n");
- printf("\nTo display the version number of the mount helper:");
- printf("\n\t%s -V\n",thisprogram);
+ fprintf(stream, "\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
+ fprintf(stream, "\nMount the remote target, specified as a UNC name,");
+ fprintf(stream, " to a local directory.\n\nOptions:\n");
+ fprintf(stream, "\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
+ fprintf(stream, "\nLess commonly used options:");
+ fprintf(stream, "\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
+ fprintf(stream, "\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
+ fprintf(stream, "\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
+ fprintf(stream, "\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
+ fprintf(stream, "\n\nOptions not needed for servers supporting CIFS Unix extensions");
+ fprintf(stream, "\n\t(e.g. unneeded for mounts to most Samba versions):");
+ fprintf(stream, "\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
+ fprintf(stream, "\n\nRarely used options:");
+ fprintf(stream, "\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
+ fprintf(stream, "\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
+ fprintf(stream, "\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
+ fprintf(stream, "\n\nOptions are described in more detail in the manual page");
+ fprintf(stream, "\n\tman 8 mount.cifs\n");
+ fprintf(stream, "\nTo display the version number of the mount helper:");
+ fprintf(stream, "\n\t%s -V\n",thisprogram);
SAFE_FREE(mountpassword);
+
+ if (stream == stderr)
+ exit(EX_USAGE);
+ exit(0);
}
/* caller frees username if necessary */
char * temp_val;
FILE * fs;
int i, length;
+
+ i = access(file_name, R_OK);
+ if (i)
+ return i;
+
fs = fopen(file_name,"r");
if(fs == NULL)
return errno;
}
}
if(length > 4086) {
- printf("mount.cifs failed due to malformed username in credentials file");
+ fprintf(stderr, "mount.cifs failed due to malformed username in credentials file\n");
memset(line_buf,0,4096);
exit(EX_USAGE);
} else {
}
}
if(length > MOUNT_PASSWD_SIZE) {
- printf("mount.cifs failed: password in credentials file too long\n");
+ fprintf(stderr, "mount.cifs failed: password in credentials file too long\n");
memset(line_buf,0, 4096);
exit(EX_USAGE);
} else {
/* go past equals sign */
temp_val++;
if(verboseflag)
- printf("\nDomain %s\n",temp_val);
+ fprintf(stderr, "\nDomain %s\n",temp_val);
for(length = 0;length<DOMAIN_SIZE+1;length++) {
if ((temp_val[length] == '\n')
|| (temp_val[length] == '\0')) {
}
}
if(length > DOMAIN_SIZE) {
- printf("mount.cifs failed: domain in credentials file too long\n");
+ fprintf(stderr, "mount.cifs failed: domain in credentials file too long\n");
exit(EX_USAGE);
} else {
if(domain_name == NULL) {
memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
if (mountpassword == NULL) {
- printf("malloc failed\n");
+ fprintf(stderr, "malloc failed\n");
exit(EX_SYSERR);
}
if(filename != NULL) {
+ rc = access(filename, R_OK);
+ if (rc) {
+ fprintf(stderr, "mount.cifs failed: access check of %s failed: %s\n",
+ filename, strerror(errno));
+ exit(EX_SYSERR);
+ }
file_descript = open(filename, O_RDONLY);
if(file_descript < 0) {
- printf("mount.cifs failed. %s attempting to open password file %s\n",
+ fprintf(stderr, "mount.cifs failed. %s attempting to open password file %s\n",
strerror(errno),filename);
exit(EX_SYSERR);
}
for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
rc = read(file_descript,&c,1);
if(rc < 0) {
- printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
+ fprintf(stderr, "mount.cifs failed. Error %s reading password file\n",strerror(errno));
if(filename != NULL)
close(file_descript);
exit(EX_SYSERR);
} else if(rc == 0) {
if(mountpassword[0] == 0) {
if(verboseflag)
- printf("\nWarning: null password used since cifs password file empty");
+ fprintf(stderr, "\nWarning: null password used since cifs password file empty");
}
break;
} else /* read valid character */ {
}
}
if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
- printf("\nWarning: password longer than %d characters specified in cifs password file",
+ fprintf(stderr, "\nWarning: password longer than %d characters specified in cifs password file",
MOUNT_PASSWD_SIZE);
}
got_password = 1;
return rc;
}
-static int parse_options(char ** optionsp, int * filesys_flags)
+static int parse_options(char ** optionsp, unsigned long * filesys_flags)
{
const char * data;
char * percent_char = NULL;
return 1;
data = *optionsp;
- if(verboseflag)
- printf("parsing options: %s\n", data);
-
/* BB fixme check for separator override BB */
if (getuid()) {
if (strncmp(data, "users",5) == 0) {
if(!value || !*value) {
+ *filesys_flags |= MS_USERS;
goto nocopy;
}
} else if (strncmp(data, "user_xattr",10) == 0) {
if (!value || !*value) {
if(data[4] == '\0') {
- if(verboseflag)
- printf("\nskipping empty user mount parameter\n");
- /* remove the parm since it would otherwise be confusing
- to the kernel code which would think it was a real username */
+ *filesys_flags |= MS_USER;
goto nocopy;
} else {
- printf("username specified with no parameter\n");
+ fprintf(stderr, "username specified with no parameter\n");
SAFE_FREE(out);
return 1; /* needs_arg; */
}
mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
if(mountpassword) {
if(got_password)
- printf("\nmount.cifs warning - password specified twice\n");
+ fprintf(stderr, "\nmount.cifs warning - password specified twice\n");
got_password = 1;
percent_char++;
strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
invoked */
domain_name = check_for_domain(&value);
} else {
- printf("username too long\n");
+ fprintf(stderr, "username too long\n");
SAFE_FREE(out);
return 1;
}
} else if (strncmp(data, "pass", 4) == 0) {
if (!value || !*value) {
if(got_password) {
- printf("\npassword specified twice, ignoring second\n");
+ fprintf(stderr, "\npassword specified twice, ignoring second\n");
} else
got_password = 1;
} else if (strnlen(value, MOUNT_PASSWD_SIZE) < MOUNT_PASSWD_SIZE) {
- if(got_password)
- printf("\nmount.cifs warning - password specified twice\n");
- got_password = 1;
+ if (got_password) {
+ fprintf(stderr, "\nmount.cifs warning - password specified twice\n");
+ } else {
+ mountpassword = strndup(value, MOUNT_PASSWD_SIZE);
+ if (!mountpassword) {
+ fprintf(stderr, "mount.cifs error: %s", strerror(ENOMEM));
+ SAFE_FREE(out);
+ return 1;
+ }
+ got_password = 1;
+ }
} else {
- printf("password too long\n");
+ fprintf(stderr, "password too long\n");
SAFE_FREE(out);
return 1;
}
+ goto nocopy;
} else if (strncmp(data, "sec", 3) == 0) {
if (value) {
if (!strncmp(value, "none", 4) ||
}
} else if (strncmp(data, "ip", 2) == 0) {
if (!value || !*value) {
- printf("target ip address argument missing");
+ fprintf(stderr, "target ip address argument missing");
} else if (strnlen(value, MAX_ADDRESS_LEN) <= MAX_ADDRESS_LEN) {
if(verboseflag)
- printf("ip address %s override specified\n",value);
+ fprintf(stderr, "ip address %s override specified\n",value);
got_ip = 1;
} else {
- printf("ip address too long\n");
+ fprintf(stderr, "ip address too long\n");
SAFE_FREE(out);
return 1;
}
|| (strncmp(data, "target", 6) == 0)
|| (strncmp(data, "path", 4) == 0)) {
if (!value || !*value) {
- printf("invalid path to network resource\n");
+ fprintf(stderr, "invalid path to network resource\n");
SAFE_FREE(out);
return 1; /* needs_arg; */
} else if(strnlen(value,5) < 5) {
- printf("UNC name too short");
+ fprintf(stderr, "UNC name too short");
}
if (strnlen(value, 300) < 300) {
got_unc = 1;
if (strncmp(value, "//", 2) == 0) {
if(got_unc)
- printf("unc name specified twice, ignoring second\n");
+ fprintf(stderr, "unc name specified twice, ignoring second\n");
else
got_unc = 1;
} else if (strncmp(value, "\\\\", 2) != 0) {
- printf("UNC Path does not begin with // or \\\\ \n");
+ fprintf(stderr, "UNC Path does not begin with // or \\\\ \n");
SAFE_FREE(out);
return 1;
} else {
if(got_unc)
- printf("unc name specified twice, ignoring second\n");
+ fprintf(stderr, "unc name specified twice, ignoring second\n");
else
got_unc = 1;
}
} else {
- printf("CIFS: UNC name too long\n");
+ fprintf(stderr, "CIFS: UNC name too long\n");
SAFE_FREE(out);
return 1;
}
such as "DOM" and "dom" and "workgroup"
and "WORKGRP" etc. */
if (!value || !*value) {
- printf("CIFS: invalid domain name\n");
+ fprintf(stderr, "CIFS: invalid domain name\n");
SAFE_FREE(out);
return 1; /* needs_arg; */
}
if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
got_domain = 1;
} else {
- printf("domain name too long\n");
+ fprintf(stderr, "domain name too long\n");
SAFE_FREE(out);
return 1;
}
if (value && *value) {
rc = open_cred_file(value);
if(rc) {
- printf("error %d (%s) opening credential file %s\n",
+ fprintf(stderr, "error %d (%s) opening credential file %s\n",
rc, strerror(rc), value);
SAFE_FREE(out);
return 1;
}
} else {
- printf("invalid credential file name specified\n");
+ fprintf(stderr, "invalid credential file name specified\n");
SAFE_FREE(out);
return 1;
}
struct passwd *pw;
if (!(pw = getpwnam(value))) {
- printf("bad user name \"%s\"\n", value);
+ fprintf(stderr, "bad user name \"%s\"\n", value);
exit(EX_USAGE);
}
snprintf(user, sizeof(user), "%u", pw->pw_uid);
struct group *gr;
if (!(gr = getgrnam(value))) {
- printf("bad group name \"%s\"\n", value);
+ fprintf(stderr, "bad group name \"%s\"\n", value);
exit(EX_USAGE);
}
snprintf(group, sizeof(group), "%u", gr->gr_gid);
/* fmask and dmask synonyms for people used to smbfs syntax */
} else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
if (!value || !*value) {
- printf ("Option '%s' requires a numerical argument\n", data);
+ fprintf(stderr, "Option '%s' requires a numerical argument\n", data);
SAFE_FREE(out);
return 1;
}
if (value[0] != '0') {
- printf ("WARNING: '%s' not expressed in octal.\n", data);
+ fprintf(stderr, "WARNING: '%s' not expressed in octal.\n", data);
}
if (strcmp (data, "fmask") == 0) {
- printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
+ fprintf(stderr, "WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
data = "file_mode"; /* BB fix this */
}
} else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
if (!value || !*value) {
- printf ("Option '%s' requires a numerical argument\n", data);
+ fprintf(stderr, "Option '%s' requires a numerical argument\n", data);
SAFE_FREE(out);
return 1;
}
if (value[0] != '0') {
- printf ("WARNING: '%s' not expressed in octal.\n", data);
+ fprintf(stderr, "WARNING: '%s' not expressed in octal.\n", data);
}
if (strcmp (data, "dmask") == 0) {
- printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
+ fprintf(stderr, "WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
data = "dir_mode";
}
/* the following eight mount options should be
got_password = 1;
} else if (strncmp(data, "ro", 2) == 0) {
*filesys_flags |= MS_RDONLY;
+ goto nocopy;
} else if (strncmp(data, "rw", 2) == 0) {
*filesys_flags &= ~MS_RDONLY;
+ goto nocopy;
} else if (strncmp(data, "remount", 7) == 0) {
*filesys_flags |= MS_REMOUNT;
} /* else if (strnicmp(data, "port", 4) == 0) {
}
} else if (strnicmp(data, "version", 3) == 0) {
} else {
- printf("CIFS: Unknown mount option %s\n",data);
+ fprintf(stderr, "CIFS: Unknown mount option %s\n",data);
} */ /* nothing to do on those four mount options above.
Just pass to kernel and ignore them here */
return;
if(number_of_commas > MOUNT_PASSWD_SIZE) {
/* would otherwise overflow the mount options buffer */
- printf("\nInvalid password. Password contains too many commas.\n");
+ fprintf(stderr, "\nInvalid password. Password contains too many commas.\n");
return;
}
}
if(got_domain) {
- printf("Domain name specified twice. Username probably malformed\n");
+ fprintf(stderr, "Domain name specified twice. Username probably malformed\n");
return NULL;
}
if (domainnm[0] != 0) {
got_domain = 1;
} else {
- printf("null domain\n");
+ fprintf(stderr, "null domain\n");
}
len = strlen(domainnm);
/* reset domainm to new buffer, and copy
int rc;
if(length > (MAX_UNC_LEN - 1)) {
- printf("mount error: UNC name too long");
+ fprintf(stderr, "mount error: UNC name too long");
return NULL;
}
if ((strncasecmp("cifs://", unc_name, 7) == 0) ||
(strncasecmp("smb://", unc_name, 6) == 0)) {
- printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n", unc_name);
+ fprintf(stderr, "\nMounting cifs URL not implemented yet. Attempt to mount %s\n", unc_name);
return NULL;
}
if(length < 3) {
/* BB add code to find DFS root here */
- printf("\nMounting the DFS root for domain not implemented yet\n");
+ fprintf(stderr, "\nMounting the DFS root for domain not implemented yet\n");
return NULL;
} else {
if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
unc_name[length+2] = 0;
goto continue_unc_parsing;
} else {
- printf("mount error: improperly formatted UNC name.");
- printf(" %s does not begin with \\\\ or //\n",unc_name);
+ fprintf(stderr, "mount error: improperly formatted UNC name.");
+ fprintf(stderr, " %s does not begin with \\\\ or //\n",unc_name);
return NULL;
}
} else {
if(got_ip == 0) {
rc = getaddrinfo(unc_name, NULL, NULL, &addrlist);
if (rc != 0) {
- printf("mount error: could not resolve address for %s: %s\n",
+ fprintf(stderr, "mount error: could not resolve address for %s: %s\n",
unc_name, gai_strerror(rc));
addrlist = NULL;
}
}
if(got_ip) {
if(verboseflag)
- printf("ip address specified explicitly\n");
+ fprintf(stderr, "ip address specified explicitly\n");
return NULL;
}
/* BB should we pass an alternate version of the share name as Unicode */
return addrlist;
} else {
/* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
- printf("Mounting the DFS root for a particular server not implemented yet\n");
+ fprintf(stderr, "Mounting the DFS root for a particular server not implemented yet\n");
return NULL;
}
}
int main(int argc, char ** argv)
{
int c;
- int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
+ unsigned long flags = MS_MANDLOCK;
char * orgoptions = NULL;
char * share_name = NULL;
const char * ipaddr = NULL;
size_t current_len;
int retry = 0; /* set when we have to retry mount with uppercase */
struct addrinfo *addrhead = NULL, *addr;
- struct stat statbuf;
struct utsname sysinfo;
struct mntent mountent;
struct sockaddr_in *addr4;
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE); */
- if(argc && argv) {
+ if(argc && argv)
thisprogram = argv[0];
- } else {
- mount_cifs_usage();
- exit(EX_USAGE);
- }
+ else
+ mount_cifs_usage(stderr);
if(thisprogram == NULL)
thisprogram = "mount.cifs";
/* BB add workstation name and domain and pass down */
/* #ifdef _GNU_SOURCE
- printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
+ fprintf(stderr, " node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
#endif */
if(argc > 2) {
dev_name = argv[1];
if ((strcmp(argv[1], "-h") == 0) ||
(strcmp(argv[1], "-?") == 0) ||
(strcmp(argv[1], "--help") == 0))
- {
- mount_cifs_usage();
- exit(0);
- }
+ mount_cifs_usage(stdout);
- mount_cifs_usage();
- exit(EX_USAGE);
+ mount_cifs_usage(stderr);
} else {
- mount_cifs_usage();
- exit(EX_USAGE);
+ mount_cifs_usage(stderr);
}
- /* add sharename in opts string as unc= parm */
+ /* add sharename in opts string as unc= parm */
while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
longopts, NULL)) != -1) {
switch (c) {
case '?':
case 'h': /* help */
- mount_cifs_usage ();
- exit(0);
+ mount_cifs_usage(stdout);
case 'n':
++nomtab;
break;
uid = strtoul(optarg, &ep, 10);
if (*ep) {
- printf("bad uid value \"%s\"\n", optarg);
+ fprintf(stderr, "bad uid value \"%s\"\n", optarg);
exit(EX_USAGE);
}
} else {
struct passwd *pw;
if (!(pw = getpwnam(optarg))) {
- printf("bad user name \"%s\"\n", optarg);
+ fprintf(stderr, "bad user name \"%s\"\n", optarg);
exit(EX_USAGE);
}
uid = pw->pw_uid;
gid = strtoul(optarg, &ep, 10);
if (*ep) {
- printf("bad gid value \"%s\"\n", optarg);
+ fprintf(stderr, "bad gid value \"%s\"\n", optarg);
exit(EX_USAGE);
}
} else {
struct group *gr;
if (!(gr = getgrnam(optarg))) {
- printf("bad user name \"%s\"\n", optarg);
+ fprintf(stderr, "bad user name \"%s\"\n", optarg);
exit(EX_USAGE);
}
gid = gr->gr_gid;
++fakemnt;
break;
default:
- printf("unknown mount option %c\n",c);
- mount_cifs_usage();
- exit(EX_USAGE);
+ fprintf(stderr, "unknown mount option %c\n",c);
+ mount_cifs_usage(stderr);
}
}
if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
- mount_cifs_usage();
- exit(EX_USAGE);
+ mount_cifs_usage(stderr);
+ }
+
+ /* make sure mountpoint is legit */
+ rc = chdir(mountpoint);
+ if (rc) {
+ fprintf(stderr, "Couldn't chdir to %s: %s\n", mountpoint,
+ strerror(errno));
+ rc = EX_USAGE;
+ goto mount_exit;
+ }
+
+ rc = check_mountpoint(thisprogram, mountpoint);
+ if (rc)
+ goto mount_exit;
+
+ /* sanity check for unprivileged mounts */
+ if (getuid()) {
+ rc = check_fstab(thisprogram, mountpoint, dev_name,
+ &orgoptions);
+ if (rc)
+ goto mount_exit;
+
+ /* enable any default user mount flags */
+ flags |= CIFS_SETUID_FLAGS;
}
if (getenv("PASSWD")) {
rc = EX_USAGE;
goto mount_exit;
}
+
+ if (getuid()) {
+#if !CIFS_LEGACY_SETUID_CHECK
+ if (!(flags & (MS_USERS|MS_USER))) {
+ fprintf(stderr, "%s: permission denied\n", thisprogram);
+ rc = EX_USAGE;
+ goto mount_exit;
+ }
+#endif /* !CIFS_LEGACY_SETUID_CHECK */
+
+ if (geteuid()) {
+ fprintf(stderr, "%s: not installed setuid - \"user\" "
+ "CIFS mounts not supported.",
+ thisprogram);
+ rc = EX_FAIL;
+ goto mount_exit;
+ }
+ }
+
+ flags &= ~(MS_USERS|MS_USER);
+
addrhead = addr = parse_server(&share_name);
if((addrhead == NULL) && (got_ip == 0)) {
- printf("No ip address specified and hostname not found\n");
+ fprintf(stderr, "No ip address specified and hostname not found\n");
rc = EX_USAGE;
goto mount_exit;
}
/* BB save off path and pop after mount returns? */
resolved_path = (char *)malloc(PATH_MAX+1);
- if(resolved_path) {
- /* Note that if we can not canonicalize the name, we get
- another chance to see if it is valid when we chdir to it */
- if (realpath(mountpoint, resolved_path)) {
- mountpoint = resolved_path;
- }
- }
- if(chdir(mountpoint)) {
- printf("mount error: can not change directory into mount target %s\n",mountpoint);
- rc = EX_USAGE;
+ if (!resolved_path) {
+ fprintf(stderr, "Unable to allocate memory.\n");
+ rc = EX_SYSERR;
goto mount_exit;
}
- if(stat (".", &statbuf)) {
- printf("mount error: mount point %s does not exist\n",mountpoint);
- rc = EX_USAGE;
+ /* Note that if we can not canonicalize the name, we get
+ another chance to see if it is valid when we chdir to it */
+ if(!realpath(".", resolved_path)) {
+ fprintf(stderr, "Unable to resolve %s to canonical path: %s\n",
+ mountpoint, strerror(errno));
+ rc = EX_SYSERR;
goto mount_exit;
}
- if (S_ISDIR(statbuf.st_mode) == 0) {
- printf("mount error: mount point %s is not a directory\n",mountpoint);
- rc = EX_USAGE;
- goto mount_exit;
- }
-
- if((getuid() != 0) && (geteuid() == 0)) {
- if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
-#ifndef CIFS_ALLOW_USR_SUID
- /* Do not allow user mounts to control suid flag
- for mount unless explicitly built that way */
- flags |= MS_NOSUID | MS_NODEV;
-#endif
- } else {
- printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
- exit(EX_USAGE);
- }
- }
+ mountpoint = resolved_path;
if(got_user == 0) {
/* Note that the password will not be retrieved from the
no good replacement yet. */
mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
if (!tmp_pass || !mountpassword) {
- printf("Password not entered, exiting\n");
+ fprintf(stderr, "Password not entered, exiting\n");
exit(EX_USAGE);
}
strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
if(share_name)
optlen += strlen(share_name) + 4;
else {
- printf("No server share name specified\n");
- printf("\nMounting the DFS root for server not implemented yet\n");
+ fprintf(stderr, "No server share name specified\n");
+ fprintf(stderr, "\nMounting the DFS root for server not implemented yet\n");
exit(EX_USAGE);
}
if(user_name)
options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain= , domain name itself was counted as part of the length username string above */);
if(options == NULL) {
- printf("Could not allocate memory for mount options\n");
+ fprintf(stderr, "Could not allocate memory for mount options\n");
exit(EX_SYSERR);
}
strlcat(options,domain_name,options_size);
}
}
- if(mountpassword) {
- /* Commas have to be doubled, or else they will
- look like the parameter separator */
-/* if(sep is not set)*/
- if(retry == 0)
- check_for_comma(&mountpassword);
- strlcat(options,",pass=",options_size);
- strlcat(options,mountpassword,options_size);
- }
strlcat(options,",ver=",options_size);
strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
strlcat(options,",prefixpath=",options_size);
strlcat(options,prefixpath,options_size); /* no need to cat the / */
}
- if(verboseflag)
- printf("\nmount.cifs kernel mount options %s \n",options);
/* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
replace_char(dev_name, '\\', '/', strlen(share_name));
ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail,
options_size - current_len);
break;
+ default:
+ ipaddr = NULL;
}
/* if the address looks bogus, try the next one */
}
}
- if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) {
+ if (addr->ai_addr->sa_family == AF_INET6 && addr6->sin6_scope_id) {
+ strlcat(options, "%", options_size);
+ current_len = strnlen(options, options_size);
+ optionstail = options + current_len;
+ snprintf(optionstail, options_size - current_len, "%u",
+ addr6->sin6_scope_id);
+ }
+
+ if(verboseflag)
+ fprintf(stderr, "\nmount.cifs kernel mount options: %s", options);
+
+ if (mountpassword) {
+ /*
+ * Commas have to be doubled, or else they will
+ * look like the parameter separator
+ */
+ if(retry == 0)
+ check_for_comma(&mountpassword);
+ strlcat(options,",pass=",options_size);
+ strlcat(options,mountpassword,options_size);
+ if (verboseflag)
+ fprintf(stderr, ",pass=********");
+ }
+
+ if (verboseflag)
+ fprintf(stderr, "\n");
+
+ if (!fakemnt && mount(dev_name, ".", cifs_fstype, flags, options)) {
switch (errno) {
case ECONNREFUSED:
case EHOSTUNREACH:
}
break;
case ENODEV:
- printf("mount error: cifs filesystem not supported by the system\n");
+ fprintf(stderr, "mount error: cifs filesystem not supported by the system\n");
break;
case ENXIO:
if(retry == 0) {
if (uppercase_string(dev_name) &&
uppercase_string(share_name) &&
uppercase_string(prefixpath)) {
- printf("retrying with upper case share name\n");
+ fprintf(stderr, "retrying with upper case share name\n");
goto mount_retry;
}
}
}
- printf("mount error(%d): %s\n", errno, strerror(errno));
- printf("Refer to the mount.cifs(8) manual page (e.g. man "
+ fprintf(stderr, "mount error(%d): %s\n", errno, strerror(errno));
+ fprintf(stderr, "Refer to the mount.cifs(8) manual page (e.g. man "
"mount.cifs)\n");
rc = EX_FAIL;
goto mount_exit;
atexit(unlock_mtab);
rc = lock_mtab();
if (rc) {
- printf("cannot lock mtab");
+ fprintf(stderr, "cannot lock mtab");
goto mount_exit;
}
pmntfile = setmntent(MOUNTED, "a+");
if (!pmntfile) {
- printf("could not update mount table\n");
+ fprintf(stderr, "could not update mount table\n");
unlock_mtab();
rc = EX_FILEIO;
goto mount_exit;
}
mountent.mnt_fsname = dev_name;
mountent.mnt_dir = mountpoint;
- mountent.mnt_type = CONST_DISCARD(char *,"cifs");
+ mountent.mnt_type = (char *)(void *)cifs_fstype;
mountent.mnt_opts = (char *)malloc(220);
if(mountent.mnt_opts) {
char * mount_user = getusername();