local a=...local b={}a.auth=b;local function c(d)local e=a.vfs.open(d,"r")if not e then error("Failed to open file: "..d)end;local f=a.vfs.read(e,1024000)a.vfs.close(e)return f end;local function g(d,f)local e=a.vfs.open(d,"w")if not e then error("Failed to open file for writing: "..d)end;a.vfs.write(e,f)a.vfs.close(e)end;local h;do local i=2^32;local function j(k)return k%i end;local function l(k)k=j(k)local m={}for n=0,31 do local o=k%2;m[n]=o;k=(k-o)/2 end;return m end;local function p(m)local k,q=0,1;for n=0,31 do if m[n]==1 then k=k+q end;q=q*2 end;return j(k)end;local function r(...)local s={...}if#s==0 then return 0 end;local t=l(s[1])for n=2,#s do local o=l(s[n])for u=0,31 do t[u]=(t[u]==1 or o[u]==1)and 1 or 0 end end;return p(t)end;local function v(...)local s={...}if#s==0 then return 0 end;local t=l(s[1])for n=2,#s do local o=l(s[n])for u=0,31 do t[u]=t[u]~=o[u]and 1 or 0 end end;return p(t)end;local function w(k,x)return j(j(k)*2^x)end;local function y(k,x)return math.floor(j(k)/2^x)end;local function z(k,x)return r(y(k,x),w(k,32-x))end;local A={0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19}local B={{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}}local function C(D,E,o,F,G,k,H)D[E]=(D[E]+D[o]+k)%i;D[G]=z(v(D[G],D[E]),16)D[F]=(D[F]+D[G])%i;D[o]=z(v(D[o],D[F]),12)D[E]=(D[E]+D[o]+H)%i;D[G]=z(v(D[G],D[E]),8)D[F]=(D[F]+D[G])%i;D[o]=z(v(D[o],D[F]),7)end;local function I(J,K,m,L)local D={}for n=1,8 do D[n]=J[n]end;for n=1,8 do D[n+8]=A[n]end;D[13]=v(D[13],m)if L then D[15]=v(D[15],0xFFFFFFFF)end;local M={}for n=0,15 do local q=n*4+1;M[n]=(K:byte(q)or 0)+(K:byte(q+1)or 0)*0x100+(K:byte(q+2)or 0)*0x10000+(K:byte(q+3)or 0)*0x1000000 end;for N=1,10 do local O=B[N]C(D,1,5,9,13,M[O[1]],M[O[2]])C(D,2,6,10,14,M[O[3]],M[O[4]])C(D,3,7,11,15,M[O[5]],M[O[6]])C(D,4,8,12,16,M[O[7]],M[O[8]])C(D,1,6,11,16,M[O[9]],M[O[10]])C(D,2,7,12,13,M[O[11]],M[O[12]])C(D,3,8,9,14,M[O[13]],M[O[14]])C(D,4,5,10,15,M[O[15]],M[O[16]])end;for n=1,8 do J[n]=v(J[n],D[n],D[n+8])end end;function h(P,Q)Q=Q or""local J={}for n=1,8 do J[n]=A[n]end;local R=32;J[1]=v(J[1],0x01010000+w(#Q,8)+R)local m=0;if#Q>0 then local K=Q..string.rep("\0",64-#Q)m=#Q;I(J,K,m,false)end;for n=1,#P,64 do local K=P:sub(n,n+63)if#K<64 then K=K..string.rep("\0",64-#K)end;m=m+math.min(64,#P-n+1)I(J,K,m,n+64>#P)end;local S=""for n=1,8 do S=S..string.format("%08x",J[n])end;return S end end;if not h then error("Failed to load blake2s")end;if not a.vfs.exists("/etc/pam.d/secret")then a.log("PAM SECRET REGENERATING PLEASE USE ROOT","WARN",0xFF8800)local Q=""for n=1,256 do Q=Q..string.char(math.random(0,255))end;local T=a.vfs.open("/etc/pam.d/secret","w")a.vfs.write(T,Q)a.vfs.close(T)end;local U=c("/etc/pam.d/secret")local function V()return toHex(math.random(0,2^32))end;local function W(X,Y)local Q=U..Y;return h(X,Q)end;local Z=c("/etc/passwd")local _=c("/etc/shadow")local a0=string.split(Z,"\n")local a1=string.split(_,"\n")local a2,a3={},{}for a4,D in ipairs(a0)do local a5=string.split(D,":")if a5[1]and a5[1]~=""then a2[#a2+1]=a5 end end;for a4,D in ipairs(a1)do local a5=string.split(D,":")if a5[1]and a5[1]~=""then a3[#a3+1]=a5 end end;for a4,D in ipairs(a2)do local a6=tonumber(D[1])if a6 then a.users[a6]=D[3]end end;a.passwd=a2;local function a7()local a8={}for a4,D in ipairs(a2)do a8[#a8+1]=table.concat(D,":")end;g("/etc/passwd",table.concat(a8,"\n"))end;local function a9()local a8={}for a4,D in ipairs(a3)do a8[#a8+1]=table.concat(D,":")end;g("/etc/shadow",table.concat(a8,"\n"))end;local function aa(a6)for a4,D in ipairs(a2)do if tonumber(D[1])==a6 then return D end end;return nil end;local function ab(a6)for a4,D in ipairs(a3)do if tonumber(D[1])==a6 then return D end end;return nil end;local function ac(ad)for a4,D in ipairs(a2)do if D[3]==ad then return D end end;return nil end;local function ae()local af=999;for a4,D in ipairs(a2)do local a6=tonumber(D[1])if a6 and a6>=1000 and a6>af then af=a6 end end;return af+1 end;function b.login(a6,X)if type(a6)~="number"or type(X)~="string"then return nil,"Authentication failure"end;local ag=aa(a6)if not ag then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local ah=ab(a6)if not ah then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local Y=ah[2]local ai=ah[3]local aj=W(X,Y)if aj~=ai then return nil,"Authentication failure"end;a.currentUID=a6;local ak=a.currentTask;if ak then ak.uid=a6;ak.euid=a6;ak.gid=tonumber(ag[2])or a6;ak.egid=tonumber(ag[2])or a6 end;a.log("AUTH: login uid="..tostring(a6).." ("..aa(a6)[3]..")")return true end;function b.setPassword(a6,al)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 and am~=a6 then return nil,"Permission denied"end;if type(al)~="string"or#al==0 then return nil,"Password may not be empty"end;if#al<6 then return nil,"Password is too short (minimum 6 characters)"end;local Y=V()local an=W(al,Y)local ah=ab(a6)if ah then ah[2]=Y;ah[3]=an else a3[#a3+1]={tostring(a6),Y,an}end;a9()a.log("AUTH: password changed for uid="..tostring(a6))return true end;function b.setUsername(a6,ao)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ao)~="string"or#ao==0 then return nil,"Invalid username"end;if not ao:match("^[a-z_][a-z0-9_%-]*$")or#ao>32 then return nil,"Invalid username format"end;if ac(ao)then return nil,"Username already taken"end;local ag=aa(a6)if not ag then return nil,"No such user"end;local ap=ag[3]ag[3]=ao;a.users[a6]=ao;a7()a.log("AUTH: uid="..tostring(a6).." renamed '"..ap.."' → '"..ao.."'")return true end;function b.newUser(ad,X,aq,ar,as)local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ad)~="string"or#ad==0 then return nil,"Invalid username"end;if not ad:match("^[a-z_][a-z0-9_%-]*$")or#ad>32 then return nil,"Invalid username format"end;if ac(ad)then return nil,"Username already exists"end;if type(X)~="string"or#X<6 then return nil,"Password is too short (minimum 6 characters)"end;local a6=ae()aq=tonumber(aq)or a6;ar=ar or"/home/"..ad;as=as or"/bin/hysh"a2[#a2+1]={tostring(a6),tostring(aq),ad,ar,as}a.users[a6]=ad;local Y=V()local an=W(X,Y)a3[#a3+1]={tostring(a6),Y,an}a7()a9()if a.vfs.mkdir and not a.vfs.exists(ar)then a.vfs.mkdir(ar)pcall(a.vfs.chown,ar,a6,a6)end;a.log("AUTH: new user '"..ad.."' uid="..tostring(a6))return a6 end;function b.whoami()local a6=a.currentProcess and a.currentProcess.euid or a.currentUID;if not a6 then return nil,"Not logged in"end;return a.users[a6]or"uid="..tostring(a6)end;function b.getUID(ad)local ag=ac(ad)if ag then return tonumber(ag[1])end;return nil end;function b.getPasswd(a6)a6=tonumber(a6)local ag=aa(a6)if not ag then return nil end;return{uid=tonumber(ag[1]),gid=tonumber(ag[2]),username=ag[3],homedir=ag[4],shell=ag[5]}end;function b.deleteUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if a6==0 then return nil,"Cannot delete root"end;local ag=aa(a6)if not ag then return nil,"No such user"end;local ad=ag[3]for n,D in ipairs(a2)do if tonumber(D[1])==a6 then table.remove(a2,n)break end end;for n,D in ipairs(a3)do if tonumber(D[1])==a6 then table.remove(a3,n)break end end;a.users[a6]=nil;a7()a9()a.log("AUTH: deleted user '"..ad.."' uid="..tostring(a6))return true end;function b.lockUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if a6==0 then return nil,"Cannot lock root"end;local ah=ab(a6)if not ah then return nil,"No shadow entry for uid"end;if ah[3]:sub(1,1)~="!"then ah[3]="!"..ah[3]end;a9()a.log("AUTH: locked uid="..tostring(a6))return true end;function b.unlockUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;local ah=ab(a6)if not ah then return nil,"No shadow entry for uid"end;if ah[3]:sub(1,1)=="!"then ah[3]=ah[3]:sub(2)end;a9()a.log("AUTH: unlocked uid="..tostring(a6))return true end;function b.listUsers()local at={}for a4,D in ipairs(a2)do local a6=tonumber(D[1])local ah=ab(a6)local au=ah and ah[3]:sub(1,1)=="!"at[#at+1]={uid=a6,gid=tonumber(D[2]),username=D[3],homedir=D[4],shell=D[5],locked=au or false}end;return at end;function b.setShell(a6,as)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 and am~=a6 then return nil,"Permission denied"end;if type(as)~="string"or#as==0 then return nil,"Invalid shell"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[5]=as;a7()a.log("AUTH: uid="..tostring(a6).." shell -> "..as)return true end;function b.setHomedir(a6,ar)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ar)~="string"or#ar==0 then return nil,"Invalid homedir"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[4]=ar;a7()a.log("AUTH: uid="..tostring(a6).." homedir -> "..ar)return true end;function b.setGID(a6,aq)a6=tonumber(a6)aq=tonumber(aq)if not a6 or not aq then return nil,"Invalid uid or gid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[2]=tostring(aq)a7()a.log("AUTH: uid="..tostring(a6).." gid -> "..tostring(aq))return true end;function b.elevate(av,X)if type(av)~="string"or type(X)~="string"then return nil,"Authentication failure"end;local ag=ac(av)if not ag then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local a6=tonumber(ag[1])local ah=ab(a6)if not ah then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local aj=W(X,ah[2])if aj~=ah[3]then return nil,"Authentication failure"end;local aw=a.currentTask;local ax=aw.uid;aw.uid=0;aw.euid=0;aw.gid=0;aw.egid=0;a.uid=0;a.log("AUTH: elevate uid="..tostring(ax).." -> 0 (via "..av..")")return true,a6 end;if a.syscalls then a.syscalls["login"]=b.login;a.syscalls["setpassword"]=b.setPassword;a.syscalls["setusername"]=b.setUsername;a.syscalls["newuser"]=b.newUser;a.syscalls["whoami"]=b.whoami;a.syscalls["getuidbyname"]=b.getUID;a.syscalls["getpasswd"]=b.getPasswd;a.syscalls["elevate"]=b.elevate;a.syscalls["deleteuser"]=b.deleteUser;a.syscalls["lockuser"]=b.lockUser;a.syscalls["unlockuser"]=b.unlockUser;a.syscalls["listusers"]=b.listUsers;a.syscalls["setshell"]=b.setShell;a.syscalls["sethomedir"]=b.setHomedir;a.syscalls["setgid"]=b.setGID end