1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/*
* protector.go - Functions for creating and getting action.Protectors which
* ensure that login passphrases are on the correct filesystem.
*
* 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 (
"log"
"github.com/google/fscrypt/actions"
"github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/metadata"
"github.com/google/fscrypt/util"
)
// createProtector makes a new protector on either ctx.Mount or if the requested
// source is a pam_passphrase, creates it on the root filesystem. Prompts for
// user input are used to get the source, name and keys.
func createProtectorFromContext(ctx *actions.Context) (*actions.Protector, error) {
if err := promptForSource(ctx); err != nil {
return nil, err
}
log.Printf("using source: %s", ctx.Config.Source.String())
if ctx.Config.Source == metadata.SourceType_pam_passphrase &&
userFlag.Value == "" && util.IsUserRoot() {
return nil, ErrSpecifyUser
}
name, err := promptForName(ctx)
if err != nil {
return nil, err
}
log.Printf("using name: %s", name)
// We only want to create new login protectors on the root filesystem.
// So we make a new context if necessary.
if ctx.Config.Source == metadata.SourceType_pam_passphrase && ctx.Mount.Path != "/" {
log.Printf("creating login protector on %q instead of %q", "/", ctx.Mount.Path)
if ctx, err = modifiedContext(ctx); err != nil {
return nil, err
}
}
return actions.CreateProtector(ctx, name, createKeyFn)
}
// selectExistingProtector returns a locked Protector which corresponds to an
// option in the non-empty slice of options. Prompts for user input are used to
// get the keys and select the option.
func selectExistingProtector(ctx *actions.Context, options []*actions.ProtectorOption) (*actions.Protector, error) {
idx, err := promptForProtector(options)
if err != nil {
return nil, err
}
option := options[idx]
log.Printf("using %s", formatInfo(option.ProtectorInfo))
return actions.GetProtectorFromOption(ctx, option)
}
// expandedProtectorOptions gets all the actions.ProtectorOptions for ctx.Mount
// as well as any pam_passphrase protectors for the root filesystem.
func expandedProtectorOptions(ctx *actions.Context) ([]*actions.ProtectorOption, error) {
options, err := ctx.ProtectorOptions()
if err != nil {
return nil, err
}
// Do nothing different if we are at the root, or cannot load the root.
if ctx.Mount.Path == "/" {
return options, nil
}
if ctx, err = modifiedContext(ctx); err != nil {
log.Print(err)
return options, nil
}
rootOptions, err := ctx.ProtectorOptions()
if err != nil {
log.Print(err)
return options, nil
}
log.Print("adding additional ProtectorOptions")
// Keep track of what we have seen, so we don't have duplicates
seenOptions := make(map[string]bool)
for _, option := range options {
seenOptions[option.Descriptor()] = true
}
for _, option := range rootOptions {
// Add in unseen passphrase protectors on the root filesystem
// to the options list as potential linked protectors.
if option.Source() == metadata.SourceType_pam_passphrase &&
!seenOptions[option.Descriptor()] {
option.LinkedMount = ctx.Mount
options = append(options, option)
}
}
return options, nil
}
// modifiedContext returns a copy of ctx with the mountpoint replaced by that of
// the root filesystem.
func modifiedContext(ctx *actions.Context) (*actions.Context, error) {
mnt, err := filesystem.GetMount("/")
if err != nil {
return nil, err
}
modifiedCtx := *ctx
modifiedCtx.Mount = mnt
return &modifiedCtx, nil
}
|