summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go')
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go104
1 files changed, 100 insertions, 4 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go
index 96622109e96..1e8ab118a0a 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/options/options.go
@@ -10,6 +10,7 @@ package options
import (
"fmt"
+ "io/ioutil"
"os"
"regexp"
"runtime"
@@ -22,6 +23,8 @@ import (
"github.com/mongodb/mongo-tools/common/failpoint"
"github.com/mongodb/mongo-tools/common/log"
"github.com/mongodb/mongo-tools/common/util"
+ "github.com/pkg/errors"
+ "gopkg.in/yaml.v2"
)
// Gitspec that the tool was built with. Needs to be set using -ldflags
@@ -95,8 +98,9 @@ type Namespace struct {
// Struct holding generic options
type General struct {
- Help bool `long:"help" description:"print usage"`
- Version bool `long:"version" description:"print the tool version and exit"`
+ Help bool `long:"help" description:"print usage"`
+ Version bool `long:"version" description:"print the tool version and exit"`
+ ConfigPath string `long:"config" value-name:"<filename>" description:"path to a configuration file"`
MaxProcs int `long:"numThreads" hidden:"true"`
Failpoints string `long:"failpoints" hidden:"true"`
@@ -421,9 +425,16 @@ func (o *ToolOptions) AddOptions(opts ExtraOptions) {
}
}
-// Parse the command line args. Returns any extra args not accounted for by
-// parsing, as well as an error if the parsing returns an error.
+// ParseArgs parses a potential config file followed by the command line args, overriding
+// any values in the config file. Returns any extra args not accounted for by parsing,
+// as well as an error if the parsing returns an error.
func (o *ToolOptions) ParseArgs(args []string) ([]string, error) {
+ LogSensitiveOptionWarnings(args)
+
+ if err := o.ParseConfigFile(args); err != nil {
+ return []string{}, err
+ }
+
args, err := o.parser.ParseArgs(args)
if err != nil {
return []string{}, err
@@ -455,6 +466,91 @@ func (o *ToolOptions) ParseArgs(args []string) ([]string, error) {
return args, err
}
+// LogSensitiveOptionWarnings logs a warning for any sensitive information (i.e. passwords)
+// that appear on the command line for the --password, --uri and --sslPEMKeyPassword options.
+// This also applies to a connection string that appears as a positional argument.
+func LogSensitiveOptionWarnings(args []string) {
+ passwordMsg := "WARNING: On some systems, a password provided directly using " +
+ "--password may be visible to system status programs such as `ps` that may be " +
+ "invoked by other users. Consider omitting the password to provide it via stdin, " +
+ "or using the --config option to specify a configuration file with the password."
+
+ uriMsg := "WARNING: On some systems, a password provided directly in a connection string " +
+ "or using --uri may be visible to system status programs such as `ps` that may be " +
+ "invoked by other users. Consider omitting the password to provide it via stdin, " +
+ "or using the --config option to specify a configuration file with the password."
+
+ sslMsg := "WARNING: On some systems, a password provided directly using --sslPEMKeyPassword " +
+ "may be visible to system status programs such as `ps` that may be invoked by other users. " +
+ "Consider using the --config option to specify a configuration file with the password."
+
+ // Create temporary options for parsing command line args.
+ tempOpts := New("", "", EnabledOptions{Auth: true, Connection: true, URI: true})
+ _, err := tempOpts.parser.ParseArgs(args)
+ if err != nil {
+ return
+ }
+
+ // Log a message for --password, if specified.
+ if tempOpts.Auth.Password != "" {
+ log.Logvf(log.Always, passwordMsg)
+ }
+
+ // Log a message for --uri or a positional connection string, if either is specified.
+ uri := tempOpts.URI.ConnectionString
+ if uri != "" {
+ if cs, err := connstring.ParseURIConnectionString(uri); err == nil && cs.Password != "" {
+ log.Logvf(log.Always, uriMsg)
+ }
+ }
+
+ // Log a message for --sslPEMKeyPassword, if specified.
+ if tempOpts.SSL.SSLPEMKeyPassword != "" {
+ log.Logvf(log.Always, sslMsg)
+ }
+}
+
+// ParseConfigFile iterates over args to find a --config option. If not found, we return.
+// If found, we read the contents of the specified config file in YAML format. We parse
+// any values corresponding to --password, --uri and --sslPEMKeyPassword, and store them
+// in the opts.
+func (opts *ToolOptions) ParseConfigFile(args []string) error {
+ // Get config file path from the arguments, if specified.
+ _, err := opts.parser.ParseArgs(args)
+ if err != nil {
+ return err
+ }
+
+ // No --config option was specified.
+ if opts.General.ConfigPath == "" {
+ return nil
+ }
+
+ // --config option specifies a file path.
+ configBytes, err := ioutil.ReadFile(opts.General.ConfigPath)
+ if err != nil {
+ return errors.Wrapf(err, "error opening file with --config")
+ }
+
+ // Unmarshal the config file as a top-level YAML file.
+ var config struct {
+ Password string `yaml:"password"`
+ ConnectionString string `yaml:"uri"`
+ SSLPEMKeyPassword string `yaml:"sslPEMKeyPassword"`
+ }
+ err = yaml.UnmarshalStrict(configBytes, &config)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing config file %s", opts.General.ConfigPath)
+ }
+
+ // Assign each parsed value to its respective ToolOptions field.
+ opts.Auth.Password = config.Password
+ opts.URI.ConnectionString = config.ConnectionString
+ opts.SSL.SSLPEMKeyPassword = config.SSLPEMKeyPassword
+
+ return nil
+}
+
func (opts *ToolOptions) handleUnknownOption(option string, arg flags.SplitArgument, args []string) ([]string, error) {
if option == "dbpath" || option == "directoryperdb" || option == "journal" {
return args, fmt.Errorf("--dbpath and related flags are not supported in 3.0 tools.\n" +