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