diff options
author | Kevin Pulo <kevin.pulo@mongodb.com> | 2017-04-28 05:43:36 +0000 |
---|---|---|
committer | Kevin Pulo <kevin.pulo@mongodb.com> | 2017-05-03 11:24:43 +1000 |
commit | e6b5935caccd012bccef945b4df82149a5a9957c (patch) | |
tree | 13104cac27144207b70cc56856fe126fe04d9039 | |
parent | c5353005e1b088851f30342b0f40377c54021a89 (diff) | |
download | mongo-e6b5935caccd012bccef945b4df82149a5a9957c.tar.gz |
SERVER-25335 SERVER-26489 avoid group and other permissions when creating .dbshell history file
Cherry-picked from:
* 035cf2afc04988b22cb67f4ebfd77e9b344cb6e0
* f2c3376d70a3540d3bee5e32abe9d5517f571369
* 4a431ceb4cb1d986ceb54ee26ca86915ef9ffd42
With additional adjustments to handle the inability to pass environment
variables to runProgram().
-rw-r--r-- | jstests/noPassthrough/shell_history.js | 126 | ||||
-rw-r--r-- | src/mongo/shell/linenoise.cpp | 14 |
2 files changed, 138 insertions, 2 deletions
diff --git a/jstests/noPassthrough/shell_history.js b/jstests/noPassthrough/shell_history.js new file mode 100644 index 00000000000..ac760201e62 --- /dev/null +++ b/jstests/noPassthrough/shell_history.js @@ -0,0 +1,126 @@ +// Test that when running the shell for the first time creates the ~/.dbshell file, and it has +// appropriate permissions (where relevant). + +(function() { + "use strict"; + + // Use dataPath because it includes the trailing "/" or "\". + var tmpHome = MongoRunner.dataPath; + // Ensure it exists and is a dir (eg. if running without resmoke.py and /data/db doesn't exist). + mkdir(tmpHome); + removeFile(tmpHome + ".dbshell"); + + var args = []; + var cmdline = "mongo --nodb"; + var redirection = ""; + var env = {}; + if (_isWindows()) { + args.push("cmd.exe"); + args.push("/c"); + + // Input is set to NUL. The output must also be redirected to NUL, otherwise running the + // jstest manually has strange terminal IO behaviour. + redirection = "< NUL > NUL"; + + // USERPROFILE set to the tmp homedir. + // Since NUL is a character device, isatty() will return true, which means that .mongorc.js + // will be created in the HOMEDRIVE + HOMEPATH location, so we must set them also. + if (tmpHome.match("^[a-zA-Z]:")) { + var tmpHomeDrive = tmpHome.substr(0, 2); + var tmpHomePath = tmpHome.substr(2); + } else { + var _pwd = pwd(); + assert(_pwd.match("^[a-zA-Z]:"), "pwd must include drive"); + var tmpHomeDrive = _pwd.substr(0, 2); + var tmpHomePath = tmpHome; + } + env = { + USERPROFILE: tmpHome, + HOMEDRIVE: tmpHomeDrive, + HOMEPATH: tmpHomePath + }; + + } else { + args.push("sh"); + args.push("-c"); + + // Use the mongo shell from the current dir, same as resmoke.py does. + // Doesn't handle resmoke's --mongo= option. + cmdline = "./" + cmdline; + + // Set umask to 0 prior to running the shell. + cmdline = "umask 0 ; " + cmdline; + + // stdin is /dev/null. + redirection = "< /dev/null"; + + // HOME set to the tmp homedir. + if (!tmpHome.startsWith("/")) { + tmpHome = pwd() + "/" + tmpHome; + } + env = { + HOME: tmpHome + }; + } + + // Workaround for SERVER-18877 not being fixed in earlier versions. + if (_isWindows()) { + for (var envvar in env) { + cmdline = "set " + envvar + "=" + env[envvar] + "&&" + cmdline; + } + } else { + for (var envvar in env) { + cmdline = envvar + "='" + env[envvar] + "' ; " + cmdline; + } + } + + // Add redirection to cmdline, and add cmdline to args. + cmdline += " " + redirection; + args.push(cmdline); + jsTestLog("Running args:\n " + tojson(args) + "\nwith env:\n " + tojson(env)); + var rc = runProgram.apply(this, args); + + assert.eq(rc, 0); + + var files = listFiles(tmpHome); + jsTestLog(tojson(files)); + + var findFile = function(baseName) { + for (var i = 0; i < files.length; i++) { + if (files[i].baseName === baseName) { + return files[i]; + } + } + return undefined; + }; + + var targetFile = ".dbshell"; + var file = findFile(targetFile); + + assert.neq(typeof(file), "undefined", targetFile + " should exist, but it doesn't"); + assert.eq(file.isDirectory, false, targetFile + " should not be a directory, but it is"); + assert.eq(file.size, 0, targetFile + " should be empty, but it isn't"); + + if (!_isWindows()) { + // On Unix, check that the file has the correct mode (permissions). + // The shell has no way to stat a file. + // There is no stat utility in POSIX. + // `ls -l` is POSIX, so this is the best that we have. + // Check for exactly "-rw-------". + clearRawMongoProgramOutput(); + var rc = runProgram("ls", "-l", file.name); + assert.eq(rc, 0); + // Before SERVER-22992 is fixed: + var output = null; + assert.soon(function() { + output = rawMongoProgramOutput(); + return output != ""; + }); + // After SERVER-22992 is fixed: + // var output = rawMongoProgramOutput(); + var fields = output.split(" "); + // First field is the prefix, second field is the `ls -l` permissions. + assert.eq(fields[1], "-rw-------", targetFile + " has bad permissions"); + } + +})(); diff --git a/src/mongo/shell/linenoise.cpp b/src/mongo/shell/linenoise.cpp index 641a4389e2d..8d32b9294bd 100644 --- a/src/mongo/shell/linenoise.cpp +++ b/src/mongo/shell/linenoise.cpp @@ -2765,7 +2765,17 @@ int linenoiseHistorySetMaxLen(int len) { /* Save the history in the specified file. On success 0 is returned * otherwise -1 is returned. */ int linenoiseHistorySave(const char* filename) { - FILE* fp = fopen(filename, "wt"); + FILE* fp; +#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE || defined(__APPLE__) + int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1) { + // report errno somehow? + return -1; + } + fp = fdopen(fd, "wt"); +#else + fp = fopen(filename, "wt"); +#endif // _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE || defined(__APPLE__) if (fp == NULL) { return -1; } @@ -2775,7 +2785,7 @@ int linenoiseHistorySave(const char* filename) { fprintf(fp, "%s\n", history[j]); } } - fclose(fp); + fclose(fp); // Also causes fd to be closed. return 0; } |