Blame mount.cifs.c

Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Mount helper utility for Linux CIFS VFS (virtual filesystem) client
Packit Service 09cdfc
 * Copyright (C) 2003,2010 Steve French  (sfrench@us.ibm.com)
Packit Service 09cdfc
 * Copyright (C) 2008 Jeremy Allison (jra@samba.org)
Packit Service 09cdfc
 * Copyright (C) 2010 Jeff Layton (jlayton@samba.org)
Packit Service 09cdfc
 *
Packit Service 09cdfc
 * This program is free software; you can redistribute it and/or modify
Packit Service 09cdfc
 * it under the terms of the GNU General Public License as published by
Packit Service 09cdfc
 * the Free Software Foundation; either version 3 of the License, or
Packit Service 09cdfc
 * (at your option) any later version.
Packit Service 09cdfc
 *
Packit Service 09cdfc
 * This program is distributed in the hope that it will be useful,
Packit Service 09cdfc
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 09cdfc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 09cdfc
 * GNU General Public License for more details.
Packit Service 09cdfc
 *
Packit Service 09cdfc
 * You should have received a copy of the GNU General Public License
Packit Service 09cdfc
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 09cdfc
 */
Packit Service 09cdfc
Packit Service 09cdfc
#ifdef HAVE_CONFIG_H
Packit Service 09cdfc
#include "config.h"
Packit Service 09cdfc
#endif /* HAVE_CONFIG_H */
Packit Service 09cdfc
Packit Service 09cdfc
#include <stdlib.h>
Packit Service 09cdfc
#include <stdio.h>
Packit Service 09cdfc
#include <unistd.h>
Packit Service 09cdfc
#include <pwd.h>
Packit Service 09cdfc
#include <grp.h>
Packit Service 09cdfc
#include <ctype.h>
Packit Service 09cdfc
#include <sys/types.h>
Packit Service 09cdfc
#include <sys/mount.h>
Packit Service 09cdfc
#include <sys/stat.h>
Packit Service 09cdfc
#include <sys/utsname.h>
Packit Service 09cdfc
#include <sys/socket.h>
Packit Service 09cdfc
#include <arpa/inet.h>
Packit Service 09cdfc
#include <getopt.h>
Packit Service 09cdfc
#include <errno.h>
Packit Service 09cdfc
#include <netdb.h>
Packit Service 09cdfc
#include <string.h>
Packit Service 09cdfc
#include <mntent.h>
Packit Service 09cdfc
#include <fcntl.h>
Packit Service 09cdfc
#include <limits.h>
Packit Service 09cdfc
#include <paths.h>
Packit Service 09cdfc
#include <libgen.h>
Packit Service 09cdfc
#include <sys/mman.h>
Packit Service 09cdfc
#include <sys/wait.h>
Packit Service 09cdfc
#ifdef HAVE_SYS_FSUID_H
Packit Service 09cdfc
#include <sys/fsuid.h>
Packit Service 09cdfc
#endif /* HAVE_SYS_FSUID_H */
Packit Service 09cdfc
#ifdef HAVE_LIBCAP_NG
Packit Service 09cdfc
#include <cap-ng.h>
Packit Service 09cdfc
#else /* HAVE_LIBCAP_NG */
Packit Service 09cdfc
#ifdef HAVE_PRCTL
Packit Service 09cdfc
#include <sys/prctl.h>
Packit Service 09cdfc
#endif /* HAVE_PRCTL */
Packit Service 09cdfc
#ifdef HAVE_LIBCAP
Packit Service 09cdfc
#include <sys/capability.h>
Packit Service 09cdfc
#endif /* HAVE_LIBCAP */
Packit Service 09cdfc
#endif /* HAVE_LIBCAP_NG */
Packit Service 09cdfc
#include "mount.h"
Packit Service 09cdfc
#include "util.h"
Packit Service 09cdfc
#include "resolve_host.h"
Packit Service 09cdfc
Packit Service 09cdfc
#ifndef MS_MOVE 
Packit Service 09cdfc
#define MS_MOVE 8192 
Packit Service 09cdfc
#endif 
Packit Service 09cdfc
Packit Service 09cdfc
#ifndef MS_BIND
Packit Service 09cdfc
#define MS_BIND 4096
Packit Service 09cdfc
#endif
Packit Service 09cdfc
Packit Service 09cdfc
/* private flags - clear these before passing to kernel */
Packit Service 09cdfc
#define MS_USERS	0x40000000
Packit Service 09cdfc
#define MS_USER		0x80000000
Packit Service 09cdfc
Packit Service 09cdfc
#define MAX_UNC_LEN 1024
Packit Service 09cdfc
Packit Service 09cdfc
/* I believe that the kernel limits options data to a page */
Packit Service 09cdfc
#define MAX_OPTIONS_LEN	4096
Packit Service 09cdfc
Packit Service 09cdfc
/* max length of mtab options */
Packit Service 09cdfc
#define MTAB_OPTIONS_LEN 220
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Max share name, username, password and domain sizes match the kernel's
Packit Service 09cdfc
 * allowances for these string sizes which in turn match Microsoft's
Packit Service 09cdfc
 * documentation.
Packit Service 09cdfc
 */
Packit Service 09cdfc
Packit Service 09cdfc
/* Max length of the share name portion of a UNC. Share names over 80
Packit Service 09cdfc
 * characters cannot be accessed via commandline in Windows 2000/XP. */
Packit Service 09cdfc
#define MAX_SHARE_LEN 256
Packit Service 09cdfc
Packit Service 09cdfc
/* Max user name length. */
Packit Service 09cdfc
#define MAX_USERNAME_SIZE 256
Packit Service 09cdfc
Packit Service 09cdfc
/* Max domain size. */
Packit Service 09cdfc
#define MAX_DOMAIN_SIZE 256
Packit Service 09cdfc
Packit Service 09cdfc
/* Max password size. */
Packit Service 09cdfc
#define MOUNT_PASSWD_SIZE 512
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * mount.cifs has been the subject of many "security" bugs that have arisen
Packit Service 09cdfc
 * because of users and distributions installing it as a setuid root program
Packit Service 09cdfc
 * before it had been audited for security holes. The default behavior is
Packit Service 09cdfc
 * now to allow mount.cifs to be run as a setuid root program. Some admins
Packit Service 09cdfc
 * may want to disable this fully, so this switch remains in place.
Packit Service 09cdfc
 */
Packit Service 09cdfc
#define CIFS_DISABLE_SETUID_CAPABILITY 0
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * When an unprivileged user runs a setuid mount.cifs, we set certain mount
Packit Service 09cdfc
 * flags by default. These defaults can be changed here.
Packit Service 09cdfc
 */
Packit Service 09cdfc
#define CIFS_SETUID_FLAGS (MS_NOSUID|MS_NODEV)
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Values for parsing a credentials file.
Packit Service 09cdfc
 */
Packit Service 09cdfc
#define CRED_UNPARSEABLE 0
Packit Service 09cdfc
#define CRED_USER        1
Packit Service 09cdfc
#define CRED_PASS        2
Packit Service 09cdfc
#define CRED_DOM         4
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Values for parsing command line options.
Packit Service 09cdfc
 */
Packit Service 09cdfc
#define OPT_ERROR       -1
Packit Service 09cdfc
#define OPT_IGNORE      0
Packit Service 09cdfc
#define OPT_USERS       1
Packit Service 09cdfc
#define OPT_USER        2
Packit Service 09cdfc
#define OPT_USER_XATTR  3
Packit Service 09cdfc
#define OPT_PASS        4
Packit Service 09cdfc
#define OPT_SEC         5
Packit Service 09cdfc
#define OPT_IP          6
Packit Service 09cdfc
#define OPT_UNC         7
Packit Service 09cdfc
#define OPT_CRED        8
Packit Service 09cdfc
#define OPT_UID         9
Packit Service 09cdfc
#define OPT_GID        10
Packit Service 09cdfc
#define OPT_FMASK      11
Packit Service 09cdfc
#define OPT_FILE_MODE  12
Packit Service 09cdfc
#define OPT_DMASK      13
Packit Service 09cdfc
#define OPT_DIR_MODE   14
Packit Service 09cdfc
#define OPT_DOM        15
Packit Service 09cdfc
#define OPT_NO_SUID    16
Packit Service 09cdfc
#define OPT_SUID       17
Packit Service 09cdfc
#define OPT_NO_DEV     18
Packit Service 09cdfc
#define OPT_DEV        19
Packit Service 09cdfc
#define OPT_NO_LOCK    20
Packit Service 09cdfc
#define OPT_NO_EXEC    21
Packit Service 09cdfc
#define OPT_EXEC       22
Packit Service 09cdfc
#define OPT_GUEST      23
Packit Service 09cdfc
#define OPT_RO         24
Packit Service 09cdfc
#define OPT_RW         25
Packit Service 09cdfc
#define OPT_REMOUNT    26
Packit Service 09cdfc
#define OPT_MAND       27
Packit Service 09cdfc
#define OPT_NOMAND     28
Packit Service 09cdfc
#define OPT_CRUID      29
Packit Service 09cdfc
#define OPT_BKUPUID    30
Packit Service 09cdfc
#define OPT_BKUPGID    31
Packit Service 09cdfc
#define OPT_NOFAIL     32
Packit Service 09cdfc
Packit Service 09cdfc
#define MNT_TMP_FILE "/.mtab.cifs.XXXXXX"
Packit Service 09cdfc
Packit Service 09cdfc
/* struct for holding parsed mount info for use by privleged process */
Packit Service 09cdfc
struct parsed_mount_info {
Packit Service 09cdfc
	unsigned long flags;
Packit Service 09cdfc
	char host[NI_MAXHOST + 1];
Packit Service 09cdfc
	char share[MAX_SHARE_LEN + 1];
Packit Service 09cdfc
	char prefix[PATH_MAX + 1];
Packit Service 09cdfc
	char options[MAX_OPTIONS_LEN];
Packit Service 09cdfc
	char domain[MAX_DOMAIN_SIZE + 1];
Packit Service 09cdfc
	char username[MAX_USERNAME_SIZE + 1];
Packit Service 09cdfc
	char password[MOUNT_PASSWD_SIZE + 1];
Packit Service 09cdfc
	char addrlist[MAX_ADDR_LIST_LEN];
Packit Service 09cdfc
	unsigned int got_user:1;
Packit Service 09cdfc
	unsigned int got_password:1;
Packit Service 09cdfc
	unsigned int fakemnt:1;
Packit Service 09cdfc
	unsigned int nomtab:1;
Packit Service 09cdfc
	unsigned int verboseflag:1;
Packit Service 09cdfc
	unsigned int nofail:1;
Packit Service 09cdfc
	unsigned int got_domain:1;
Packit Service 09cdfc
};
Packit Service 09cdfc
Packit Service 09cdfc
static const char *thisprogram;
Packit Service 09cdfc
static const char *cifs_fstype = "cifs";
Packit Service 09cdfc
Packit Service 09cdfc
static int parse_unc(const char *unc_name, struct parsed_mount_info *parsed_info);
Packit Service 09cdfc
Packit Service 09cdfc
static int check_setuid(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (geteuid()) {
Packit Service 09cdfc
		fprintf(stderr, "This program is not installed setuid root - "
Packit Service 09cdfc
			" \"user\" CIFS mounts not supported.\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
#if CIFS_DISABLE_SETUID_CAPABILITY
Packit Service 09cdfc
	if (getuid() && !geteuid()) {
Packit Service 09cdfc
		printf("This mount.cifs program has been built with the "
Packit Service 09cdfc
		       "ability to run as a setuid root program disabled.\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
#endif /* CIFS_DISABLE_SETUID_CAPABILITY */
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
check_fstab(const char *progname, const char *mountpoint, const char *devname,
Packit Service 09cdfc
	    char **options)
Packit Service 09cdfc
{
Packit Service 09cdfc
	FILE *fstab;
Packit Service 09cdfc
	struct mntent *mnt;
Packit Service 09cdfc
Packit Service 09cdfc
	/* make sure this mount is listed in /etc/fstab */
Packit Service 09cdfc
	fstab = setmntent(_PATH_MNTTAB, "r");
Packit Service 09cdfc
	if (!fstab) {
Packit Service 09cdfc
		fprintf(stderr, "Couldn't open %s for reading!\n", _PATH_MNTTAB);
Packit Service 09cdfc
		return EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	while ((mnt = getmntent(fstab))) {
Packit Service 09cdfc
		if (!strcmp(mountpoint, mnt->mnt_dir))
Packit Service 09cdfc
			break;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	endmntent(fstab);
Packit Service 09cdfc
Packit Service 09cdfc
	if (mnt == NULL || strcmp(mnt->mnt_fsname, devname)) {
Packit Service 09cdfc
		fprintf(stderr, "%s: permission denied: no match for "
Packit Service 09cdfc
			"%s found in %s\n", progname, mountpoint, _PATH_MNTTAB);
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * 'mount' munges the options from fstab before passing them
Packit Service 09cdfc
	 * to us. It is non-trivial to test that we have the correct
Packit Service 09cdfc
	 * set of options. We don't want to trust what the user
Packit Service 09cdfc
	 * gave us, so just take whatever is in /etc/fstab.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	free(*options);
Packit Service 09cdfc
	*options = strdup(mnt->mnt_opts);
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/* BB finish BB
Packit Service 09cdfc
Packit Service 09cdfc
	cifs_umount
Packit Service 09cdfc
	open nofollow - avoid symlink exposure? 
Packit Service 09cdfc
	get owner of dir see if matches self or if root
Packit Service 09cdfc
	call system(umount argv) etc.
Packit Service 09cdfc
Packit Service 09cdfc
BB end finish BB */
Packit Service 09cdfc
Packit Service 09cdfc
static int mount_usage(FILE * stream)
Packit Service 09cdfc
{
Packit Service 09cdfc
	fprintf(stream, "\nUsage:  %s <remotetarget> <dir> -o <options>\n",
Packit Service 09cdfc
		thisprogram);
Packit Service 09cdfc
	fprintf(stream, "\nMount the remote target, specified as a UNC name,");
Packit Service 09cdfc
	fprintf(stream, " to a local directory.\n\nOptions:\n");
Packit Service 09cdfc
	fprintf(stream, "\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
Packit Service 09cdfc
	fprintf(stream, "\nLess commonly used options:");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign,seal,fsc");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\nOptions not needed for servers supporting CIFS Unix extensions");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\t(e.g. unneeded for mounts to most Samba versions):");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
Packit Service 09cdfc
	fprintf(stream, "\n\nRarely used options:");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
Packit Service 09cdfc
	fprintf(stream,
Packit Service 09cdfc
		"\n\nOptions are described in more detail in the manual page");
Packit Service 09cdfc
	fprintf(stream, "\n\tman 8 mount.cifs\n");
Packit Service 09cdfc
	fprintf(stream, "\nTo display the version number of the mount helper:");
Packit Service 09cdfc
	fprintf(stream, "\n\t%s -V\n", thisprogram);
Packit Service 09cdfc
Packit Service 09cdfc
	if (stream == stderr)
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * CIFS has to "escape" commas in the password field so that they don't
Packit Service 09cdfc
 * end up getting confused for option delimiters. Copy password into pw
Packit Service 09cdfc
 * field, turning any commas into double commas.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int set_password(struct parsed_mount_info *parsed_info, const char *src)
Packit Service 09cdfc
{
Packit Service 09cdfc
	char *dst = parsed_info->password;
Packit Service 09cdfc
	unsigned int i = 0, j = 0;
Packit Service 09cdfc
Packit Service 09cdfc
	while (src[i]) {
Packit Service 09cdfc
		if (src[i] == ',')
Packit Service 09cdfc
			dst[j++] = ',';
Packit Service 09cdfc
		dst[j++] = src[i++];
Packit Service 09cdfc
		if (j > sizeof(parsed_info->password)) {
Packit Service 09cdfc
			fprintf(stderr, "Converted password too long!\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	dst[j] = '\0';
Packit Service 09cdfc
	parsed_info->got_password = 1;
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
#ifdef HAVE_LIBCAP_NG
Packit Service 09cdfc
static int
Packit Service 09cdfc
drop_capabilities(int parent)
Packit Service 09cdfc
{
Packit Service 09cdfc
	capng_setpid(getpid());
Packit Service 09cdfc
	capng_clear(CAPNG_SELECT_BOTH);
Packit Service 09cdfc
	if (parent) {
Packit Service 09cdfc
		if (capng_updatev(CAPNG_ADD, CAPNG_PERMITTED, CAP_DAC_READ_SEARCH, CAP_DAC_OVERRIDE, -1)) {
Packit Service 09cdfc
			fprintf(stderr, "Unable to update capability set.\n");
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		if (capng_update(CAPNG_ADD, CAPNG_PERMITTED|CAPNG_EFFECTIVE, CAP_SYS_ADMIN)) {
Packit Service 09cdfc
			fprintf(stderr, "Unable to update capability set.\n");
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	} else {
Packit Service 09cdfc
		if (capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_DAC_READ_SEARCH)) {
Packit Service 09cdfc
			fprintf(stderr, "Unable to update capability set.\n");
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (capng_apply(CAPNG_SELECT_BOTH)) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to apply new capability set.\n");
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
toggle_dac_capability(int writable, int enable)
Packit Service 09cdfc
{
Packit Service 09cdfc
	unsigned int capability = writable ? CAP_DAC_OVERRIDE : CAP_DAC_READ_SEARCH;
Packit Service 09cdfc
Packit Service 09cdfc
	if (capng_update(enable ? CAPNG_ADD : CAPNG_DROP, CAPNG_EFFECTIVE, capability)) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to update capability set.\n");
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (capng_apply(CAPNG_SELECT_CAPS)) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to apply new capability set.\n");
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
#else /* HAVE_LIBCAP_NG */
Packit Service 09cdfc
#ifdef HAVE_LIBCAP
Packit Service 09cdfc
#ifdef HAVE_PRCTL
Packit Service 09cdfc
static int
Packit Service 09cdfc
prune_bounding_set(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int i, rc = 0;
Packit Service 09cdfc
	static int bounding_set_cleared;
Packit Service 09cdfc
Packit Service 09cdfc
	if (bounding_set_cleared)
Packit Service 09cdfc
		return 0;
Packit Service 09cdfc
Packit Service 09cdfc
	for (i = 0; i <= CAP_LAST_CAP && rc == 0; ++i)
Packit Service 09cdfc
		rc = prctl(PR_CAPBSET_DROP, i);
Packit Service 09cdfc
Packit Service 09cdfc
	if (rc != 0) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to clear capability bounding set: %d\n", rc);
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	++bounding_set_cleared;
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
#else /* HAVE_PRCTL */
Packit Service 09cdfc
static int
Packit Service 09cdfc
prune_bounding_set(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
#endif /* HAVE_PRCTL */
Packit Service 09cdfc
static int
Packit Service 09cdfc
drop_capabilities(int parent)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc, ncaps;
Packit Service 09cdfc
	cap_t caps;
Packit Service 09cdfc
	cap_value_t cap_list[3];
Packit Service 09cdfc
Packit Service 09cdfc
	rc = prune_bounding_set();
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
Packit Service 09cdfc
	caps = cap_get_proc();
Packit Service 09cdfc
	if (caps == NULL) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to get current capability set: %s\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (cap_clear(caps) == -1) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to clear capability set: %s\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
		goto free_caps;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (parent || getuid() == 0) {
Packit Service 09cdfc
		ncaps = 1;
Packit Service 09cdfc
		cap_list[0] = CAP_DAC_READ_SEARCH;
Packit Service 09cdfc
		if (parent) {
Packit Service 09cdfc
			cap_list[1] = CAP_DAC_OVERRIDE;
Packit Service 09cdfc
			cap_list[2] = CAP_SYS_ADMIN;
Packit Service 09cdfc
			ncaps += 2;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		if (cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET) == -1) {
Packit Service 09cdfc
			fprintf(stderr, "Unable to set permitted capabilities: %s\n",
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
			rc = EX_SYSERR;
Packit Service 09cdfc
			goto free_caps;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		if (parent) {
Packit Service 09cdfc
			cap_list[0] = CAP_SYS_ADMIN;
Packit Service 09cdfc
			if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) {
Packit Service 09cdfc
				fprintf(stderr, "Unable to set effective capabilities: %s\n",
Packit Service 09cdfc
					strerror(errno));
Packit Service 09cdfc
				rc = EX_SYSERR;
Packit Service 09cdfc
				goto free_caps;
Packit Service 09cdfc
			}
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (cap_set_proc(caps) != 0) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to set current process capabilities: %s\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
free_caps:
Packit Service 09cdfc
	cap_free(caps);
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
toggle_dac_capability(int writable, int enable)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc = 0;
Packit Service 09cdfc
	cap_t caps;
Packit Service 09cdfc
	cap_value_t capability = writable ? CAP_DAC_OVERRIDE : CAP_DAC_READ_SEARCH;
Packit Service 09cdfc
Packit Service 09cdfc
	caps = cap_get_proc();
Packit Service 09cdfc
	if (caps == NULL) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to get current capability set: %s\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability,
Packit Service 09cdfc
			 enable ? CAP_SET : CAP_CLEAR) == -1) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to %s effective capabilities: %s\n",
Packit Service 09cdfc
			enable ? "set" : "clear", strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
		goto free_caps;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (cap_set_proc(caps) != 0) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to set current process capabilities: %s\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
free_caps:
Packit Service 09cdfc
	cap_free(caps);
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
#else /* HAVE_LIBCAP */
Packit Service 09cdfc
static int
Packit Service 09cdfc
drop_capabilities(int parent __attribute((unused)))
Packit Service 09cdfc
{
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
toggle_dac_capability(int writable __attribute((unused)), int enable __attribute((unused)))
Packit Service 09cdfc
{
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
#endif /* HAVE_LIBCAP */
Packit Service 09cdfc
#endif /* HAVE_LIBCAP_NG */
Packit Service 09cdfc
Packit Service 09cdfc
static void null_terminate_endl(char *source)
Packit Service 09cdfc
{
Packit Service 09cdfc
	char *newline = strchr(source, '\n');
Packit Service 09cdfc
	if (newline)
Packit Service 09cdfc
		*newline = '\0';
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Parse a line from the credentials file.  Changes target to first
Packit Service 09cdfc
 * character after '=' on 'line' and returns the value type of the line
Packit Service 09cdfc
 * Returns CRED_UNPARSEABLE on failure or if either parameter is NULL.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int parse_cred_line(char *line, char **target)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (line == NULL || target == NULL)
Packit Service 09cdfc
		goto parsing_err;
Packit Service 09cdfc
Packit Service 09cdfc
	/* position target at first char of value */
Packit Service 09cdfc
	*target = strchr(line, '=');
Packit Service 09cdfc
	if (!*target)
Packit Service 09cdfc
		goto parsing_err;
Packit Service 09cdfc
	*target += 1;
Packit Service 09cdfc
Packit Service 09cdfc
	/* tell the caller which value target points to */
Packit Service 09cdfc
	if (strncasecmp("user", line, 4) == 0)
Packit Service 09cdfc
		return CRED_USER;
Packit Service 09cdfc
	if (strncasecmp("pass", line, 4) == 0)
Packit Service 09cdfc
		return CRED_PASS;
Packit Service 09cdfc
	if (strncasecmp("dom", line, 3) == 0)
Packit Service 09cdfc
		return CRED_DOM;
Packit Service 09cdfc
Packit Service 09cdfc
parsing_err:
Packit Service 09cdfc
	return CRED_UNPARSEABLE;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int open_cred_file(char *file_name,
Packit Service 09cdfc
			struct parsed_mount_info *parsed_info)
Packit Service 09cdfc
{
Packit Service 09cdfc
	char *line_buf = NULL;
Packit Service 09cdfc
	char *temp_val = NULL;
Packit Service 09cdfc
	FILE *fs = NULL;
Packit Service 09cdfc
	int i;
Packit Service 09cdfc
	const int line_buf_size = 4096;
Packit Service 09cdfc
	const int min_non_white = 10;
Packit Service 09cdfc
Packit Service 09cdfc
	i = toggle_dac_capability(0, 1);
Packit Service 09cdfc
	if (i)
Packit Service 09cdfc
		goto return_i;
Packit Service 09cdfc
Packit Service 09cdfc
	i = access(file_name, R_OK);
Packit Service 09cdfc
	if (i) {
Packit Service 09cdfc
		toggle_dac_capability(0, 0);
Packit Service 09cdfc
		i = errno;
Packit Service 09cdfc
		goto return_i;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	fs = fopen(file_name, "r");
Packit Service 09cdfc
	if (fs == NULL) {
Packit Service 09cdfc
		toggle_dac_capability(0, 0);
Packit Service 09cdfc
		i = errno;
Packit Service 09cdfc
		goto return_i;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	i = toggle_dac_capability(0, 0);
Packit Service 09cdfc
	if (i)
Packit Service 09cdfc
		goto return_i;
Packit Service 09cdfc
Packit Service 09cdfc
	line_buf = (char *)malloc(line_buf_size);
Packit Service 09cdfc
	if (line_buf == NULL) {
Packit Service 09cdfc
		i = EX_SYSERR;
Packit Service 09cdfc
		goto return_i;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* parse line from credentials file */
Packit Service 09cdfc
	while (fgets(line_buf, line_buf_size, fs)) {
Packit Service 09cdfc
		/* eat leading white space */
Packit Service 09cdfc
		for (i = 0; i < line_buf_size - min_non_white + 1; i++) {
Packit Service 09cdfc
			if ((line_buf[i] != ' ') && (line_buf[i] != '\t'))
Packit Service 09cdfc
				break;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		null_terminate_endl(line_buf);
Packit Service 09cdfc
Packit Service 09cdfc
		/* parse next token */
Packit Service 09cdfc
		switch (parse_cred_line(line_buf + i, &temp_val)) {
Packit Service 09cdfc
		case CRED_USER:
Packit Service 09cdfc
			strlcpy(parsed_info->username, temp_val,
Packit Service 09cdfc
				sizeof(parsed_info->username));
Packit Service 09cdfc
			parsed_info->got_user = 1;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case CRED_PASS:
Packit Service 09cdfc
			i = set_password(parsed_info, temp_val);
Packit Service 09cdfc
			if (i)
Packit Service 09cdfc
				goto return_i;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case CRED_DOM:
Packit Service 09cdfc
			if (parsed_info->verboseflag)
Packit Service 09cdfc
				fprintf(stderr, "domain=%s\n",
Packit Service 09cdfc
					temp_val);
Packit Service 09cdfc
			strlcpy(parsed_info->domain, temp_val,
Packit Service 09cdfc
				sizeof(parsed_info->domain));
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case CRED_UNPARSEABLE:
Packit Service 09cdfc
			if (parsed_info->verboseflag)
Packit Service 09cdfc
				fprintf(stderr, "Credential formatted "
Packit Service 09cdfc
					"incorrectly: %s\n",
Packit Service 09cdfc
					temp_val ? temp_val : "(null)");
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	i = 0;
Packit Service 09cdfc
return_i:
Packit Service 09cdfc
	if (fs != NULL)
Packit Service 09cdfc
		fclose(fs);
Packit Service 09cdfc
Packit Service 09cdfc
	/* make sure passwords are scrubbed from memory */
Packit Service 09cdfc
	if (line_buf != NULL)
Packit Service 09cdfc
		memset(line_buf, 0, line_buf_size);
Packit Service 09cdfc
	free(line_buf);
Packit Service 09cdfc
	return i;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
get_password_from_file(int file_descript, char *filename,
Packit Service 09cdfc
		       struct parsed_mount_info *parsed_info)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc = 0;
Packit Service 09cdfc
	char buf[sizeof(parsed_info->password) + 1];
Packit Service 09cdfc
Packit Service 09cdfc
	if (filename != NULL) {
Packit Service 09cdfc
		rc = toggle_dac_capability(0, 1);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			return rc;
Packit Service 09cdfc
Packit Service 09cdfc
		rc = access(filename, R_OK);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"mount.cifs failed: access check of %s failed: %s\n",
Packit Service 09cdfc
				filename, strerror(errno));
Packit Service 09cdfc
			toggle_dac_capability(0, 0);
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		file_descript = open(filename, O_RDONLY);
Packit Service 09cdfc
		if (file_descript < 0) {
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"mount.cifs failed. %s attempting to open password file %s\n",
Packit Service 09cdfc
				strerror(errno), filename);
Packit Service 09cdfc
			toggle_dac_capability(0, 0);
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = toggle_dac_capability(0, 0);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			rc = EX_SYSERR;
Packit Service 09cdfc
			goto get_pw_exit;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	memset(buf, 0, sizeof(buf));
Packit Service 09cdfc
	rc = read(file_descript, buf, sizeof(buf) - 1);
Packit Service 09cdfc
	if (rc < 0) {
Packit Service 09cdfc
		fprintf(stderr,
Packit Service 09cdfc
			"mount.cifs failed. Error %s reading password file\n",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
		goto get_pw_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = set_password(parsed_info, buf);
Packit Service 09cdfc
Packit Service 09cdfc
get_pw_exit:
Packit Service 09cdfc
	if (filename != NULL)
Packit Service 09cdfc
		close(file_descript);
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Returns OPT_ERROR on unparsable token.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int parse_opt_token(const char *token)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (token == NULL)
Packit Service 09cdfc
		return OPT_ERROR;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * token is NULL terminated and contains exactly the
Packit Service 09cdfc
	 * keyword so we can match exactly
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	if (strcmp(token, "users") == 0)
Packit Service 09cdfc
		return OPT_USERS;
Packit Service 09cdfc
	if (strcmp(token, "user_xattr") == 0)
Packit Service 09cdfc
		return OPT_USER_XATTR;
Packit Service 09cdfc
	if (strcmp(token, "user") == 0 ||
Packit Service 09cdfc
		strcmp(token, "username") == 0)
Packit Service 09cdfc
		return OPT_USER;
Packit Service 09cdfc
	if (strcmp(token, "pass") == 0 ||
Packit Service 09cdfc
		strcmp(token, "password") == 0)
Packit Service 09cdfc
		return OPT_PASS;
Packit Service 09cdfc
	if (strcmp(token, "sec") == 0)
Packit Service 09cdfc
		return OPT_SEC;
Packit Service 09cdfc
	if (strcmp(token, "ip") == 0 ||
Packit Service 09cdfc
		strcmp(token, "addr") == 0)
Packit Service 09cdfc
		return OPT_IP;
Packit Service 09cdfc
	if (strcmp(token, "unc") == 0 ||
Packit Service 09cdfc
		strcmp(token, "target") == 0 ||
Packit Service 09cdfc
		strcmp(token, "path") == 0)
Packit Service 09cdfc
		return OPT_UNC;
Packit Service 09cdfc
	if (strcmp(token, "dom") == 0 ||
Packit Service 09cdfc
		strcmp(token, "domain") == 0 ||
Packit Service 09cdfc
		strcmp(token, "workgroup") == 0)
Packit Service 09cdfc
		return OPT_DOM;
Packit Service 09cdfc
	if (strcmp(token, "cred") == 0 || /* undocumented */
Packit Service 09cdfc
		strcmp(token, "credentials") == 0)
Packit Service 09cdfc
		return OPT_CRED;
Packit Service 09cdfc
	if (strcmp(token, "uid") == 0)
Packit Service 09cdfc
		return OPT_UID;
Packit Service 09cdfc
	if (strcmp(token, "cruid") == 0)
Packit Service 09cdfc
		return OPT_CRUID;
Packit Service 09cdfc
	if (strcmp(token, "gid") == 0)
Packit Service 09cdfc
		return OPT_GID;
Packit Service 09cdfc
	if (strcmp(token, "fmask") == 0)
Packit Service 09cdfc
		return OPT_FMASK;
Packit Service 09cdfc
	if (strcmp(token, "file_mode") == 0)
Packit Service 09cdfc
		return OPT_FILE_MODE;
Packit Service 09cdfc
	if (strcmp(token, "dmask") == 0)
Packit Service 09cdfc
		return OPT_DMASK;
Packit Service 09cdfc
	if (strcmp(token, "dir_mode") == 0 ||
Packit Service 09cdfc
		strcmp(token, "dirm") == 0)
Packit Service 09cdfc
		return OPT_DIR_MODE;
Packit Service 09cdfc
	if (strcmp(token, "nosuid") == 0)
Packit Service 09cdfc
		return OPT_NO_SUID;
Packit Service 09cdfc
	if (strcmp(token, "suid") == 0)
Packit Service 09cdfc
		return OPT_SUID;
Packit Service 09cdfc
	if (strcmp(token, "nodev") == 0)
Packit Service 09cdfc
		return OPT_NO_DEV;
Packit Service 09cdfc
	if (strcmp(token, "nobrl") == 0 ||
Packit Service 09cdfc
		strcmp(token, "nolock") == 0)
Packit Service 09cdfc
		return OPT_NO_LOCK;
Packit Service 09cdfc
	if (strcmp(token, "mand") == 0)
Packit Service 09cdfc
		return OPT_MAND;
Packit Service 09cdfc
	if (strcmp(token, "nomand") == 0)
Packit Service 09cdfc
		return OPT_NOMAND;
Packit Service 09cdfc
	if (strcmp(token, "dev") == 0)
Packit Service 09cdfc
		return OPT_DEV;
Packit Service 09cdfc
	if (strcmp(token, "noexec") == 0)
Packit Service 09cdfc
		return OPT_NO_EXEC;
Packit Service 09cdfc
	if (strcmp(token, "exec") == 0)
Packit Service 09cdfc
		return OPT_EXEC;
Packit Service 09cdfc
	if (strcmp(token, "guest") == 0)
Packit Service 09cdfc
		return OPT_GUEST;
Packit Service 09cdfc
	if (strcmp(token, "ro") == 0)
Packit Service 09cdfc
		return OPT_RO;
Packit Service 09cdfc
	if (strcmp(token, "rw") == 0)
Packit Service 09cdfc
		return OPT_RW;
Packit Service 09cdfc
	if (strcmp(token, "remount") == 0)
Packit Service 09cdfc
		return OPT_REMOUNT;
Packit Service 09cdfc
	if (strcmp(token, "_netdev") == 0)
Packit Service 09cdfc
		return OPT_IGNORE;
Packit Service 09cdfc
	if (strcmp(token, "backupuid") == 0)
Packit Service 09cdfc
		return OPT_BKUPUID;
Packit Service 09cdfc
	if (strcmp(token, "backupgid") == 0)
Packit Service 09cdfc
		return OPT_BKUPGID;
Packit Service 09cdfc
	if (strcmp(token, "nofail") == 0)
Packit Service 09cdfc
		return OPT_NOFAIL;
Packit Service 09cdfc
	if (strncmp(token, "x-", 2) == 0)
Packit Service 09cdfc
		return OPT_IGNORE;
Packit Service 09cdfc
Packit Service 09cdfc
	return OPT_ERROR;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
parse_options(const char *data, struct parsed_mount_info *parsed_info)
Packit Service 09cdfc
{
Packit Service 09cdfc
	char *value = NULL;
Packit Service 09cdfc
	char *equals = NULL;
Packit Service 09cdfc
	char *next_keyword = NULL;
Packit Service 09cdfc
	char *out = parsed_info->options;
Packit Service 09cdfc
	unsigned long *filesys_flags = &parsed_info->flags;
Packit Service 09cdfc
	int out_len = 0;
Packit Service 09cdfc
	int word_len;
Packit Service 09cdfc
	int rc = 0;
Packit Service 09cdfc
	int got_bkupuid = 0;
Packit Service 09cdfc
	int got_bkupgid = 0;
Packit Service 09cdfc
	int got_uid = 0;
Packit Service 09cdfc
	int got_cruid = 0;
Packit Service 09cdfc
	int got_gid = 0;
Packit Service 09cdfc
	uid_t uid, cruid = 0, bkupuid = 0;
Packit Service 09cdfc
	gid_t gid, bkupgid = 0;
Packit Service 09cdfc
	char *ep;
Packit Service 09cdfc
	struct passwd *pw;
Packit Service 09cdfc
	struct group *gr;
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * max 32-bit uint in decimal is 4294967295 which is 10 chars wide
Packit Service 09cdfc
	 * +1 for NULL, and +1 for good measure
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	char txtbuf[12];
Packit Service 09cdfc
Packit Service 09cdfc
	/* make sure we're starting from beginning */
Packit Service 09cdfc
	out[0] = '\0';
Packit Service 09cdfc
Packit Service 09cdfc
	/* BB fixme check for separator override BB */
Packit Service 09cdfc
	uid = getuid();
Packit Service 09cdfc
	if (uid != 0)
Packit Service 09cdfc
		got_uid = 1;
Packit Service 09cdfc
Packit Service 09cdfc
	gid = getgid();
Packit Service 09cdfc
	if (gid != 0)
Packit Service 09cdfc
		got_gid = 1;
Packit Service 09cdfc
Packit Service 09cdfc
	if (!data)
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * format is keyword,keyword2=value2,keyword3=value3... 
Packit Service 09cdfc
	 * data  = next keyword
Packit Service 09cdfc
	 * value = next value ie stuff after equal sign
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	while (data && *data) {
Packit Service 09cdfc
		next_keyword = strchr(data, ',');	/* BB handle sep= */
Packit Service 09cdfc
Packit Service 09cdfc
		/* temporarily null terminate end of keyword=value pair */
Packit Service 09cdfc
		if (next_keyword)
Packit Service 09cdfc
			*next_keyword++ = 0;
Packit Service 09cdfc
Packit Service 09cdfc
		/* temporarily null terminate keyword if there's a value */
Packit Service 09cdfc
		value = NULL;
Packit Service 09cdfc
		if ((equals = strchr(data, '=')) != NULL) {
Packit Service 09cdfc
			*equals = '\0';
Packit Service 09cdfc
			value = equals + 1;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		switch(parse_opt_token(data)) {
Packit Service 09cdfc
		case OPT_USERS:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				*filesys_flags |= MS_USERS;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			break;
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_USER:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				if (data[4] == '\0') {
Packit Service 09cdfc
					*filesys_flags |= MS_USER;
Packit Service 09cdfc
					goto nocopy;
Packit Service 09cdfc
				} else {
Packit Service 09cdfc
					fprintf(stderr,
Packit Service 09cdfc
						"username specified with no parameter\n");
Packit Service 09cdfc
					return EX_USAGE;
Packit Service 09cdfc
				}
Packit Service 09cdfc
			} else {
Packit Service 09cdfc
				strlcpy(parsed_info->username, value,
Packit Service 09cdfc
					sizeof(parsed_info->username));
Packit Service 09cdfc
				parsed_info->got_user = 1;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_PASS:
Packit Service 09cdfc
			if (parsed_info->got_password) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"password specified twice, ignoring second\n");
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				parsed_info->got_password = 1;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			rc = set_password(parsed_info, value);
Packit Service 09cdfc
			if (rc)
Packit Service 09cdfc
				return rc;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_SEC:
Packit Service 09cdfc
			if (value) {
Packit Service 09cdfc
				if (!strncmp(value, "none", 4) ||
Packit Service 09cdfc
				    !strncmp(value, "krb5", 4))
Packit Service 09cdfc
					parsed_info->got_password = 1;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			break;
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_IP:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"target ip address argument missing\n");
Packit Service 09cdfc
			} else if (strnlen(value, MAX_ADDRESS_LEN) <=
Packit Service 09cdfc
				MAX_ADDRESS_LEN) {
Packit Service 09cdfc
				strcpy(parsed_info->addrlist, value);
Packit Service 09cdfc
				if (parsed_info->verboseflag)
Packit Service 09cdfc
					fprintf(stderr,
Packit Service 09cdfc
						"ip address %s override specified\n",
Packit Service 09cdfc
						value);
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			} else {
Packit Service 09cdfc
				fprintf(stderr, "ip address too long\n");
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
Packit Service 09cdfc
			}
Packit Service 09cdfc
			break;
Packit Service 09cdfc
Packit Service 09cdfc
		/* unc || target || path */
Packit Service 09cdfc
		case OPT_UNC:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"invalid path to network resource\n");
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			rc = parse_unc(value, parsed_info);
Packit Service 09cdfc
			if (rc)
Packit Service 09cdfc
				return rc;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
Packit Service 09cdfc
		/* dom || workgroup */
Packit Service 09cdfc
		case OPT_DOM:
Packit Service 09cdfc
			if (!value) {
Packit Service 09cdfc
				/*
Packit Service 09cdfc
				 * An empty domain has been passed
Packit Service 09cdfc
				 */
Packit Service 09cdfc
				/* not necessary but better safe than.. */
Packit Service 09cdfc
				parsed_info->domain[0] = '\0';
Packit Service 09cdfc
				parsed_info->got_domain = 1;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			if (strnlen(value, sizeof(parsed_info->domain)) >=
Packit Service 09cdfc
			    sizeof(parsed_info->domain)) {
Packit Service 09cdfc
				fprintf(stderr, "domain name too long\n");
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			strlcpy(parsed_info->domain, value,
Packit Service 09cdfc
				sizeof(parsed_info->domain));
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_CRED:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"invalid credential file name specified\n");
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			rc = open_cred_file(value, parsed_info);
Packit Service 09cdfc
			if (rc) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"error %d (%s) opening credential file %s\n",
Packit Service 09cdfc
					rc, strerror(rc), value);
Packit Service 09cdfc
				return rc;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
		case OPT_UID:
Packit Service 09cdfc
			if (!value || !*value)
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			got_uid = 1;
Packit Service 09cdfc
			pw = getpwnam(value);
Packit Service 09cdfc
			if (pw) {
Packit Service 09cdfc
				uid = pw->pw_uid;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			errno = 0;
Packit Service 09cdfc
			uid = strtoul(value, &ep, 10);
Packit Service 09cdfc
			if (errno == 0 && *ep == '\0')
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			fprintf(stderr, "bad option uid=\"%s\"\n", value);
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		case OPT_CRUID:
Packit Service 09cdfc
			if (!value || !*value)
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			got_cruid = 1;
Packit Service 09cdfc
			pw = getpwnam(value);
Packit Service 09cdfc
			if (pw) {
Packit Service 09cdfc
				cruid = pw->pw_uid;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			errno = 0;
Packit Service 09cdfc
			cruid = strtoul(value, &ep, 10);
Packit Service 09cdfc
			if (errno == 0 && *ep == '\0')
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			fprintf(stderr, "bad option: cruid=\"%s\"\n", value);
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		case OPT_GID:
Packit Service 09cdfc
			if (!value || !*value)
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			got_gid = 1;
Packit Service 09cdfc
			gr = getgrnam(value);
Packit Service 09cdfc
			if (gr) {
Packit Service 09cdfc
				gid = gr->gr_gid;
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			errno = 0;
Packit Service 09cdfc
			gid = strtoul(value, &ep, 10);
Packit Service 09cdfc
			if (errno == 0 && *ep == '\0')
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			fprintf(stderr, "bad option: gid=\"%s\"\n", value);
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		/* fmask falls through to file_mode */
Packit Service 09cdfc
		case OPT_FMASK:
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"WARNING: CIFS mount option 'fmask' is\
Packit Service 09cdfc
				 deprecated. Use 'file_mode' instead.\n");
Packit Service 09cdfc
			data = "file_mode";	/* BB fix this */
Packit Service 09cdfc
			/* Fallthrough */
Packit Service 09cdfc
		case OPT_FILE_MODE:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"Option '%s' requires a numerical argument\n",
Packit Service 09cdfc
					data);
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			if (value[0] != '0')
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"WARNING: '%s' not expressed in octal.\n",
Packit Service 09cdfc
					data);
Packit Service 09cdfc
			break;
Packit Service 09cdfc
Packit Service 09cdfc
		/* dmask falls through to dir_mode */
Packit Service 09cdfc
		case OPT_DMASK:
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"WARNING: CIFS mount option 'dmask' is\
Packit Service 09cdfc
				 deprecated. Use 'dir_mode' instead.\n");
Packit Service 09cdfc
			data = "dir_mode";
Packit Service 09cdfc
			/* Fallthrough */
Packit Service 09cdfc
		case OPT_DIR_MODE:
Packit Service 09cdfc
			if (!value || !*value) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"Option '%s' requires a numerical argument\n",
Packit Service 09cdfc
					data);
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			if (value[0] != '0')
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"WARNING: '%s' not expressed in octal.\n",
Packit Service 09cdfc
					data);
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case OPT_NO_SUID:
Packit Service 09cdfc
			*filesys_flags |= MS_NOSUID;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_SUID:
Packit Service 09cdfc
			*filesys_flags &= ~MS_NOSUID;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_NO_DEV:
Packit Service 09cdfc
			*filesys_flags |= MS_NODEV;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_NO_LOCK:
Packit Service 09cdfc
			*filesys_flags &= ~MS_MANDLOCK;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case OPT_MAND:
Packit Service 09cdfc
			*filesys_flags |= MS_MANDLOCK;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_NOMAND:
Packit Service 09cdfc
			*filesys_flags &= ~MS_MANDLOCK;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_DEV:
Packit Service 09cdfc
			*filesys_flags &= ~MS_NODEV;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_NO_EXEC:
Packit Service 09cdfc
			*filesys_flags |= MS_NOEXEC;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_EXEC:
Packit Service 09cdfc
			*filesys_flags &= ~MS_NOEXEC;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_GUEST:
Packit Service 09cdfc
			parsed_info->got_user = 1;
Packit Service 09cdfc
			parsed_info->got_password = 1;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_RO:
Packit Service 09cdfc
			*filesys_flags |= MS_RDONLY;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_RW:
Packit Service 09cdfc
			*filesys_flags &= ~MS_RDONLY;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_REMOUNT:
Packit Service 09cdfc
			*filesys_flags |= MS_REMOUNT;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_IGNORE:
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_BKUPUID:
Packit Service 09cdfc
			if (!value || !*value)
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			got_bkupuid = 1;
Packit Service 09cdfc
			errno = 0;
Packit Service 09cdfc
			bkupuid = strtoul(value, &ep, 10);
Packit Service 09cdfc
			if (errno == 0 && *ep == '\0')
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			pw = getpwnam(value);
Packit Service 09cdfc
			if (pw == NULL) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"bad user name \"%s\"\n", value);
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			bkupuid = pw->pw_uid;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_BKUPGID:
Packit Service 09cdfc
			if (!value || !*value)
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			got_bkupgid = 1;
Packit Service 09cdfc
			errno = 0;
Packit Service 09cdfc
			bkupgid = strtoul(value, &ep, 10);
Packit Service 09cdfc
			if (errno == 0 && *ep == '\0')
Packit Service 09cdfc
				goto nocopy;
Packit Service 09cdfc
Packit Service 09cdfc
			gr = getgrnam(value);
Packit Service 09cdfc
			if (gr == NULL) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"bad group name \"%s\"\n", value);
Packit Service 09cdfc
				return EX_USAGE;
Packit Service 09cdfc
			}
Packit Service 09cdfc
Packit Service 09cdfc
			bkupgid = gr->gr_gid;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		case OPT_NOFAIL:
Packit Service 09cdfc
			parsed_info->nofail = 1;
Packit Service 09cdfc
			goto nocopy;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		/* check size before copying option to buffer */
Packit Service 09cdfc
		word_len = strlen(data);
Packit Service 09cdfc
		if (value)
Packit Service 09cdfc
			word_len += 1 + strlen(value);
Packit Service 09cdfc
Packit Service 09cdfc
		/* need 2 extra bytes for comma and null byte */
Packit Service 09cdfc
		if (out_len + word_len + 2 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		/* put back equals sign, if any */
Packit Service 09cdfc
		if (equals)
Packit Service 09cdfc
			*equals = '=';
Packit Service 09cdfc
Packit Service 09cdfc
		/* go ahead and copy */
Packit Service 09cdfc
		if (out_len)
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
Packit Service 09cdfc
		strlcat(out, data, MAX_OPTIONS_LEN);
Packit Service 09cdfc
		out_len = strlen(out);
Packit Service 09cdfc
nocopy:
Packit Service 09cdfc
		data = next_keyword;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
Packit Service 09cdfc
	/* special-case the uid and gid */
Packit Service 09cdfc
	if (got_uid) {
Packit Service 09cdfc
		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", uid);
Packit Service 09cdfc
Packit Service 09cdfc
		/* comma + "uid=" + terminating NULL == 6 */
Packit Service 09cdfc
		if (out_len + word_len + 6 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (out_len) {
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
			out_len++;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		snprintf(out + out_len, word_len + 5, "uid=%s", txtbuf);
Packit Service 09cdfc
		out_len = strlen(out);
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (got_cruid) {
Packit Service 09cdfc
		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", cruid);
Packit Service 09cdfc
Packit Service 09cdfc
		/* comma + "cruid=" + terminating NULL == 8 */
Packit Service 09cdfc
		if (out_len + word_len + 8 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (out_len) {
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
			out_len++;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		snprintf(out + out_len, word_len + 7, "cruid=%s", txtbuf);
Packit Service 09cdfc
		out_len = strlen(out);
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (got_gid) {
Packit Service 09cdfc
		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", gid);
Packit Service 09cdfc
Packit Service 09cdfc
		/* comma + "gid=" + terminating NULL == 6 */
Packit Service 09cdfc
		if (out_len + word_len + 6 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (out_len) {
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
			out_len++;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		snprintf(out + out_len, word_len + 5, "gid=%s", txtbuf);
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (got_bkupuid) {
Packit Service 09cdfc
		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", bkupuid);
Packit Service 09cdfc
Packit Service 09cdfc
		/* comma + "backupuid=" + terminating NULL == 12 */
Packit Service 09cdfc
		if (out_len + word_len + 12 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (out_len) {
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
			out_len++;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		snprintf(out + out_len, word_len + 11, "backupuid=%s", txtbuf);
Packit Service 09cdfc
		out_len = strlen(out);
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (got_bkupgid) {
Packit Service 09cdfc
		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", bkupgid);
Packit Service 09cdfc
Packit Service 09cdfc
		/* comma + "backkupgid=" + terminating NULL == 12 */
Packit Service 09cdfc
		if (out_len + word_len + 12 > MAX_OPTIONS_LEN) {
Packit Service 09cdfc
			fprintf(stderr, "Options string too long\n");
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (out_len) {
Packit Service 09cdfc
			strlcat(out, ",", MAX_OPTIONS_LEN);
Packit Service 09cdfc
			out_len++;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		snprintf(out + out_len, word_len + 11, "backupgid=%s", txtbuf);
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int parse_unc(const char *unc_name, struct parsed_mount_info *parsed_info)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int length = strnlen(unc_name, MAX_UNC_LEN);
Packit Service 09cdfc
	const char *host, *share, *prepath;
Packit Service 09cdfc
	size_t hostlen, sharelen, prepathlen;
Packit Service 09cdfc
Packit Service 09cdfc
	if (length > (MAX_UNC_LEN - 1)) {
Packit Service 09cdfc
		fprintf(stderr, "mount error: UNC name too long\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (length < 3) {
Packit Service 09cdfc
		fprintf(stderr, "mount error: UNC name too short\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if ((strncasecmp("cifs://", unc_name, 7) == 0) ||
Packit Service 09cdfc
	    (strncasecmp("smb://", unc_name, 6) == 0)) {
Packit Service 09cdfc
		fprintf(stderr,
Packit Service 09cdfc
			"Mounting cifs URL not implemented yet. Attempt to mount %s\n",
Packit Service 09cdfc
			unc_name);
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (strncmp(unc_name, "//", 2) && strncmp(unc_name, "\\\\", 2)) {
Packit Service 09cdfc
		fprintf(stderr, "mount.cifs: bad UNC (%s)\n", unc_name);
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	host = unc_name + 2;
Packit Service 09cdfc
	hostlen = strcspn(host, "/\\");
Packit Service 09cdfc
	if (!hostlen) {
Packit Service 09cdfc
		fprintf(stderr, "mount.cifs: bad UNC (%s)\n", unc_name);
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	share = host + hostlen + 1;
Packit Service 09cdfc
Packit Service 09cdfc
	if (hostlen + 1 > sizeof(parsed_info->host)) {
Packit Service 09cdfc
		fprintf(stderr, "mount.cifs: host portion of UNC too long\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	sharelen = strcspn(share, "/\\");
Packit Service 09cdfc
	if (sharelen + 1 > sizeof(parsed_info->share)) {
Packit Service 09cdfc
		fprintf(stderr, "mount.cifs: share portion of UNC too long\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	prepath = share + sharelen;
Packit Service 09cdfc
	if (*prepath != '\0')
Packit Service 09cdfc
		prepath++;
Packit Service 09cdfc
Packit Service 09cdfc
	prepathlen = strlen(prepath);
Packit Service 09cdfc
Packit Service 09cdfc
	if (prepathlen + 1 > sizeof(parsed_info->prefix)) {
Packit Service 09cdfc
		fprintf(stderr, "mount.cifs: UNC prefixpath too long\n");
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* copy pieces into their resepective buffers */
Packit Service 09cdfc
	memcpy(parsed_info->host, host, hostlen);
Packit Service 09cdfc
	memcpy(parsed_info->share, share, sharelen);
Packit Service 09cdfc
	memcpy(parsed_info->prefix, prepath, prepathlen);
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int get_pw_from_env(struct parsed_mount_info *parsed_info)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc = 0;
Packit Service 09cdfc
Packit Service 09cdfc
	if (getenv("PASSWD"))
Packit Service 09cdfc
		rc = set_password(parsed_info, getenv("PASSWD"));
Packit Service 09cdfc
	else if (getenv("PASSWD_FD"))
Packit Service 09cdfc
		rc = get_password_from_file(atoi(getenv("PASSWD_FD")), NULL,
Packit Service 09cdfc
					    parsed_info);
Packit Service 09cdfc
	else if (getenv("PASSWD_FILE"))
Packit Service 09cdfc
		rc = get_password_from_file(0, getenv("PASSWD_FILE"),
Packit Service 09cdfc
					    parsed_info);
Packit Service 09cdfc
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static struct option longopts[] = {
Packit Service 09cdfc
	{"all", 0, NULL, 'a'},
Packit Service 09cdfc
	{"help", 0, NULL, 'h'},
Packit Service 09cdfc
	{"move", 0, NULL, 'm'},
Packit Service 09cdfc
	{"bind", 0, NULL, 'b'},
Packit Service 09cdfc
	{"read-only", 0, NULL, 'r'},
Packit Service 09cdfc
	{"ro", 0, NULL, 'r'},
Packit Service 09cdfc
	{"verbose", 0, NULL, 'v'},
Packit Service 09cdfc
	{"version", 0, NULL, 'V'},
Packit Service 09cdfc
	{"read-write", 0, NULL, 'w'},
Packit Service 09cdfc
	{"rw", 0, NULL, 'w'},
Packit Service 09cdfc
	{"options", 1, NULL, 'o'},
Packit Service 09cdfc
	{"type", 1, NULL, 't'},
Packit Service 09cdfc
	{"uid", 1, NULL, '1'},
Packit Service 09cdfc
	{"gid", 1, NULL, '2'},
Packit Service 09cdfc
	{"user", 1, NULL, 'u'},
Packit Service 09cdfc
	{"username", 1, NULL, 'u'},
Packit Service 09cdfc
	{"dom", 1, NULL, 'd'},
Packit Service 09cdfc
	{"domain", 1, NULL, 'd'},
Packit Service 09cdfc
	{"password", 1, NULL, 'p'},
Packit Service 09cdfc
	{"pass", 1, NULL, 'p'},
Packit Service 09cdfc
	{"credentials", 1, NULL, 'c'},
Packit Service 09cdfc
	{"port", 1, NULL, 'P'},
Packit Service 09cdfc
	{"sloppy", 0, NULL, 's'},
Packit Service 09cdfc
	{NULL, 0, NULL, 0}
Packit Service 09cdfc
};
Packit Service 09cdfc
Packit Service 09cdfc
/* convert a string to uppercase. return false if the string
Packit Service 09cdfc
 * wasn't ASCII. Return success on a NULL ptr */
Packit Service 09cdfc
static int uppercase_string(char *string)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (!string)
Packit Service 09cdfc
		return 1;
Packit Service 09cdfc
Packit Service 09cdfc
	while (*string) {
Packit Service 09cdfc
		/* check for unicode */
Packit Service 09cdfc
		if ((unsigned char)string[0] & 0x80)
Packit Service 09cdfc
			return 0;
Packit Service 09cdfc
		*string = toupper((unsigned char)*string);
Packit Service 09cdfc
		string++;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	return 1;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static void print_cifs_mount_version(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	printf("mount.cifs version: %s\n", VERSION);
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * This function borrowed from fuse-utils...
Packit Service 09cdfc
 *
Packit Service 09cdfc
 * glibc's addmntent (at least as of 2.10 or so) doesn't properly encode
Packit Service 09cdfc
 * newlines embedded within the text fields. To make sure no one corrupts
Packit Service 09cdfc
 * the mtab, fail the mount if there are embedded newlines.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int check_newline(const char *progname, const char *name)
Packit Service 09cdfc
{
Packit Service 09cdfc
	const char *s;
Packit Service 09cdfc
	for (s = "\n"; *s; s++) {
Packit Service 09cdfc
		if (strchr(name, *s)) {
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"%s: illegal character 0x%02x in mount entry\n",
Packit Service 09cdfc
				progname, *s);
Packit Service 09cdfc
			return EX_USAGE;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int check_mtab(const char *progname, const char *devname,
Packit Service 09cdfc
		      const char *dir)
Packit Service 09cdfc
{
Packit Service 09cdfc
	if (check_newline(progname, devname) || check_newline(progname, dir))
Packit Service 09cdfc
		return EX_USAGE;
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
add_mtab(char *devname, char *mountpoint, unsigned long flags, const char *fstype)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc = 0, tmprc, fd;
Packit Service 09cdfc
	uid_t uid;
Packit Service 09cdfc
	char *mount_user = NULL;
Packit Service 09cdfc
	struct mntent mountent;
Packit Service 09cdfc
	struct stat statbuf;
Packit Service 09cdfc
	FILE *pmntfile;
Packit Service 09cdfc
	sigset_t mask, oldmask;
Packit Service 09cdfc
Packit Service 09cdfc
	uid = getuid();
Packit Service 09cdfc
	if (uid != 0)
Packit Service 09cdfc
		mount_user = getusername(uid);
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * Set the real uid to the effective uid. This prevents unprivileged
Packit Service 09cdfc
	 * users from sending signals to this process, though ^c on controlling
Packit Service 09cdfc
	 * terminal should still work.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	rc = setreuid(geteuid(), -1);
Packit Service 09cdfc
	if (rc != 0) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to set real uid to effective uid: %s\n",
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
		return EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = sigfillset(&mask);
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to set filled signal mask\n");
Packit Service 09cdfc
		return EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = sigprocmask(SIG_SETMASK, &mask, &oldmask);
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to make process ignore signals\n");
Packit Service 09cdfc
		return EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = toggle_dac_capability(1, 1);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return EX_FILEIO;
Packit Service 09cdfc
Packit Service 09cdfc
	atexit(unlock_mtab);
Packit Service 09cdfc
	rc = lock_mtab();
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		fprintf(stderr, "cannot lock mtab");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto add_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	pmntfile = setmntent(MOUNTED, "a+");
Packit Service 09cdfc
	if (!pmntfile) {
Packit Service 09cdfc
		fprintf(stderr, "could not update mount table\n");
Packit Service 09cdfc
		unlock_mtab();
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto add_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	fd = fileno(pmntfile);
Packit Service 09cdfc
	if (fd < 0) {
Packit Service 09cdfc
		fprintf(stderr, "mntent does not appear to be valid\n");
Packit Service 09cdfc
		unlock_mtab();
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto add_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = fstat(fd, &statbuf);
Packit Service 09cdfc
	if (rc != 0) {
Packit Service 09cdfc
		fprintf(stderr, "unable to fstat open mtab\n");
Packit Service 09cdfc
		endmntent(pmntfile);
Packit Service 09cdfc
		unlock_mtab();
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto add_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mountent.mnt_fsname = devname;
Packit Service 09cdfc
	mountent.mnt_dir = mountpoint;
Packit Service 09cdfc
	mountent.mnt_type = (char *)(void *)fstype;
Packit Service 09cdfc
	mountent.mnt_opts = (char *)calloc(MTAB_OPTIONS_LEN, 1);
Packit Service 09cdfc
	if (mountent.mnt_opts) {
Packit Service 09cdfc
		if (flags & MS_RDONLY)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, "ro", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		else
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, "rw", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
Packit Service 09cdfc
		if (flags & MS_MANDLOCK)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",mand", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		if (flags & MS_NOEXEC)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",noexec", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		if (flags & MS_NOSUID)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",nosuid", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		if (flags & MS_NODEV)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",nodev", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		if (flags & MS_SYNCHRONOUS)
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",sync", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		if (mount_user) {
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, ",user=", MTAB_OPTIONS_LEN);
Packit Service 09cdfc
			strlcat(mountent.mnt_opts, mount_user,
Packit Service 09cdfc
				MTAB_OPTIONS_LEN);
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	mountent.mnt_freq = 0;
Packit Service 09cdfc
	mountent.mnt_passno = 0;
Packit Service 09cdfc
	rc = addmntent(pmntfile, &mountent);
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		int ignore __attribute__((unused));
Packit Service 09cdfc
Packit Service 09cdfc
		fprintf(stderr, "unable to add mount entry to mtab\n");
Packit Service 09cdfc
		ignore = ftruncate(fd, statbuf.st_size);
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	tmprc = my_endmntent(pmntfile, statbuf.st_size);
Packit Service 09cdfc
	if (tmprc) {
Packit Service 09cdfc
		fprintf(stderr, "error %d detected on close of mtab\n", tmprc);
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	unlock_mtab();
Packit Service 09cdfc
	free(mountent.mnt_opts);
Packit Service 09cdfc
add_mtab_exit:
Packit Service 09cdfc
	toggle_dac_capability(1, 0);
Packit Service 09cdfc
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
Packit Service 09cdfc
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
del_mtab(char *mountpoint)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int len, tmprc, rc = 0;
Packit Service 09cdfc
	FILE *mnttmp, *mntmtab;
Packit Service 09cdfc
	struct mntent *mountent;
Packit Service 09cdfc
	char *mtabfile, *mtabdir, *mtabtmpfile = NULL;
Packit Service 09cdfc
Packit Service 09cdfc
	mtabfile = strdup(MOUNTED);
Packit Service 09cdfc
	if (!mtabfile) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: cannot strdup MOUNTED\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mtabdir = dirname(mtabfile);
Packit Service 09cdfc
	len = strlen(mtabdir) + strlen(MNT_TMP_FILE);
Packit Service 09cdfc
	mtabtmpfile = malloc(len + 1);
Packit Service 09cdfc
	if (!mtabtmpfile) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: cannot allocate memory to tmp file\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (sprintf(mtabtmpfile, "%s%s", mtabdir, MNT_TMP_FILE) != len) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: error writing new string\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	atexit(unlock_mtab);
Packit Service 09cdfc
	rc = lock_mtab();
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: cannot lock mtab\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mtabtmpfile = mktemp(mtabtmpfile);
Packit Service 09cdfc
	if (!mtabtmpfile) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: cannot setup tmp file destination\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mntmtab = setmntent(MOUNTED, "r");
Packit Service 09cdfc
	if (!mntmtab) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: could not update mount table\n");
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mnttmp = setmntent(mtabtmpfile, "w");
Packit Service 09cdfc
	if (!mnttmp) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: could not update mount table\n");
Packit Service 09cdfc
		endmntent(mntmtab);
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	while ((mountent = getmntent(mntmtab)) != NULL) {
Packit Service 09cdfc
		if (!strcmp(mountent->mnt_dir, mountpoint))
Packit Service 09cdfc
			continue;
Packit Service 09cdfc
		rc = addmntent(mnttmp, mountent);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			fprintf(stderr, "del_mtab: unable to add mount entry to mtab\n");
Packit Service 09cdfc
			rc = EX_FILEIO;
Packit Service 09cdfc
			goto del_mtab_error;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	endmntent(mntmtab);
Packit Service 09cdfc
Packit Service 09cdfc
	tmprc = my_endmntent(mnttmp, 0);
Packit Service 09cdfc
	if (tmprc) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: error %d detected on close of tmp file\n", tmprc);
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_error;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (rename(mtabtmpfile, MOUNTED)) {
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: error %d when renaming mtab in place\n", errno);
Packit Service 09cdfc
		rc = EX_FILEIO;
Packit Service 09cdfc
		goto del_mtab_error;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
del_mtab_exit:
Packit Service 09cdfc
	unlock_mtab();
Packit Service 09cdfc
	free(mtabtmpfile);
Packit Service 09cdfc
	free(mtabfile);
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
Packit Service 09cdfc
del_mtab_error:
Packit Service 09cdfc
	if (unlink(mtabtmpfile))
Packit Service 09cdfc
		fprintf(stderr, "del_mtab: failed to delete tmp file - %s\n",
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
	goto del_mtab_exit;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/* have the child drop root privileges */
Packit Service 09cdfc
static int
Packit Service 09cdfc
drop_child_privs(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc;
Packit Service 09cdfc
	uid_t uid = getuid();
Packit Service 09cdfc
	gid_t gid = getgid();
Packit Service 09cdfc
Packit Service 09cdfc
	if (gid) {
Packit Service 09cdfc
		rc = setgid(gid);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			fprintf(stderr, "Unable set group identity: %s\n",
Packit Service 09cdfc
					strerror(errno));
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
	if (uid) {
Packit Service 09cdfc
		rc = setuid(uid);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			fprintf(stderr, "Unable set user identity: %s\n",
Packit Service 09cdfc
					strerror(errno));
Packit Service 09cdfc
			return EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * If systemd is running and systemd-ask-password --
Packit Service 09cdfc
 * is available, then use that else fallback on getpass(..)
Packit Service 09cdfc
 *
Packit Service 09cdfc
 * Returns: @input or NULL on error
Packit Service 09cdfc
 */
Packit Service 09cdfc
static char*
Packit Service 09cdfc
get_password(const char *prompt, char *input, int capacity)
Packit Service 09cdfc
{
Packit Service 09cdfc
#ifdef ENABLE_SYSTEMD
Packit Service 09cdfc
	int is_systemd_running;
Packit Service 09cdfc
	struct stat a, b;
Packit Service 09cdfc
Packit Service 09cdfc
	/* We simply test whether the systemd cgroup hierarchy is
Packit Service 09cdfc
	 * mounted */
Packit Service 09cdfc
	is_systemd_running = (lstat("/sys/fs/cgroup", &a) == 0)
Packit Service 09cdfc
		&& (lstat("/sys/fs/cgroup/systemd", &b) == 0)
Packit Service 09cdfc
		&& (a.st_dev != b.st_dev);
Packit Service 09cdfc
Packit Service 09cdfc
	if (is_systemd_running) {
Packit Service 09cdfc
		char *cmd, *ret;
Packit Service 09cdfc
		FILE *ask_pass_fp = NULL;
Packit Service 09cdfc
Packit Service 09cdfc
		cmd = ret = NULL;
Packit Service 09cdfc
		if (asprintf(&cmd, "systemd-ask-password \"%s\"", prompt) >= 0) {
Packit Service 09cdfc
			ask_pass_fp = popen (cmd, "re");
Packit Service 09cdfc
			free (cmd);
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (ask_pass_fp) {
Packit Service 09cdfc
			ret = fgets(input, capacity, ask_pass_fp);
Packit Service 09cdfc
			pclose(ask_pass_fp);
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		if (ret) {
Packit Service 09cdfc
			int len = strlen(input);
Packit Service 09cdfc
			if (input[len - 1] == '\n')
Packit Service 09cdfc
				input[len - 1] = '\0';
Packit Service 09cdfc
			return input;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
#endif
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * Falling back to getpass(..)
Packit Service 09cdfc
	 * getpass is obsolete, but there's apparently nothing that replaces it
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	char *tmp_pass = getpass(prompt);
Packit Service 09cdfc
	if (!tmp_pass)
Packit Service 09cdfc
		return NULL;
Packit Service 09cdfc
Packit Service 09cdfc
	strncpy(input, tmp_pass, capacity - 1);
Packit Service 09cdfc
	input[capacity - 1] = '\0';
Packit Service 09cdfc
Packit Service 09cdfc
	/* zero-out the static buffer */
Packit Service 09cdfc
	memset(tmp_pass, 0, strlen(tmp_pass));
Packit Service 09cdfc
Packit Service 09cdfc
	return input;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
assemble_mountinfo(struct parsed_mount_info *parsed_info,
Packit Service 09cdfc
		   const char *thisprogram, const char *mountpoint,
Packit Service 09cdfc
		   const char *orig_dev, char *orgoptions)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = drop_capabilities(0);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = drop_child_privs();
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	if (getuid()) {
Packit Service 09cdfc
		rc = check_fstab(thisprogram, mountpoint, orig_dev,
Packit Service 09cdfc
				 &orgoptions);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
		/* enable any default user mount flags */
Packit Service 09cdfc
		parsed_info->flags |= CIFS_SETUID_FLAGS;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = get_pw_from_env(parsed_info);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	if (orgoptions) {
Packit Service 09cdfc
		rc = parse_options(orgoptions, parsed_info);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			goto assemble_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (getuid()) {
Packit Service 09cdfc
		if (!(parsed_info->flags & (MS_USERS | MS_USER))) {
Packit Service 09cdfc
			fprintf(stderr, "%s: permission denied\n", thisprogram);
Packit Service 09cdfc
			rc = EX_USAGE;
Packit Service 09cdfc
			goto assemble_exit;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	parsed_info->flags &= ~(MS_USERS | MS_USER);
Packit Service 09cdfc
Packit Service 09cdfc
	rc = parse_unc(orig_dev, parsed_info);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	if (parsed_info->addrlist[0] == '\0')
Packit Service 09cdfc
		rc = resolve_host(parsed_info->host, parsed_info->addrlist);
Packit Service 09cdfc
Packit Service 09cdfc
	switch (rc) {
Packit Service 09cdfc
	case EX_USAGE:
Packit Service 09cdfc
		fprintf(stderr, "mount error: could not resolve address for "
Packit Service 09cdfc
			"%s: %s\n", parsed_info->host,
Packit Service 09cdfc
			rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	case EX_SYSERR:
Packit Service 09cdfc
		fprintf(stderr, "mount error: problem parsing address "
Packit Service 09cdfc
			"list: %s\n", strerror(errno));
Packit Service 09cdfc
		goto assemble_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (!parsed_info->got_user) {
Packit Service 09cdfc
		/*
Packit Service 09cdfc
		 * Note that the password will not be retrieved from the
Packit Service 09cdfc
		 * USER env variable (ie user%password form) as there is
Packit Service 09cdfc
		 * already a PASSWD environment varaible
Packit Service 09cdfc
		 */
Packit Service 09cdfc
		if (getenv("USER"))
Packit Service 09cdfc
			strlcpy(parsed_info->username, getenv("USER"),
Packit Service 09cdfc
				sizeof(parsed_info->username));
Packit Service 09cdfc
		else
Packit Service 09cdfc
			strlcpy(parsed_info->username, getusername(getuid()),
Packit Service 09cdfc
				sizeof(parsed_info->username));
Packit Service 09cdfc
		parsed_info->got_user = 1;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (!parsed_info->got_password) {
Packit Service 09cdfc
		char tmp_pass[MOUNT_PASSWD_SIZE + 1];
Packit Service 09cdfc
		char *prompt = NULL;
Packit Service 09cdfc
Packit Service 09cdfc
		if(asprintf(&prompt, "Password for %s@%s: ", parsed_info->username, orig_dev) < 0)
Packit Service 09cdfc
			prompt = NULL;
Packit Service 09cdfc
Packit Service 09cdfc
		if (get_password(prompt ? prompt : "Password: ", tmp_pass, MOUNT_PASSWD_SIZE + 1)) {
Packit Service 09cdfc
			rc = set_password(parsed_info, tmp_pass);
Packit Service 09cdfc
		} else {
Packit Service 09cdfc
			fprintf(stderr, "Error reading password, exiting\n");
Packit Service 09cdfc
			rc = EX_SYSERR;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		free(prompt);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			goto assemble_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* copy in user= string */
Packit Service 09cdfc
	if (parsed_info->got_user) {
Packit Service 09cdfc
		if (*parsed_info->options)
Packit Service 09cdfc
			strlcat(parsed_info->options, ",",
Packit Service 09cdfc
				sizeof(parsed_info->options));
Packit Service 09cdfc
		strlcat(parsed_info->options, "user=",
Packit Service 09cdfc
			sizeof(parsed_info->options));
Packit Service 09cdfc
		strlcat(parsed_info->options, parsed_info->username,
Packit Service 09cdfc
			sizeof(parsed_info->options));
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (*parsed_info->domain) {
Packit Service 09cdfc
		if (*parsed_info->options)
Packit Service 09cdfc
			strlcat(parsed_info->options, ",",
Packit Service 09cdfc
				sizeof(parsed_info->options));
Packit Service 09cdfc
		strlcat(parsed_info->options, "domain=",
Packit Service 09cdfc
			sizeof(parsed_info->options));
Packit Service 09cdfc
		strlcat(parsed_info->options, parsed_info->domain,
Packit Service 09cdfc
			sizeof(parsed_info->options));
Packit Service 09cdfc
	} else if (parsed_info->got_domain) {
Packit Service 09cdfc
		strlcat(parsed_info->options, ",domain=",
Packit Service 09cdfc
			sizeof(parsed_info->options));
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
assemble_exit:
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * chdir() into the mountpoint and determine "realpath". We assume here that
Packit Service 09cdfc
 * "mountpoint" is a statically allocated string and does not need to be freed.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int
Packit Service 09cdfc
acquire_mountpoint(char **mountpointp)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc, dacrc;
Packit Service 09cdfc
	uid_t realuid, oldfsuid;
Packit Service 09cdfc
	gid_t oldfsgid;
Packit Service 09cdfc
	char *mountpoint;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * Acquire the necessary privileges to chdir to the mountpoint. If
Packit Service 09cdfc
	 * the real uid is root, then we reacquire CAP_DAC_READ_SEARCH. If
Packit Service 09cdfc
	 * it's not, then we change the fsuid to the real uid to ensure that
Packit Service 09cdfc
	 * the mounting user actually has access to the mountpoint.
Packit Service 09cdfc
	 *
Packit Service 09cdfc
	 * The mount(8) manpage does not state that users must be able to
Packit Service 09cdfc
	 * chdir into the mountpoint in order to mount onto it, but if we
Packit Service 09cdfc
	 * allow that, then an unprivileged user could use this program to
Packit Service 09cdfc
	 * "probe" into directories to which he does not have access.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	realuid = getuid();
Packit Service 09cdfc
	if (realuid == 0) {
Packit Service 09cdfc
		dacrc = toggle_dac_capability(0, 1);
Packit Service 09cdfc
		if (dacrc)
Packit Service 09cdfc
			return dacrc;
Packit Service 09cdfc
	} else {
Packit Service 09cdfc
		oldfsuid = setfsuid(realuid);
Packit Service 09cdfc
		oldfsgid = setfsgid(getgid());
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = chdir(*mountpointp);
Packit Service 09cdfc
	if (rc) {
Packit Service 09cdfc
		fprintf(stderr, "Couldn't chdir to %s: %s\n", *mountpointp,
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		rc = EX_USAGE;
Packit Service 09cdfc
		goto restore_privs;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	mountpoint = realpath(".", NULL);
Packit Service 09cdfc
	if (!mountpoint) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to resolve %s to canonical path: %s\n",
Packit Service 09cdfc
			*mountpointp, strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	*mountpointp = mountpoint;
Packit Service 09cdfc
restore_privs:
Packit Service 09cdfc
	if (realuid == 0) {
Packit Service 09cdfc
		dacrc = toggle_dac_capability(0, 0);
Packit Service 09cdfc
		if (dacrc)
Packit Service 09cdfc
			rc = rc ? rc : dacrc;
Packit Service 09cdfc
	} else {
Packit Service 09cdfc
		uid_t __attribute__((unused)) uignore = setfsuid(oldfsuid);
Packit Service 09cdfc
		gid_t __attribute__((unused)) gignore = setfsgid(oldfsgid);
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
int main(int argc, char **argv)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int c;
Packit Service 09cdfc
	char *orgoptions = NULL;
Packit Service 09cdfc
	char *mountpoint = NULL;
Packit Service 09cdfc
	char *options = NULL;
Packit Service 09cdfc
	char *orig_dev = NULL;
Packit Service 09cdfc
	char *currentaddress, *nextaddress;
Packit Service 09cdfc
	int rc = 0;
Packit Service 09cdfc
	int already_uppercased = 0;
Packit Service 09cdfc
	int sloppy = 0;
Packit Service 09cdfc
	size_t options_size = MAX_OPTIONS_LEN;
Packit Service 09cdfc
	struct parsed_mount_info *parsed_info = NULL;
Packit Service 09cdfc
	pid_t pid;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = check_setuid();
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
Packit Service 09cdfc
	rc = drop_capabilities(1);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
Packit Service 09cdfc
	/* setlocale(LC_ALL, "");
Packit Service 09cdfc
	   bindtextdomain(PACKAGE, LOCALEDIR);
Packit Service 09cdfc
	   textdomain(PACKAGE); */
Packit Service 09cdfc
Packit Service 09cdfc
	if (!argc || !argv) {
Packit Service 09cdfc
		rc = mount_usage(stderr);
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	thisprogram = basename(argv[0]);
Packit Service 09cdfc
	if (thisprogram == NULL)
Packit Service 09cdfc
		thisprogram = "mount.cifs";
Packit Service 09cdfc
Packit Service 09cdfc
	/* allocate parsed_info as shared anonymous memory range */
Packit Service 09cdfc
	parsed_info = mmap((void *)0, sizeof(*parsed_info), PROT_READ | PROT_WRITE,
Packit Service 09cdfc
			   MAP_ANONYMOUS | MAP_SHARED, -1, 0);
Packit Service 09cdfc
	if (parsed_info == (struct parsed_mount_info *) -1) {
Packit Service 09cdfc
		parsed_info = NULL;
Packit Service 09cdfc
		fprintf(stderr, "Unable to allocate memory: %s\n",
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
		return EX_SYSERR;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* add sharename in opts string as unc= parm */
Packit Service 09cdfc
	while ((c = getopt_long(argc, argv, "?fhno:rsvVw",
Packit Service 09cdfc
				longopts, NULL)) != -1) {
Packit Service 09cdfc
		switch (c) {
Packit Service 09cdfc
		case '?':
Packit Service 09cdfc
		case 'h':	/* help */
Packit Service 09cdfc
			rc = mount_usage(stdout);
Packit Service 09cdfc
			goto mount_exit;
Packit Service 09cdfc
		case 'n':
Packit Service 09cdfc
			++parsed_info->nomtab;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'o':
Packit Service 09cdfc
			orgoptions = strndup(optarg, MAX_OPTIONS_LEN);
Packit Service 09cdfc
			if (!orgoptions) {
Packit Service 09cdfc
				rc = EX_SYSERR;
Packit Service 09cdfc
				goto mount_exit;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'r':	/* mount readonly */
Packit Service 09cdfc
			parsed_info->flags |= MS_RDONLY;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'v':
Packit Service 09cdfc
			++parsed_info->verboseflag;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'V':
Packit Service 09cdfc
			print_cifs_mount_version();
Packit Service 09cdfc
			exit(0);
Packit Service 09cdfc
		case 'w':
Packit Service 09cdfc
			parsed_info->flags &= ~MS_RDONLY;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'f':
Packit Service 09cdfc
			++parsed_info->fakemnt;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 's':
Packit Service 09cdfc
			++sloppy;
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		default:
Packit Service 09cdfc
			fprintf(stderr, "unknown command-line option: %c\n", c);
Packit Service 09cdfc
			rc = mount_usage(stderr);
Packit Service 09cdfc
			goto mount_exit;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (argc < optind + 2) {
Packit Service 09cdfc
		rc = mount_usage(stderr);
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	orig_dev = argv[optind];
Packit Service 09cdfc
	mountpoint = argv[optind + 1];
Packit Service 09cdfc
Packit Service 09cdfc
	/* chdir into mountpoint as soon as possible */
Packit Service 09cdfc
	rc = acquire_mountpoint(&mountpoint);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * mount.cifs does privilege separation. Most of the code to handle
Packit Service 09cdfc
	 * assembling the mount info is done in a child process that drops
Packit Service 09cdfc
	 * privileges. The info is assembled in parsed_info which is a
Packit Service 09cdfc
	 * shared, mmaped memory segment. The parent waits for the child to
Packit Service 09cdfc
	 * exit and checks the return code. If it's anything but "0", then
Packit Service 09cdfc
	 * the process exits without attempting anything further.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	pid = fork();
Packit Service 09cdfc
	if (pid == -1) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to fork: %s\n", strerror(errno));
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	} else if (!pid) {
Packit Service 09cdfc
		/* child */
Packit Service 09cdfc
		rc = assemble_mountinfo(parsed_info, thisprogram, mountpoint,
Packit Service 09cdfc
					orig_dev, orgoptions);
Packit Service 09cdfc
		return rc;
Packit Service 09cdfc
	} else {
Packit Service 09cdfc
		/* parent */
Packit Service 09cdfc
		pid = wait(&rc);
Packit Service 09cdfc
		if (!WIFEXITED(rc)) {
Packit Service 09cdfc
			fprintf(stderr, "Child process terminated abnormally.\n");
Packit Service 09cdfc
			rc = EX_SYSERR;
Packit Service 09cdfc
			goto mount_exit;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		rc = WEXITSTATUS(rc);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	options = calloc(options_size, 1);
Packit Service 09cdfc
	if (!options) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to allocate memory.\n");
Packit Service 09cdfc
		rc = EX_SYSERR;
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	currentaddress = parsed_info->addrlist;
Packit Service 09cdfc
	nextaddress = strchr(currentaddress, ',');
Packit Service 09cdfc
	if (nextaddress)
Packit Service 09cdfc
		*nextaddress++ = '\0';
Packit Service 09cdfc
Packit Service 09cdfc
mount_retry:
Packit Service 09cdfc
	if (!currentaddress) {
Packit Service 09cdfc
		fprintf(stderr, "Unable to find suitable address.\n");
Packit Service 09cdfc
		rc = parsed_info->nofail ? 0 : EX_FAIL;
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
	strlcpy(options, "ip=", options_size);
Packit Service 09cdfc
	strlcat(options, currentaddress, options_size);
Packit Service 09cdfc
Packit Service 09cdfc
	strlcat(options, ",unc=\\\\", options_size);
Packit Service 09cdfc
	strlcat(options, parsed_info->host, options_size);
Packit Service 09cdfc
	strlcat(options, "\\", options_size);
Packit Service 09cdfc
	strlcat(options, parsed_info->share, options_size);
Packit Service 09cdfc
Packit Service 09cdfc
	if (*parsed_info->options) {
Packit Service 09cdfc
		strlcat(options, ",", options_size);
Packit Service 09cdfc
		strlcat(options, parsed_info->options, options_size);
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (*parsed_info->prefix) {
Packit Service 09cdfc
		strlcat(options, ",prefixpath=", options_size);
Packit Service 09cdfc
		strlcat(options, parsed_info->prefix, options_size);
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (sloppy)
Packit Service 09cdfc
		strlcat(options, ",sloppy", options_size);
Packit Service 09cdfc
Packit Service 09cdfc
	if (parsed_info->verboseflag)
Packit Service 09cdfc
		fprintf(stderr, "%s kernel mount options: %s",
Packit Service 09cdfc
			thisprogram, options);
Packit Service 09cdfc
Packit Service 09cdfc
	if (parsed_info->got_password) {
Packit Service 09cdfc
		/*
Packit Service 09cdfc
		 * Commas have to be doubled, or else they will
Packit Service 09cdfc
		 * look like the parameter separator
Packit Service 09cdfc
		 */
Packit Service 09cdfc
		strlcat(options, ",pass=", options_size);
Packit Service 09cdfc
		strlcat(options, parsed_info->password, options_size);
Packit Service 09cdfc
		if (parsed_info->verboseflag)
Packit Service 09cdfc
			fprintf(stderr, ",pass=********");
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (parsed_info->verboseflag)
Packit Service 09cdfc
		fprintf(stderr, "\n");
Packit Service 09cdfc
Packit Service 09cdfc
	rc = check_mtab(thisprogram, orig_dev, mountpoint);
Packit Service 09cdfc
	if (rc)
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
Packit Service 09cdfc
	if (!parsed_info->fakemnt) {
Packit Service 09cdfc
		toggle_dac_capability(0, 1);
Packit Service 09cdfc
		rc = mount(orig_dev, ".", cifs_fstype, parsed_info->flags, options);
Packit Service 09cdfc
		toggle_dac_capability(0, 0);
Packit Service 09cdfc
		if (rc == 0)
Packit Service 09cdfc
			goto do_mtab;
Packit Service 09cdfc
Packit Service 09cdfc
		switch (errno) {
Packit Service 09cdfc
		case ECONNREFUSED:
Packit Service 09cdfc
		case EHOSTUNREACH:
Packit Service 0fa287
			if (currentaddress) {
Packit Service 0fa287
				fprintf(stderr, "mount error(%d): could not connect to %s",
Packit Service 0fa287
					errno, currentaddress);
Packit Service 0fa287
			}
Packit Service 09cdfc
			currentaddress = nextaddress;
Packit Service 09cdfc
			if (currentaddress) {
Packit Service 09cdfc
				nextaddress = strchr(currentaddress, ',');
Packit Service 09cdfc
				if (nextaddress)
Packit Service 09cdfc
					*nextaddress++ = '\0';
Packit Service 09cdfc
			}
Packit Service 09cdfc
			goto mount_retry;
Packit Service 09cdfc
		case ENODEV:
Packit Service 09cdfc
			fprintf(stderr,
Packit Service 09cdfc
				"mount error: %s filesystem not supported by the system\n", cifs_fstype);
Packit Service 09cdfc
			break;
Packit Service 0fa287
		case EHOSTDOWN:
Packit Service 0fa287
			fprintf(stderr,
Packit Service 0fa287
				"mount error: Server abruptly closed the connection.\n"
Packit Service 0fa287
				"This can happen if the server does not support the SMB version you are trying to use.\n"
Packit Service 0fa287
				"The default SMB version recently changed from SMB1 to SMB2.1 and above. Try mounting with vers=1.0.\n");
Packit Service 0fa287
			break;
Packit Service 09cdfc
		case ENXIO:
Packit Service 09cdfc
			if (!already_uppercased &&
Packit Service 09cdfc
			    uppercase_string(parsed_info->host) &&
Packit Service 09cdfc
			    uppercase_string(parsed_info->share) &&
Packit Service 09cdfc
			    uppercase_string(parsed_info->prefix) &&
Packit Service 09cdfc
			    uppercase_string(orig_dev)) {
Packit Service 09cdfc
				fprintf(stderr,
Packit Service 09cdfc
					"Retrying with upper case share name\n");
Packit Service 09cdfc
				already_uppercased = 1;
Packit Service 09cdfc
				goto mount_retry;
Packit Service 09cdfc
			}
Packit Service 09cdfc
		}
Packit Service 09cdfc
		fprintf(stderr, "mount error(%d): %s\n", errno,
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		fprintf(stderr,
Packit Service 09cdfc
			"Refer to the %s(8) manual page (e.g. man "
Packit Service 0fa287
			"%s) and kernel log messages (dmesg)\n", thisprogram, thisprogram);
Packit Service 09cdfc
		rc = EX_FAIL;
Packit Service 09cdfc
		goto mount_exit;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
do_mtab:
Packit Service 09cdfc
	if (!parsed_info->nomtab && !mtab_unusable()) {
Packit Service 09cdfc
		if (parsed_info->flags & MS_REMOUNT) {
Packit Service 09cdfc
			rc = del_mtab(mountpoint);
Packit Service 09cdfc
			if (rc)
Packit Service 09cdfc
				goto mount_exit;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = add_mtab(orig_dev, mountpoint, parsed_info->flags, cifs_fstype);
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
mount_exit:
Packit Service 09cdfc
	if (parsed_info) {
Packit Service 09cdfc
		memset(parsed_info->password, 0, sizeof(parsed_info->password));
Packit Service 09cdfc
		munmap(parsed_info, sizeof(*parsed_info));
Packit Service 09cdfc
	}
Packit Service 09cdfc
	free(options);
Packit Service 09cdfc
	free(orgoptions);
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}