diff --git a/clite/core.js b/clite/core.js index d0dccc3..dbe700c 100644 --- a/clite/core.js +++ b/clite/core.js @@ -9,7 +9,7 @@ var clite = { // a list of program/command files to load prog:['commands.js','shell.js','vi.js'], // a list of library files to load - libs:['libclite.js','libcurses.js','libstd.js','libstdio.js','libterm.js','libtime.js'] + libs:['libclite.js','libcurses.js','libstd.js','libstdio.js','libterm.js','libtime.js','libauth.js'] }, time:{ sec:function() { @@ -270,32 +270,38 @@ var clite = { function defaultConfig() { // /etc/env contains the default environment variables + { vfsapi.mkFile(0,'/etc/env'); - var n = vfsapi.getNode(0,'/etc/env'); + let n = vfsapi.getNode(0,'/etc/env'); if (!n) { clite.log.write('environment failure'); return false; } n.data.content = ` PATH=/bin +EDITOR=/bin/vi `; n.mode = clite.lib.modestr('-rw-r--r--'); + } // /etc/passwd contains user account details + { vfsapi.mkFile(0,'/etc/passwd'); - var n = vfsapi.getNode(0,'/etc/passwd'); + let n = vfsapi.getNode(0,'/etc/passwd'); if (!n) { clite.log.write('access config failure'); return false; } n.data.content = ` -root:x:0:0:root:/root:/bin/sh +root:$-7a1c0437:0:0:root:/root:/bin/sh guest:x:1:1:guest:/usr/home/guest:/bin/sh `; // TODO: check cookies for a local user - n.mode = clite.lib.modestr('-rw-r--r--'); - // /etc/passwd contains user account details + n.mode = clite.lib.modestr('-rw-------'); + } + // /etc/group contains group details + { vfsapi.mkFile(0,'/etc/group'); - var n = vfsapi.getNode(0,'/etc/group'); + let n = vfsapi.getNode(0,'/etc/group'); if (!n) { clite.log.write('group config failure'); return false; @@ -306,9 +312,11 @@ guest:x:1: `; // TODO: check cookies for a local user n.mode = clite.lib.modestr('-rw-r--r--'); + } // /etc/greeting is displayed by the shell after login + { vfsapi.mkFile(0,'/etc/greeting'); - var n = vfsapi.getNode(0,'/etc/greeting'); + let n = vfsapi.getNode(0,'/etc/greeting'); if (!n) { clite.log.write('config failure'); return false; @@ -322,9 +330,11 @@ guest:x:1: \\_____|______|_____|\\__\\___| `; n.mode = clite.lib.modestr('-rw-r--r--'); + } // /etc/shrc shell startup file + { vfsapi.mkFile(0,'/etc/shrc'); - var n = vfsapi.getNode(0,'/etc/shrc'); + let n = vfsapi.getNode(0,'/etc/shrc'); if (!n) { clite.log.write('shell config failure'); return false; @@ -333,6 +343,7 @@ guest:x:1: cat /etc/greeting `; n.mode = clite.lib.modestr('-rwxr-xr-x'); + } } function loadCommands(nextfn) { @@ -802,6 +813,7 @@ clite.user = { var data = { users:[{ name:'root', + pass:'', uid:0, gid:0, groups:[], @@ -831,6 +843,10 @@ clite.user = { } return null; } + function saveUsers() { + // TODO: write /etc/passwd and /etc/group + // TODO: write all non-root and non-guest lines to cookies + } function loadUsers() { // load in user data from /etc/passwd var n = vfsapi.getFile(0,'/etc/passwd'); @@ -842,7 +858,7 @@ clite.user = { return; var sects = line.split(':'); // 0 username - // 1 null + // 1 password hash // 2 uid // 3 gid // 4 real name @@ -858,6 +874,9 @@ clite.user = { } udata.name = sects[0]; + udata.pass = sects[1]; + if (udata.pass[0] == '$') + udata.pass = udata.pass.substring(1); udata.uid = parseInt(sects[2]); udata.gid = parseInt(sects[3]); udata.groups = []; @@ -971,6 +990,76 @@ cat -l /usr/share/introduction pw_shell:udata.env.SHELL // Program to use as shell. }); } + clite.user.getPWDataInd = function(i) { + if (i >= data.user.length) + return null; + + var udata = data.users[i]; + + return Object.create({ + pw_name:udata.name, // User's login name. + pw_uid:udata.uid, // Numerical user ID. + pw_gid:udata.gid, // Numerical group ID. + pw_dir:udata.env.HOME, // Initial working directory. + pw_shell:udata.env.SHELL // Program to use as shell. + }); + } + clite.user.setPWData = function(pid,pw) { + if (typeof pw.pw_name !== 'string') + return false; + if (typeof pw.pw_uid !== 'number') + return false; + if (typeof pw.pw_gid !== 'number') + return false; + var gr = clite.user.getGRData(pw.pw_gid); + if (gr == null) + return false; + if (typeof pw.pw_dir !== 'string') + return false; + if (typeof pw.pw_shell !== 'string') + return false; + loadUsers(); + if (pw.pw_uid < 0) { + if (clite.user.mapUserName(pw.pw_name) > -1) + return false; + var udata = {}; + udata.name = pw.pw_name; + udata.pass = 'x'; + // TODO: this could cause 2 users with the same uid + udata.uid = data.users.length; + udata.gid = pw.pw_gid; + udata.groups = []; + udata.env = {}; + udata.env.HOME = pw.pw_dir; + udata.env.SHELL = pw.pw_shell; + udata.env.USER = udata.name; + udata.env.PWD = udata.env.HOME; + + data.users.push(udata); + + saveUsers(); + loadUsers(); + return true; + } + var uid = clite.proc.getUID(pid); + if (pw.pw_uid != uid && uid != 0) + return false; + + var udata = getUser(pw.pw_uid); + if (!udata) + return false; + udata.name = pw.pw_name; + udata.uid = pw.pw_uid; + udata.gid = pw.pw_gid; + udata.env.HOME = pw.pw_dir; + udata.env.SHELL = pw.pw_shell; + udata.env.USER = udata.name; + udata.env.PWD = udata.env.HOME; + + saveUsers(); + loadUsers(); + return true; + } clite.user.getGRData = function(gid) { var gdata = getGroup(gid); if (!gdata) @@ -982,6 +1071,54 @@ cat -l /usr/share/introduction gr_mem:gdata.users // array of member names. }); } + clite.user.getGRDataInd = function(i) { + if (i >= data.groups.length) + return null; + + var gdata = data.groups[i]; + + return Object.create({ + gr_name:gdata.name, // The name of the group. + gr_gid:gdata.gid, // Numerical group ID. + gr_mem:gdata.users // array of member names. + }); + } + clite.user.setGRData = function(pid,gr) { + if (typeof gr.gr_name !== 'string') + return false; + if (typeof gr.gr_gid !== 'number') + return false; + if (!Array.isArray(gr.gr_mem)) + return false; + loadUsers(); + if (gr.gr_gid < 0) { + if (clite.user.mapGroupName(gr.gr_name) > -1) + return false; + var gdata = {}; + gdata.name = gr.gr_name; + // TODO: this could cause 2 groups with the same gid + gdata.gid = data.groups.length; + gdata.users = Array.from(gr.gr_mem); + data.groups.push(gdata); + saveUsers(); + loadUsers(); + + return true; + } + var uid = clite.proc.getUID(pid); + if (!clite.user.checkGID(uid,gr.gr_gid) && uid != 0) + return false; + var gdata = getGroup(gr.gr_gid); + if (!gdata) + return false; + gdata.name = gr.gr_name; + gdata.gid = gr.gr_gid; + gdata.users = Array.from(gr.gr_mem); + + saveUsers(); + loadUsers(); + return true; + } clite.user.mapUserName = function(name) { for (var i=0; i -rwxrwxrwx) strmode:function(mode) { var str = mode.toString(8); diff --git a/clite/libauth.js b/clite/libauth.js new file mode 100644 index 0000000..c374e6a --- /dev/null +++ b/clite/libauth.js @@ -0,0 +1,39 @@ +clite.libs.data = function() { + +clite.libs.load('libauth','auth',function(io,env) { + +return Object.create({ + + setpwentry:function(pw) { + return clite.user.setPWData(io.pid,pw); + }, + + setgrentry:function(gr) { + return clite.user.setGRData(io.pid,gr); + }, + + setpassuid:function(uid, pass) { + return clite.user.setPasswd(io.pid,uid,pass); + }, + setpassnam:function(name, pass) { + var uid = clite.user.mapUserName(name); + if (uid < 0) + return false; + return clite.user.setPasswd(io.pid,uid,pass); + }, + + checkpassuid:function(uid, pass) { + return clite.user.checkPasswd(uid,pass); + }, + checkpassnam:function(name, pass) { + var uid = clite.user.mapUserName(name); + if (uid < 0) + return false; + return clite.user.checkPasswd(uid,pass); + } + +}); + +}); + +} diff --git a/clite/libstd.js b/clite/libstd.js index a7f1293..4a09dcb 100644 --- a/clite/libstd.js +++ b/clite/libstd.js @@ -2,6 +2,9 @@ clite.libs.data = function() { clite.libs.load('libstd','stdlib',function(io,env) { + var pwentind = 0; + var grentind = 0; + return Object.create({ // returns the file name of a path /tmp/test/foo = foo @@ -17,6 +20,10 @@ return Object.create({ return parts.join('/'); }, + crypt:function(str,salt) { + return clite.lib.hash(str.toString()+':'+salt.toString()); + }, + // returns system info uname:function() { return Object.create({ @@ -47,8 +54,11 @@ return Object.create({ getuid:function() { return clite.proc.getUID(io.pid); }, - setuid:function(id) { - return clite.proc.setUID(io.pid,id,false); + setuid:function(uid) { + return clite.proc.setUID(io.pid,uid,false); + }, + setreuid:function(ruid,euid) { + return clite.proc.setGID(io.pid,euid,false); }, // gets the passwd file data for a user based on their uid @@ -62,13 +72,36 @@ return Object.create({ return null; return clite.user.getPWData(uid); }, + endpwent:function() {}, + getpwent:function() { + var e = clite.user.getPWDataInd(pwentind); + if (e !== null) + grentind++; + return e; + }, + setpwent:function() { + pwentind = 0; + }, // returns the current group id getgid:function() { return clite.proc.getGID(io.pid); }, - setgid:function(id) { - return clite.proc.setGID(io.pid,id,false); + setgid:function(gid) { + return clite.proc.setGID(io.pid,gid,false); + }, + setregid:function(rgid,egid) { + return clite.proc.setGID(io.pid,egid,false); + }, + endgrent:function() {}, + getgrent:function() { + var e = clite.user.getGRDataInd(grentind); + if (e !== null) + grentind++; + return e; + }, + setgrent:function() { + grentind = 0; }, // gets teh group file data for a group based on their gid