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
|
local posix = require('posix')
local db = {}
db.file = "/etc/shadow"
db.fields = { 'name', 'passwd', 'lastchanged', 'minimum', 'maximum', 'warn', 'inactive', 'expire', 'dummy' }
function db.splitent(line)
local ent = {}
local i = 1
for value in string.gmatch(line or "", "([^:]*):?") do
ent[db.fields[i]] = value
i = i + 1
end
return ent
end
function db.getent(username)
local f = io.open(db.file)
if f == nil then
return nil
end
for line in f:lines() do
local ent = db.splitent(line)
if ent.name == username then
f:close()
return ent
end
end
f:close()
return nil, db.file..": user '"..tostring(username).."' not found"
end
function db.verify_passwd(cleartext, pwhash)
--[[
from man crypt(3):
If salt is a character string starting with the characters "$id$" fol-
lowed by a string terminated by "$":
$id$salt$encrypted
then instead of using the DES machine, id identifies the encryption
method used and this then determines how the rest of the password
string is interpreted. The following values of id are supported:
ID | Method
---------------------------------------------------------
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
]]--
local algo_salt, hash = string.match(pwhash, "^(%$%d%$[a-zA-Z0-9./]+%$)(.*)")
local userhash = posix.crypt(cleartext, algo_salt)
return (pwhash == userhash)
end
function db.authenticate(username, cleartextpw)
local ent = db.getent(username)
if ent == nil then
return nil, tostring(username)..": no such user"
end
return db.verify_passwd(cleartextpw, ent.passwd)
end
return db
|