forked from booski/passman
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcryptapi.sh
executable file
·395 lines (306 loc) · 11 KB
/
cryptapi.sh
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
#!/bin/bash
set -e
E_VALIDATE="1" # wrong password etc
E_CONFLICT="2" # mapping already exists etc
E_INVALID="3" # invalid argument given
E_PRIVILEGE="4" # user cannot access password etc
E_GENERAL="99" # uncategorized error
function bootstrap {
local fuser="$1"
local upass="$2"
# initializes passman into a usable state, using '$1' as its initial administrator
# '$2' is the initial user's password
# returns an error if any remnants of a working state are detected, in which case it does nothing
local count=0
for i in user group pass
do
[ -e $i ] && (( count++ ))
done
if [ "$count" = 3 ] && [ -e group/admin.* ]
then
echo "passman seems to be bootstrapped already, not doing anything."
return $E_CONFLICT
elif [ ! "$count" = 0 ]
then
echo "passman seems to be in an inconsistent state, please clean up before trying to bootstrap."
return $E_GENERAL
fi
mkdir user
mkdir group
mkdir pass
chmod -R u=rwX,g=rX,o=rX .
local utoken=$(make-token)
local atoken=$(make-token)
encrypt user/"$fuser" "$upass" "$utoken"
encrypt group/admin."$fuser" "$utoken" "$atoken"
encrypt user/"$fuser".admin "$atoken" "$utoken"
return 0
}
function get-user-token {
local uname=$1
local pass=$2
# prints the token associated with '$1' by decrypting the file
# user/'$1' with '$2'
# if the decryption encounters an error, its error code is returned
decrypt user/"$uname" "$pass"
}
function get-admin-token {
local uname="$1"
local pass="$2"
# prints the token associated with '$1' by decrypting the file
# group/admin.'$1' with '$2'
# if the decryption encounters an error, its error code is returned
decrypt group/admin."$uname" "$pass"
}
function encrypt {
local name="$1"
local pass="$2"
local cont="$3"
# encrypts '$3' in '$1' with '$2'
# if the file exists, an error is returned
# if the encryption encounters an error, its error code is returned
[ -e "$name" ] && return $E_CONFLICT
touch "$name"
chmod 600 "$name"
echo -e "$cont" > "$name"
export pass
ccrypt -eq -S "" -E pass "$name" 2>/dev/null
}
function decrypt {
local name="$1"
local pass="$2"
# tries to decrypt and print '$1' using '$2'
# if the decryption encounters an error, its error code is returned
export pass
ccrypt -cq -E pass "$name" 2>/dev/null || return $E_VALIDATE
}
function make-token {
# prints a generated string for use as intermediate encryption key for groups/users
pwgen -s 128 1
}
function list-user-groups {
local uname="$1"
# prints all groups that '$1' belongs to as a space-delimited list
local out=$(ls group/*.$uname 2>/dev/null | sed -r -e "s%^group/%%" -e "s%\.$uname$%%" | sort -u)
printf "%s\n" "$out"
}
function list-group-passes {
local gname="$1"
# prints all password files belonging to '$1' as a space-delimited list
# does not decrypt any passwords
local out=$(ls pass/*.$gname 2>/dev/null | sed -r -e "s%^pass/%%" -e "s%\.$gname$%%" | sort -u)
printf "%s\n" "$out"
}
function list-password-groups {
local pname="$1"
# prints all the groups that '$1' belongs to as a space-delimited list
local out=$(ls pass/$pname.* 2>/dev/null | sed -r "s%^pass/$pname\.%%" | sort -u)
printf "%s\n" "$out"
}
function list-group-users {
local gname="$1"
# prints all the users that belong to '$1' as a space-delimited list
local out=$(ls group/$gname.* 2>/dev/null | sed -r "s%^group/$gname\.%%" | sort -u)
printf "%s\n" "$out"
}
function list-passwords {
# prints all the passwords stored in the system
# does not decrypt any passwords, only prints identifiers
local out=$(ls pass/ | sed -r -e "s%^pass/%%" -e "s%\.[^.]+$%%" | sort -u)
printf "%s\n" "$out"
}
function list-users {
local out=$(ls user/ | sed -r -e "s%^user/%%" -e "s%\.[^.]+$%%" | sort -u)
printf "%s\n" "$out"
}
function list-groups {
local out=$(ls group/ | sed -r -e "s%^group/%%" -e "s%\.[^.]+$%%" | sort -u)
printf "%s\n" "$out"
}
function list-available {
local uname="$1"
# prints all the password files that '$1' has access to as a space-delimited list
# does not decrypt any passwords
local groups=$(list-user-groups "$uname")
local passes=""
for gname in $groups
do
passes=$(list-group-passes "$gname")' '"$passes"
done
local out=$(printf "%s" "$passes" | sort -u)
printf "%s\n" "$out"
}
function show-pass {
local uname="$1"
local utoken="$2"
local pname="$3"
# decrypts and prints '$3', using '$2' belonging to '$1'
# if '$1' cannot access '$3', an error is returned
local ugroups=$(list-user-groups "$uname")
local pgroups=$(list-password-groups "$pname")
for group in $pgroups
do
echo "$ugroups" | grep -q "$group"
if [ "$?" = "0" ]
then
local gtoken=$(decrypt group/"$group"."$uname" "$utoken")
decrypt pass/"$pname"."$group" "$gtoken"
return $?
fi
done
return $E_PRIVILEGE
}
function add-user {
local admintoken="$1"
local uname="$2"
local upass="$3"
# adds '$2' to the system with '$3', authenticating with '$1'
# returns an error if the username 'admin' is supplied or the username already exists
# will NOT return an error if an invalid '$1' is supplied, because there isn't necessarily anything to validate against
local utoken=$(make-token)
[ "$uname" = "admin" ] && return $E_CONFLICT
encrypt user/"$uname".admin "$admintoken" "$utoken" || return $?
encrypt user/"$uname" "$upass" "$utoken" || return $?
}
function change-user-pass {
local utoken="$1"
local uname="$2"
local newpass="$3"
# changes '$2's password to '$3', authenticating with '$1'
# if the user does not belong to any groups, the password is changed without question
# otherwise, the supplied '$1' is checked against one of the groups the user belongs to
local testfile=$(ls group/*."$uname" 2>/dev/null | tr '\n' ' ' | cut -d' ' -f1)
[ -n "$testfile" ] && { decrypt "$testfile" "$utoken" &> /dev/null || return $E_VALIDATE; }
rm user/"$uname"
encrypt user/"$uname" "$newpass" "$utoken" || return $?
}
function remove-user {
local admintoken="$1"
local uname="$2"
# removes '$2' from the system, given that '$1' is valid
# also removes all group mappings for the user
# returns an error if the user doesn't exist or '$1' is invalid
decrypt user/"$uname".admin "$admintoken" &> /dev/null|| return $E_VALIDATE
rm user/"$uname"*
rm group/*."$uname" 2>/dev/null || true
}
function make-user-admin {
local admintoken="$1"
local uname="$2"
# makes '$2' an administrator
# an error will be returned if '$1' is invalid
local utoken=$(decrypt user/"$uname".admin "$admintoken") || return $E_VALIDATE
encrypt group/admin."$uname" "$utoken" "$admintoken"
}
function unmake-user-admin {
local admintoken="$1"
local uname="$2"
# revokes '$2's admin privileges
# an error is returned if the user isn't an administrator or '$1' is invalid
decrypt user/"$uname".admin "$admintoken" &> /dev/null || return $?
rm group/admin."$uname"
}
function map-user-group {
local admintoken="$1"
local uname="$2"
local gname="$3"
# adds '$2' to '$3'
# admin privileges cannot be granted via this function
# an error is returned if '$3' is 'admin', '$2' already belongs to '$3', or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
[ -e group/"$gname"."$uname" ] && return $E_CONFLICT
local utoken=$(decrypt user/"$uname".admin "$admintoken") || return $E_VALIDATE
local gtoken=$(decrypt group/"$gname".admin "$admintoken") || return $E_VALIDATE
encrypt group/"$gname"."$uname" "$utoken" "$gtoken"
}
function unmap-user-group {
local admintoken="$1"
local uname="$2"
local gname="$3"
# removes '$2' from '$3'
# admin privileges cannot be revoked via this function
# an error is returned if '$3' is admin, the mapping doesn't exist, or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
decrypt group/"$gname".admin "$admintoken" &> /dev/null || return $?
rm group/"$gname"."$uname"
}
function add-group {
local admintoken="$1"
local gname="$2"
# adds a group called '$2'
# an error is returned if '$2' is 'admin', the group already exists, or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
[ -e group/"$gname".admin ] && return $E_CONFLICT
local gtoken=$(make-token)
encrypt group/"$gname".admin "$admintoken" "$gtoken"
}
function remove-group {
local admintoken="$1"
local gname="$2"
# removes the group named '$2'
# an error is returned if '$2' is 'admin', '$2' doesn't exist, or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
decrypt group/"$gname".admin "$admintoken" &> /dev/null || return $?
rm pass/*."$gname" 2>/dev/null || true
rm group/"$gname".*
}
function map-pass-group {
local admintoken="$1"
local pname="$2"
local gname="$3"
# adds '$3' to '$2'
# an error is returned if '$2' is 'admin', the password is already in the group, or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
[ -e pass/"$pname"."$gname" ] && return $E_CONFLICT
local gtoken=$(decrypt group/"$gname".admin "$admintoken") || return $E_VALIDATE
local pass=$(decrypt pass/"$pname".admin "$admintoken") || return $E_VALIDATE
encrypt pass/"$pname"."$gname" "$gtoken" "$pass"
}
function unmap-pass-group {
local admintoken="$1"
local pname="$2"
local gname="$3"
# removes '$3' from '$2'
# returns an error if '$2' or '$3' is 'admin', the mapping doesn't exist, or '$1' is invalid
[ "$gname" = "admin" ] && return $E_PRIVILEGE
decrypt pass/"$pname".admin "$admintoken" &> /dev/null || return $E_VALIDATE
decrypt group/"$gname".admin "$admintoken" &> /dev/null || return $E_VALIDATE
rm pass/"$pname"."$gname"
}
function add-pass {
local admintoken="$1"
local pname="$2"
local pass="$3"
# adds a password to the system. It is identified by '$2', and its value is '$3'
# an error is returned if '$1' is invalid or '$2' already exists
encrypt pass/"$pname".admin "$admintoken" "$pass"
}
function remove-pass {
local admintoken="$1"
local pname="$2"
# removes the password named '$2' from the system
# an error is returned if '$1' is invalid or '$2' doesn't exist
decrypt pass/"$pname".admin "$admintoken" &> /dev/null || return $?
rm pass/"$pname".*
}
function modify-pass {
local admintoken="$1"
local pname="$2"
local newpass="$3"
# replaces the content of '$2' with '$3'
# an error is returned if '$1' is invalid or '$2' doesn't exist
for group in $(list-password-groups "$pname")
do
rm pass/"$pname"."$group"
if [ "$group" == "admin" ]
then
continue
fi
gtok=$(decrypt group/"$group".admin "$admintoken")
res=$?
[ -z "$gtok" ] && return "$res"
encrypt pass/"$pname"."$group" "$gtok" "$newpass"
done
encrypt pass/"$pname".admin "$admintoken" "$newpass"
return $?
}