aboutsummaryrefslogtreecommitdiff
path: root/cmd/fscrypt/flags.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/fscrypt/flags.go')
-rw-r--r--cmd/fscrypt/flags.go261
1 files changed, 261 insertions, 0 deletions
diff --git a/cmd/fscrypt/flags.go b/cmd/fscrypt/flags.go
new file mode 100644
index 0000000..da3116f
--- /dev/null
+++ b/cmd/fscrypt/flags.go
@@ -0,0 +1,261 @@
+/*
+ * flags.go - File which contains all the flags used by the application. This
+ * includes both global flags and command specific flags. When applicable, it
+ * also includes the default values.
+ *
+ * Copyright 2017 Google Inc.
+ * Author: Joe Richey (joerichey@google.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "fscrypt/actions"
+ "log"
+ "regexp"
+ "strconv"
+ "time"
+
+ "github.com/urfave/cli"
+)
+
+// We define the types boolFlag, durationFlag, and stringFlag here instead of
+// using those present in urfave/cli because we need them to conform to the
+// prettyFlag interface (in format.go). The Getters just get the corresponding
+// variables, String() just uses longDisplay, and Apply just sets the
+// corresponding type of flag.
+type boolFlag struct {
+ Name string
+ Usage string
+ Default bool
+ Value bool
+}
+
+func (b *boolFlag) GetName() string { return b.Name }
+func (b *boolFlag) GetArgName() string { return "" }
+func (b *boolFlag) GetUsage() string { return b.Usage }
+
+func (b *boolFlag) String() string {
+ if b.Default == false {
+ return longDisplay(b)
+ }
+ return longDisplay(b, strconv.FormatBool(b.Default))
+}
+
+func (b *boolFlag) Apply(set *flag.FlagSet) {
+ set.BoolVar(&b.Value, b.Name, b.Default, b.Usage)
+}
+
+type durationFlag struct {
+ Name string
+ ArgName string
+ Usage string
+ Default time.Duration
+ Value time.Duration
+}
+
+func (d *durationFlag) GetName() string { return d.Name }
+func (d *durationFlag) GetArgName() string { return d.ArgName }
+func (d *durationFlag) GetUsage() string { return d.Usage }
+
+func (d *durationFlag) String() string {
+ if d.Default == 0 {
+ return longDisplay(d)
+ }
+ return longDisplay(d, d.Value.String())
+}
+
+func (d *durationFlag) Apply(set *flag.FlagSet) {
+ set.DurationVar(&d.Value, d.Name, d.Default, d.Usage)
+}
+
+type stringFlag struct {
+ Name string
+ ArgName string
+ Usage string
+ Default string
+ Value string
+}
+
+func (s *stringFlag) GetName() string { return s.Name }
+func (s *stringFlag) GetArgName() string { return s.ArgName }
+func (s *stringFlag) GetUsage() string { return s.Usage }
+
+func (s *stringFlag) String() string {
+ if s.Default == "" {
+ return longDisplay(s)
+ }
+ return longDisplay(s, strconv.Quote(s.Default))
+}
+
+func (s *stringFlag) Apply(set *flag.FlagSet) {
+ set.StringVar(&s.Value, s.Name, s.Default, s.Usage)
+}
+
+var (
+ // allFlags contains every defined flag (used for formatting).
+ // UPDATE THIS ARRAY WHEN ADDING NEW FLAGS!!!
+ // TODO(joerichey) add presubmit rule to enforce this
+ allFlags = []prettyFlag{helpFlag, versionFlag, verboseFlag, quietFlag,
+ forceFlag, legacyFlag, skipUnlockFlag, timeTargetFlag,
+ sourceFlag, nameFlag, keyFileFlag, protectorFlag,
+ unlockWithFlag, policyFlag}
+ // universalFlags contains flags that should be on every command
+ universalFlags = []cli.Flag{verboseFlag, quietFlag, helpFlag}
+)
+
+// Bool flags: used to switch some behavior on or off
+var (
+ helpFlag = &boolFlag{
+ Name: "help",
+ Usage: `Prints help screen for commands and subcommands.`,
+ }
+ versionFlag = &boolFlag{
+ Name: "version",
+ Usage: `Prints version and license information.`,
+ }
+ verboseFlag = &boolFlag{
+ Name: "verbose",
+ Usage: `Prints additional debug messages to standard output.`,
+ }
+ quietFlag = &boolFlag{
+ Name: "quiet",
+ Usage: `Prints nothing to standard output except for errors.
+ Selects the default for any options that would normally
+ show a prompt.`,
+ }
+ forceFlag = &boolFlag{
+ Name: "force",
+ Usage: fmt.Sprintf(`Suppresses all confirmation prompts and
+ warnings, causing any action to automatically proceed.
+ WARNING: This bypasses confirmations for protective
+ operations, use with care.`),
+ }
+ legacyFlag = &boolFlag{
+ Name: "legacy",
+ Usage: `Allow for support of older kernels with ext4 (before
+ v4.8) and F2FS (before v4.6) filesystems.`,
+ Default: true,
+ }
+ skipUnlockFlag = &boolFlag{
+ Name: "skip-unlock",
+ Usage: `Leave the directory in a locked state after setup.
+ "fscrypt unlock" will need to be run in order to use the
+ directory.`,
+ }
+)
+
+// Option flags: used to specify options instead of being prompted for them
+var (
+ timeTargetFlag = &durationFlag{
+ Name: "time",
+ ArgName: "TIME",
+ Usage: `Set the global options so that passphrase hashing takes
+ TIME long. TIME should be formatted as a sequence of
+ decimal numbers, each with optional fraction and a unit
+ suffix, such as "300ms", "1.5s" or "2h45m". Valid time
+ units are "ms", "s", "m", and "h".`,
+ Default: 1 * time.Second,
+ }
+ sourceFlag = &stringFlag{
+ Name: "source",
+ ArgName: "SOURCE",
+ Usage: fmt.Sprintf(`New protectors will have type SOURCE. SOURCE
+ can be one of pam_passphrase, custom_passphrase, or
+ raw_key. If not specified, the user will be prompted for
+ the source, with a default pulled from %s.`,
+ actions.ConfigFileLocation),
+ }
+ nameFlag = &stringFlag{
+ Name: "name",
+ ArgName: "PROTECTOR_NAME",
+ Usage: `New custom_passphrase and raw_key protectors will be
+ named PROTECTOR_NAME. If not specified, the user will be
+ prompted for a name.`,
+ }
+ keyFileFlag = &stringFlag{
+ Name: "key",
+ ArgName: "FILE",
+ Usage: `Use the contents of FILE as the wrapping key when
+ creating or unlocking raw_key protectors. FILE should be
+ formatted as raw binary and should be exactly 32 bytes
+ long.`,
+ }
+ protectorFlag = &stringFlag{
+ Name: "protector",
+ ArgName: "MOUNTPOINT:ID",
+ Usage: `Specify an existing protector on filesystem MOUNTPOINT
+ with protector descriptor ID which should be used in the
+ command.`,
+ }
+ unlockWithFlag = &stringFlag{
+ Name: "unlock-with",
+ ArgName: "MOUNTPOINT:ID",
+ Usage: `Specify an existing protector on filesystem MOUNTPOINT
+ with protector descriptor ID which should be used to
+ unlock a policy (usually specified with --policy). This
+ flag is only useful if a policy is protected with
+ multiple protectors. If not specified, the user will be
+ prompted for a protector.`,
+ }
+ policyFlag = &stringFlag{
+ Name: "policy",
+ ArgName: "MOUNTPOINT:ID",
+ Usage: `Specify an existing policy on filesystem MOUNTPOINT with
+ key descriptor ID which should be used in the command.`,
+ }
+)
+
+// The first group is optional and corresponds to the mountpoint. The second
+// group is required and corresponds to the descriptor.
+var idFlagRegex = regexp.MustCompile("^([[:print:]]+):([[:alnum:]]+)$")
+
+// parseMetadataFlag takes the value of either protectorFlag or policyFlag
+// formatted as MOUNTPOINT:DESCRIPTOR, and returns a context for the mountpoint
+// and a string for the descriptor.
+func parseMetadataFlag(flagValue string) (*actions.Context, string, error) {
+ matches := idFlagRegex.FindStringSubmatch(flagValue)
+ if matches == nil {
+ err := fmt.Errorf("flag value %q does not have format %s", flagValue, mountpointIDArg)
+ return nil, "", err
+ }
+
+ mountpoint := matches[1]
+ descriptor := matches[2]
+ log.Printf("parsed flag: mountpoint=%q descriptor=%s", mountpoint, descriptor)
+
+ ctx, err := actions.NewContextFromMountpoint(mountpoint)
+ return ctx, descriptor, err
+}
+
+// getProtectorFromFlag gets an existing locked protector from protectorFlag.
+func getProtectorFromFlag(flagValue string) (*actions.Protector, error) {
+ ctx, descriptor, err := parseMetadataFlag(flagValue)
+ if err != nil {
+ return nil, err
+ }
+ return actions.GetProtector(ctx, descriptor)
+}
+
+// getPolicyFromFlag gets an existing locked policy from policyFlag.
+func getPolicyFromFlag(flagValue string) (*actions.Policy, error) {
+ ctx, descriptor, err := parseMetadataFlag(flagValue)
+ if err != nil {
+ return nil, err
+ }
+ return actions.GetPolicy(ctx, descriptor)
+}