diff options
author | Shyam Prasad N <sprasad@microsoft.com> | 2020-09-16 00:18:44 -0700 |
---|---|---|
committer | Pavel Shilovsky <pshilov@microsoft.com> | 2020-12-16 15:51:27 -0800 |
commit | 1a1507654c5f4367c27a11dfdbcfea42110c670c (patch) | |
tree | cd30cd33ad9b99d6cd870816fa4a8d0862c1b4b0 /mount.cifs.c | |
parent | 7156c6eca0fcf3d4a2fd2f8677b2622475c5c46e (diff) | |
download | cifs-utils-1a1507654c5f4367c27a11dfdbcfea42110c670c.tar.gz cifs-utils-1a1507654c5f4367c27a11dfdbcfea42110c670c.tar.bz2 cifs-utils-1a1507654c5f4367c27a11dfdbcfea42110c670c.zip |
mount.cifs: use SUDO_UID env variable for cruid
In the current mount.cifs logic, when sudo is used for mount,
uid=0, so the mount command searches for cruid=0 unless explicitly
specified by the user. The user may already have cred cache populated
but mount.cifs would end up searching cred cache for uid=0.
mount.cifs can avoid this confusion by reading the cruid from SUDO_UID
environment variable. If it is set to non-zero, we can make cruid=$SUDO_UID.
However, to maintain backward compatibility, keeping this as a fallback option.
If mount fails with ENOKEY, then retry with this option.
To enable this fallback, I had to make a few minor changes in the flow.
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
Diffstat (limited to 'mount.cifs.c')
-rw-r--r-- | mount.cifs.c | 83 |
1 files changed, 67 insertions, 16 deletions
diff --git a/mount.cifs.c b/mount.cifs.c index 7c949cf..7f898bb 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -171,7 +171,11 @@ #define NTFS_TIME_OFFSET ((unsigned long long)(369*365 + 89) * 24 * 3600 * 10000000) -/* struct for holding parsed mount info for use by privileged process */ +/* +* struct for holding parsed mount info for use by privileged process. +* Please do not keep pointers in this struct. +* That way, reinit of this struct is a simple memset. +*/ struct parsed_mount_info { unsigned long flags; char host[NI_MAXHOST + 1]; @@ -189,6 +193,8 @@ struct parsed_mount_info { unsigned int verboseflag:1; unsigned int nofail:1; unsigned int got_domain:1; + unsigned int is_krb5:1; + uid_t sudo_uid; }; static const char *thisprogram; @@ -907,9 +913,12 @@ parse_options(const char *data, struct parsed_mount_info *parsed_info) case OPT_SEC: if (value) { - if (!strncmp(value, "none", 4) || - !strncmp(value, "krb5", 4)) + if (!strncmp(value, "none", 4)) + parsed_info->got_password = 1; + if (!strncmp(value, "krb5", 4)) { + parsed_info->is_krb5 = 1; parsed_info->got_password = 1; + } } break; @@ -1215,6 +1224,10 @@ nocopy: snprintf(out + out_len, word_len + 5, "uid=%s", txtbuf); out_len = strlen(out); } + if (parsed_info->is_krb5 && parsed_info->sudo_uid) { + cruid = parsed_info->sudo_uid; + got_cruid = 1; + } if (got_cruid) { word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", cruid); @@ -2031,12 +2044,17 @@ int main(int argc, char **argv) char *options = NULL; char *orig_dev = NULL; char *currentaddress, *nextaddress; + char *value = NULL; + char *ep = NULL; int rc = 0; int already_uppercased = 0; int sloppy = 0; + int fallback_sudo_uid = 0; size_t options_size = MAX_OPTIONS_LEN; struct parsed_mount_info *parsed_info = NULL; + struct parsed_mount_info *reinit_parsed_info = NULL; pid_t pid; + uid_t sudo_uid = 0; rc = check_setuid(); if (rc) @@ -2072,7 +2090,23 @@ int main(int argc, char **argv) parsed_info = NULL; fprintf(stderr, "Unable to allocate memory: %s\n", strerror(errno)); - return EX_SYSERR; + rc = EX_SYSERR; + goto mount_exit; + } + + reinit_parsed_info = malloc(sizeof(*reinit_parsed_info)); + if (reinit_parsed_info == NULL) { + fprintf(stderr, "Unable to allocate memory: %s\n", + strerror(errno)); + rc = EX_SYSERR; + goto mount_exit; + } + + options = calloc(options_size, 1); + if (!options) { + fprintf(stderr, "Unable to allocate memory.\n"); + rc = EX_SYSERR; + goto mount_exit; } /* add sharename in opts string as unc= parm */ @@ -2129,10 +2163,13 @@ int main(int argc, char **argv) /* chdir into mountpoint as soon as possible */ rc = acquire_mountpoint(&mountpoint); if (rc) { - free(orgoptions); - return rc; + goto mount_exit; } + /* Before goto assemble_retry, reinitialize parsed_info with reinit_parsed_info */ + memcpy(reinit_parsed_info, parsed_info, sizeof(*reinit_parsed_info)); + +assemble_retry: /* * mount.cifs does privilege separation. Most of the code to handle * assembling the mount info is done in a child process that drops @@ -2150,9 +2187,7 @@ int main(int argc, char **argv) /* child */ rc = assemble_mountinfo(parsed_info, thisprogram, mountpoint, orig_dev, orgoptions); - free(orgoptions); - free(mountpoint); - return rc; + goto mount_child_exit; } else { /* parent */ pid = wait(&rc); @@ -2166,19 +2201,13 @@ int main(int argc, char **argv) goto mount_exit; } - options = calloc(options_size, 1); - if (!options) { - fprintf(stderr, "Unable to allocate memory.\n"); - rc = EX_SYSERR; - goto mount_exit; - } - currentaddress = parsed_info->addrlist; nextaddress = strchr(currentaddress, ','); if (nextaddress) *nextaddress++ = '\0'; mount_retry: + options[0] = '\0'; if (!currentaddress) { fprintf(stderr, "Unable to find suitable address.\n"); rc = parsed_info->nofail ? 0 : EX_FAIL; @@ -2269,6 +2298,24 @@ mount_retry: already_uppercased = 1; goto mount_retry; } + break; + case ENOKEY: + if (!fallback_sudo_uid && parsed_info->is_krb5) { + /* mount could have failed because cruid option was not passed when triggered with sudo */ + value = getenv("SUDO_UID"); + if (value) { + errno = 0; + sudo_uid = strtoul(value, &ep, 10); + if (errno == 0 && *ep == '\0' && sudo_uid) { + /* Reinitialize parsed_info and assemble options again with sudo_uid */ + memcpy(parsed_info, reinit_parsed_info, sizeof(*parsed_info)); + parsed_info->sudo_uid = sudo_uid; + fallback_sudo_uid = 1; + goto assemble_retry; + } + } + } + break; } fprintf(stderr, "mount error(%d): %s\n", errno, strerror(errno)); @@ -2295,6 +2342,10 @@ mount_exit: memset(parsed_info->password, 0, sizeof(parsed_info->password)); munmap(parsed_info, sizeof(*parsed_info)); } + +mount_child_exit: + /* Objects to be freed both in main process and child */ + free(reinit_parsed_info); free(options); free(orgoptions); free(mountpoint); |