Mercurial > go > multipass
annotate file/file.go @ 18:00d30c67b56d
Put all the library stuff into multipass/file.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 01 Nov 2015 12:16:51 -0500 |
parents | 9b4ec6b5c23e |
children | ef2ef22ca4b1 |
rev | line source |
---|---|
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
1 // Package file handles I/O for single password files. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
2 // |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
3 // A password file contains multiple passwords for a single user. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
4 // It starts with a banner that indicates the version of the file, |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
5 // then has entries in the format specified by Entry. |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
6 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
7 package file |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
8 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
9 import ( |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
10 "bufio" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
11 "errors" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
12 "os" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
13 "syscall" |
10 | 14 "time" |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
15 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
16 "golang.org/x/sys/unix" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
17 ) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
18 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
19 const ( |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
20 // the Banner acts as a version indicator |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
21 Banner = "# Multipass v0.1 password file" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
22 ) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
23 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
24 var ( |
15
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
25 // Raised when there's an error in the file format. |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
26 ErrorBadFile = errors.New("multipass/file: Invalid file format") |
15
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
27 |
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
28 // we spin waiting for the file to become available, doubling our wait time |
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
29 // every time it's unavailable. If the wait time is longer than this, |
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
30 // give up. Variable so it can be set in tests. |
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
31 maxDelay = time.Minute |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
32 ) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
33 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
34 type ShadowFile struct { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
35 name string |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
36 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
37 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
38 // New creates a ShadowFile for reading at the given path. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
39 // If a file needs to be created, uses the given GID to create it. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
40 func New(name string) *ShadowFile { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
41 f := new(ShadowFile) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
42 f.name = name |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
43 return f |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
44 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
45 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
46 func (f *ShadowFile) newFilename() string { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
47 return f.name + ".new" |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
48 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
49 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
50 func (f *ShadowFile) open() (*os.File, *bufio.Scanner, error) { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
51 file, err := os.Open(f.name) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
52 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
53 return nil, nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
54 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
55 scanner := bufio.NewScanner(file) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
56 if !scanner.Scan() { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
57 file.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
58 return nil, nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
59 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
60 if scanner.Text() != Banner { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
61 file.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
62 return nil, nil, ErrorBadFile |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
63 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
64 return file, scanner, nil |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
65 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
66 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
67 func (f *ShadowFile) Authenticate(password string) (bool, error) { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
68 file, scanner, err := f.open() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
69 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
70 return false, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
71 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
72 defer file.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
73 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
74 for scanner.Scan() { |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
75 entry, err := EntryFromShadow(scanner.Text()) |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
76 // Skip invalid lines. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
77 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
78 continue |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
79 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
80 if entry.Authenticate(password) { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
81 return true, nil |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
82 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
83 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
84 return false, nil |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
85 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
86 |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
87 func (f *ShadowFile) Add(entry *Entry) error { |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
88 handle, err := f.openWrite() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
89 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
90 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
91 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
92 err = handle.write(entry) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
93 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
94 handle.bail() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
95 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
96 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
97 for handle.next() { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
98 if entry, err := handle.entry(); err == nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
99 // If we get an invalid entry, just skip it. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
100 if err := handle.write(entry); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
101 handle.bail() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
102 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
103 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
104 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
105 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
106 return handle.finalize() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
107 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
108 |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
109 func (f *ShadowFile) AllEntries() ([]*Entry, error) { |
10 | 110 file, scanner, err := f.open() |
111 if err != nil { | |
112 return nil, err | |
113 } | |
114 defer file.Close() | |
115 | |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
116 var entries []*Entry |
10 | 117 |
118 for scanner.Scan() { | |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
119 entry, err := EntryFromShadow(scanner.Text()) |
10 | 120 // Skip invalid lines. |
121 if err != nil { | |
122 continue | |
123 } | |
124 entries = append(entries, entry) | |
125 } | |
126 return entries, nil | |
127 } | |
128 | |
129 func (f *ShadowFile) Remove(id uint64) error { | |
130 handle, err := f.openWrite() | |
131 if err != nil { | |
132 return err | |
133 } | |
134 for handle.next() { | |
135 if entry, err := handle.entry(); err == nil { | |
136 // If we get an invalid entry, just skip it. | |
137 if entry.ID() != id { | |
138 if err := handle.write(entry); err != nil { | |
139 handle.bail() | |
140 return err | |
141 } | |
142 } | |
143 } | |
144 } | |
145 return handle.finalize() | |
146 } | |
147 | |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
148 func (f *ShadowFile) openWrite() (*writeHandle, error) { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
149 return openWriteHandle(f.newFilename(), f.name) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
150 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
151 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
152 type writeHandle struct { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
153 // We write to a file handle pointing to tempName. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
154 tempName string |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
155 tempFile *os.File |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
156 writer *bufio.Writer |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
157 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
158 // It will eventually move to fileName, which is our source file. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
159 fileName string |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
160 // If inFile is nil, we're creating a new multipass file. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
161 inFile *os.File |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
162 scanner *bufio.Scanner |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
163 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
164 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
165 func openWriteHandle(tempName, fileName string) (*writeHandle, error) { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
166 h := new(writeHandle) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
167 h.tempName = tempName |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
168 h.fileName = fileName |
10 | 169 // Open the output file, but only if it doesn't exist. |
9
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
170 // This prevents race conditions. |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
171 oldUmask := unix.Umask(077) |
10 | 172 var tempFile *os.File |
173 delay := time.Nanosecond | |
174 for tempFile == nil { | |
175 tempTempFile, err := os.OpenFile(tempName, os.O_CREATE|os.O_EXCL|os.O_WRONLY|os.O_SYNC, 0600) | |
176 tempFile = tempTempFile | |
177 if err != nil { | |
178 perr := err.(*os.PathError) | |
179 errno, ok := perr.Err.(syscall.Errno) | |
180 if !ok { | |
181 return nil, err | |
182 } | |
15
9b4ec6b5c23e
Add tests for multipass files.
Paul Fisher <paul@pfish.zone>
parents:
13
diff
changeset
|
183 if errno != syscall.EEXIST || delay > maxDelay { |
10 | 184 return nil, err |
185 } | |
186 time.Sleep(delay) | |
187 delay *= 2 | |
188 } | |
189 } | |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
190 unix.Umask(oldUmask) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
191 h.tempFile = tempFile |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
192 // Open the input file. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
193 inFile, err := os.Open(fileName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
194 if err == nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
195 // Prepare to read in the input file, if it exists. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
196 h.inFile = inFile |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
197 h.scanner = bufio.NewScanner(h.inFile) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
198 if !h.scanner.Scan() { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
199 return nil, ErrorBadFile |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
200 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
201 if h.scanner.Text() != Banner { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
202 return nil, ErrorBadFile |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
203 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
204 // Change the owner and group of the new file to that of the old. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
205 inStat, err := h.inFile.Stat() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
206 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
207 h.bail() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
208 return nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
209 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
210 inStatUnix := inStat.Sys().(*syscall.Stat_t) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
211 if err := h.tempFile.Chown(int(inStatUnix.Uid), int(inStatUnix.Gid)); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
212 h.bail() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
213 return nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
214 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
215 if err := h.tempFile.Chmod(inStat.Mode()); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
216 h.bail() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
217 return nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
218 } |
9
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
219 } else { |
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
220 // TODO(pfish): Restrict ACL to only multipass authenticators. |
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
221 if err := h.tempFile.Chmod(0644); err != nil { |
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
222 h.bail() |
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
223 return nil, err |
e58bfc7fc207
Make multipass files default all-readable.
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
224 } |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
225 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
226 h.writer = bufio.NewWriter(h.tempFile) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
227 if _, err := h.writer.WriteString(Banner + "\n"); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
228 return nil, err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
229 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
230 return h, nil |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
231 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
232 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
233 func (h *writeHandle) bail() { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
234 h.tempFile.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
235 h.inFile.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
236 os.Remove(h.tempName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
237 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
238 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
239 func (h *writeHandle) next() bool { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
240 // If the scanner is nil, then we have no input file and therefore no next. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
241 return h.scanner != nil && h.scanner.Scan() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
242 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
243 |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
244 func (h *writeHandle) entry() (*Entry, error) { |
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
245 return EntryFromShadow(h.scanner.Text()) |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
246 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
247 |
18
00d30c67b56d
Put all the library stuff into multipass/file.
Paul Fisher <paul@pfish.zone>
parents:
15
diff
changeset
|
248 func (h *writeHandle) write(entry *Entry) error { |
0
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
249 if _, err := h.writer.WriteString(entry.Encode()); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
250 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
251 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
252 _, err := h.writer.WriteString("\n") |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
253 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
254 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
255 |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
256 func (h *writeHandle) finalize() error { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
257 h.inFile.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
258 // Make absolutely completely sure we're synced. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
259 if err := h.writer.Flush(); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
260 h.tempFile.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
261 os.Remove(h.tempName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
262 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
263 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
264 if err := h.tempFile.Sync(); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
265 h.tempFile.Close() |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
266 os.Remove(h.tempName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
267 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
268 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
269 // Close the file. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
270 if err := h.tempFile.Close(); err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
271 os.Remove(h.tempName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
272 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
273 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
274 // And atomically write it over the new one. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
275 err := os.Rename(h.tempName, h.fileName) |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
276 if err != nil { |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
277 return err |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
278 } |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
279 // If we get here, everything succeeded, and only in this case |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
280 // will the multipass shadow file have been updated. |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
281 return nil |
c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
282 } |