From af1942daa1b00abfdd7257b4fcab2f163a30b47f Mon Sep 17 00:00:00 2001 From: Lisa Milne Date: Sat, 16 Dec 2023 13:13:04 +1000 Subject: [PATCH] convert file permissions to using bitwise integer values --- clite/commands.js | 147 +++++++++++++----- clite/core.js | 386 ++++++++++++++++++++++++++++++++++------------ clite/libclite.js | 7 + clite/libstdio.js | 10 ++ readme-libs.txt | 114 ++++++++++---- 5 files changed, 492 insertions(+), 172 deletions(-) diff --git a/clite/commands.js b/clite/commands.js index 20f472a..c5411ae 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -78,13 +78,14 @@ Options: }else{ d = time.strftime('%b %d %H:%M',tm); } + var ms = clite.strmode(st.st_mode); if (st.type == stdio.types.FT_LINK) { var lp = stdio.readAll(fd); if (!lp) lp = '?'; - stdio.printf('%s%12s%12s%14s%12s -> %s\n',st.perms,uname,gname,d,st.name,lp); + stdio.printf('%s%12s%12s%14s%12s -> %s\n',ms,uname,gname,d,st.name,lp); }else{ - stdio.printf('%s%12s%12s%14s%12s\n',st.perms,uname,gname,d,st.name); + stdio.printf('%s%12s%12s%14s%12s\n',ms,uname,gname,d,st.name); } }else if (one) { stdio.printf('%s\n',st.name); @@ -931,6 +932,90 @@ Options: return modmask.join(''); } + function getMode(mode,isdir) { + if (modmask[0] == 'r') { + mode |= stdio.modes.S_IRUSR; + }else if (modmask[0] == '-') { + mode &= ~stdio.modes.S_IRUSR; + } + if (modmask[1] == 'w') { + mode |= stdio.modes.S_IWUSR; + }else if (modmask[1] == '-') { + mode &= ~stdio.modes.S_IWUSR; + } + if (modmask[2] == 'x' || (isdir && modmask[2] == 'X')) { + mode |= stdio.modes.S_IXUSR; + mode &= ~stdio.modes.S_ISUID; + }else if (modmask[2] == 's') { + mode |= stdio.modes.S_IXUSR; + mode |= stdio.modes.S_ISUID; + }else if (modmask[2] == 'S') { + mode &= ~stdio.modes.S_IXUSR; + mode |= stdio.modes.S_ISUID; + }else if (modmask[2] == '-' || (isdir && modmask[2] == 'Y')) { + mode &= ~stdio.modes.S_IXUSR; + mode &= ~stdio.modes.S_ISUID; + } + + if (modmask[3] == 'r') { + mode |= stdio.modes.S_IRGRP; + }else if (modmask[3] == '-') { + mode &= ~stdio.modes.S_IRGRP; + } + if (modmask[4] == 'w') { + mode |= stdio.modes.S_IWGRP; + }else if (modmask[4] == '-') { + mode &= ~stdio.modes.S_IWGRP; + } + if (modmask[5] == 'x' || (isdir && modmask[5] == 'X')) { + mode |= stdio.modes.S_IXGRP; + mode &= ~stdio.modes.S_ISGID; + }else if (modmask[5] == 's') { + mode |= stdio.modes.S_IXGRP; + mode |= stdio.modes.S_ISGID; + }else if (modmask[5] == 'S') { + mode &= ~stdio.modes.S_IXGRP; + mode |= stdio.modes.S_ISGID; + }else if (modmask[5] == '-' || (isdir && modmask[5] == 'Y')) { + mode &= ~stdio.modes.S_IXGRP; + mode &= ~stdio.modes.S_ISGID; + } + + if (modmask[6] == 'r') { + mode |= stdio.modes.S_IROTH; + }else if (modmask[6] == '-') { + mode &= ~stdio.modes.S_IROTH; + } + if (modmask[7] == 'w') { + mode |= stdio.modes.S_IWOTH; + }else if (modmask[7] == '-') { + mode &= ~stdio.modes.S_IWOTH; + } + if (!isdir) { + if (modmask[8] == 'x') { + mode |= stdio.modes.S_IXOTH; + }else if (modmask[8] == '-') { + mode &= ~stdio.modes.S_IXOTH; + } + }else{ + if (modmask[8] == 'x' || modmask[8] == 'X') { + mode |= stdio.modes.S_IXOTH; + mode &= ~stdio.modes.S_ISVTX; + }else if (modmask[8] == 't') { + mode |= stdio.modes.S_IXOTH; + mode |= stdio.modes.S_ISVTX; + }else if (modmask[8] == 'T') { + mode &= ~stdio.modes.S_IXOTH; + mode |= stdio.modes.S_ISVTX; + }else if (modmask[8] == '-' || modmask[8] == 'Y') { + mode &= ~stdio.modes.S_IXOTH; + mode &= ~stdio.modes.S_ISVTX; + } + } + + return mode; + } + function getPerms(str,isdir) { var n = str.substring(1); for (var i=0; i<9; i++) { @@ -1001,9 +1086,9 @@ Options: return 1; } - var perms = getPerms(st.perms,(st.type == stdio.types.FT_DIR)); + var mode = getMode(st.st_mode,(st.type == stdio.types.FT_DIR)); - if (!stdio.chmod(file,perms)) { + if (!stdio.chmod(file,mode)) { stdio.fprintf(io.stderr,'cannot write file: %s\n',short); return 1; } @@ -1608,36 +1693,6 @@ Options: `); } - // TODO: this - // -rwxrwxrwx - function checkReadable(fuid,fgid,perms) { - if (perms[7] == 'r') - return true; - if (perms[4] == 'r' && fgid == stdlib.getgid()) - return true; - if (perms[1] == 'r' && fuid == stdlib.getuid()) - return true; - return false; - } - function checkWritable(fuid,fgid,perms) { - if (perms[8] == 'w') - return true; - if (perms[5] == 'w' && fgid == stdlib.getgid()) - return true; - if (perms[2] == 'w' && fuid == stdlib.getuid()) - return true; - return false; - } - function checkExecutable(fuid,fgid,perms) { - if (perms[9] == 'x') - return true; - if (perms[6] == 'x' && fgid == stdlib.getgid()) - return true; - if (perms[3] == 'x' && fuid == stdlib.getuid()) - return true; - return false; - } - function main(args) { var negate = false; if (args.length == 1) @@ -1777,12 +1832,16 @@ Options: break; case '-r': var p = clite.resolvePath(uargs[1]); - var st = stdio.stat(p); - if (!st || !checkReadable(st.st_uid,st.st_gid,st.perms)) { + var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC); + if (!fd || !stdio.isreadable(fd)) { + if (fd) + stdio.close(fd); if (negate) return 0; return 1; } + if (fd) + stdio.close(fd); if (negate) return 1; return 0; @@ -1846,24 +1905,32 @@ Options: break; case '-w': var p = clite.resolvePath(uargs[1]); - var st = stdio.stat(p); - if (!st || !checkWritable(st.st_uid,st.st_gid,st.perms)) { + var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC); + if (!fd || !stdio.iswritable(fd)) { + if (fd) + stdio.close(fd); if (negate) return 0; return 1; } + if (fd) + stdio.close(fd); if (negate) return 1; return 0; break; case '-x': var p = clite.resolvePath(uargs[1]); - var st = stdio.stat(p); - if (!st || !checkExecutable(st.st_uid,st.st_gid,st.perms)) { + var fd = stdio.open(p,stdio.flags.O_RDONLY|stdio.flags.O_SYNC); + if (!fd || !stdio.isexecutable(fd)) { + if (fd) + stdio.close(fd); if (negate) return 0; return 1; } + if (fd) + stdio.close(fd); if (negate) return 1; return 0; diff --git a/clite/core.js b/clite/core.js index 310eead..54084ab 100644 --- a/clite/core.js +++ b/clite/core.js @@ -135,7 +135,7 @@ var clite = { return true; } }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } // /dev/null - writing to it goes nowhere, reading from it is always null @@ -154,7 +154,7 @@ var clite = { return true; } }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } // /dev/random - writing to it goes nowhere, reading from it returns a stringified random number (integer) @@ -171,7 +171,7 @@ var clite = { }, write:null }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } // /dev/initctl - writing to it sets the runlevel, reading from it returns the current runlevel @@ -214,7 +214,7 @@ var clite = { return false; } }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } // /dev/console - an interface for the system console - required by posix/sus, currently no op @@ -229,7 +229,7 @@ var clite = { read:clite.console.read, write:clite.console.write }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } // /dev/tty - virtual device that always acts like the controlling terminal @@ -244,7 +244,7 @@ var clite = { read:clite.tty.read, write:clite.tty.write }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; n.data.istty = true; } @@ -262,7 +262,7 @@ var clite = { }, write:null }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; } return true; @@ -279,7 +279,7 @@ var clite = { n.data.content = ` PATH=/bin `; - n.perms = '-rw-r--r--'; + 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'); @@ -292,7 +292,7 @@ root:x:0:0:root:/root:/bin/sh guest:x:1:1:guest:/usr/home/guest:/bin/sh `; // TODO: check cookies for a local user - n.perms = '-rw-r--r--'; + n.mode = clite.lib.modestr('-rw-r--r--'); // /etc/passwd contains user account details vfsapi.mkFile(0,'/etc/group'); var n = vfsapi.getNode(0,'/etc/group'); @@ -305,7 +305,7 @@ root:x:0: guest:x:1: `; // TODO: check cookies for a local user - n.perms = '-rw-r--r--'; + 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'); @@ -321,7 +321,7 @@ guest:x:1: | |____| |____ _| |_| || __/ \\_____|______|_____|\\__\\___| `; - n.perms = '-rw-r--r--'; + 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'); @@ -332,7 +332,7 @@ guest:x:1: n.data.content =`#!/bin/sh cat /etc/greeting `; - n.perms = '-rwxr-xr-x'; + n.mode = clite.lib.modestr('-rwxr-xr-x'); } function loadCommands(nextfn) { @@ -343,13 +343,13 @@ cat /etc/greeting var f = vfsapi.getNode(0,'/bin/'+name); if (!f) return; - f.perms = '-rwxr-xr-x'; + f.mode = clite.lib.modestr('-rwxr-xr-x'); f.data.content = fn; vfsapi.mkFile(0,'/usr/src/'+name+'.js'); f = vfsapi.getNode(0,'/usr/src/'+name+'.js'); if (!f) return; - f.perms = '-rw-rw-r--'; + f.mode = clite.lib.modestr('-rw-rw-r--'); f.data.content = 'function main'+fn.toString().substring(8); } } @@ -383,13 +383,13 @@ cat /etc/greeting var f = vfsapi.getNode(0,'/lib/'+name+'.so'); if (!f) return; - f.perms = '-rw-r--r--'; + f.mode = clite.lib.modestr('-rw-r--r--'); f.data.content = fn; vfsapi.mkFile(0,'/usr/src/libs/'+name+'.js'); f = vfsapi.getNode(0,'/usr/src/libs/'+name+'.js'); if (!f) return; - f.perms = '-rw-rw-r--'; + f.mode = clite.lib.modestr('-rw-rw-r--'); f.data.content = 'function init'+fn.toString().substring(8); clite.libs.index.push({header:header,file:name}); } @@ -452,7 +452,7 @@ license.txt:/etc/license:0:0:-rw-r--r--`; return; } n.data.content = data; - n.perms = 'cr--r--r--'; + n.mode = clite.lib.modestr('cr--r--r--'); n.data.isdev = true; var fd = clite.io.open(0,'/dev/wfs',clite.io.flags.O_RDONLY|clite.io.flags.O_SYNC); var l; @@ -481,7 +481,7 @@ license.txt:/etc/license:0:0:-rw-r--r--`; } if (!fn) continue; - fn.perms = perms; + fn.mode = clite.lib.modestr(perms); fn.uid = uid; fn.gid = gid; fn.name = clite.lib.basename(path); @@ -913,7 +913,7 @@ clite.user = { vfsapi.mkDir(0,'/usr/home/guest'); var n = vfsapi.getNode(0,'/usr/home/guest'); if (n) { - n.perms = '-rwx------'; + n.mode = clite.lib.modestr('drwx------'); n.uid = 1; n.gid = 1; } @@ -923,7 +923,7 @@ clite.user = { n = vfsapi.getNode(1,'/usr/home/guest/.shrc'); if (!n) return; - n.perms = '-rwx------'; + n.mode = clite.lib.modestr('-rwx------'); n.uid = 1; n.gid = 1; n.data.content = `#!/bin/sh @@ -995,40 +995,6 @@ clite.io = { init:function() { var vfsapi = clite.vfs.getApi(); - var perms = { - // -rwxrwxrwx user1-3,group4-6,other7-9 - checkReadable:function(p,nuid,ngid,pid) { - var uid = clite.proc.getUID(pid); - if (p[7] == 'r') - return true; - if (clite.user.checkGID(uid,ngid) && p[4] == 'r') - return true; - if (nuid == uid && p[1] == 'r') - return true; - return false; - }, - checkWritable:function(p,nuid,ngid,pid) { - var uid = clite.proc.getUID(pid); - if (p[8] == 'w') - return true; - if (clite.user.checkGID(uid,ngid) && p[5] == 'w') - return true; - if (nuid == uid && p[2] == 'w') - return true; - return false; - }, - checkExecutable:function(p,nuid,ngid,pid) { - var uid = clite.proc.getUID(pid); - if (p[9] == 'x') - return true; - if (clite.user.checkGID(uid,ngid) && p[6] == 'x') - return true; - if (nuid == uid && p[3] == 'x') - return true; - return false; - } - }; - function getFileDesPre(pid,path,link) { var uid = clite.proc.getUID(pid); var n = vfsapi.getNode(uid,path); @@ -1048,9 +1014,9 @@ clite.io = { callback:null } }); - fd.canread = perms.checkReadable(fd.node.perms,fd.node.uid,fd.node.gid,pid); - fd.canwrite = perms.checkWritable(fd.node.perms,fd.node.uid,fd.node.gid,pid); - fd.canexec = perms.checkExecutable(fd.node.perms,fd.node.uid,fd.node.gid,pid); + fd.canread = clite.lib.checkNodeReadable(fd.node,pid); + fd.canwrite = clite.lib.checkNodeWritable(fd.node,pid); + fd.canexec = clite.lib.checkNodeExecutable(fd.node,pid); return fd; } @@ -1400,7 +1366,7 @@ clite.io = { type:clite.lib.getFileType(fd), st_dev:0, st_ino:0, - st_mode:0, + st_mode:fd.node.mode, st_nlink:0, st_uid:fd.node.uid, st_gid:fd.node.gid, @@ -1416,8 +1382,7 @@ clite.io = { st_ctim:{ tv_sec:fd.node.time.change, tv_nsec:0 - }, - perms:fd.node.perms + } }); if (stat.type == clite.io.types.FT_TEXT || stat.type == clite.io.types.FT_SCRIPT) @@ -1426,43 +1391,31 @@ clite.io = { return stat; }, clite.io.fchmod = function(pid,fd,mode) { + if (typeof mode != 'number') + return false; var uid = clite.proc.getUID(pid); if (fd.node.uid != uid) return false; - if (typeof mode !== 'string') - return false; - if (mode.length == 9) { - var c = fd.node.perms[0]; - fd.node.perms = c+mode; - }else if (mode.length != 10) { - return false; - } - if (fd.node.data.isdev) { - fd.node.perms = 'c'+mode.substring(1); - }else if (fd.node.data.isdir) { - fd.node.perms = 'd'+mode.substring(1); - }else if (fd.node.data.islink) { - fd.node.perms = 'l'+mode.substring(1); - }else{ - fd.node.perms = '-'+mode.substring(0); - } + + mode &= ~clite.io.modes.S_IFMT; + mode |= (fd.node.mode&clite.io.modes.S_IFMT); + + fd.node.mode = mode; fd.node.time.change = clite.time.sec(); return true; } clite.io.chmod = function(pid,path,mode) { - var fd = getFileDes(pid,path,true,false); + var fd = getFileDesPre(pid,path,true); return clite.io.fchmod(pid,fd,mode); } clite.io.isatty = function(pid,fd) { return fd.node.data.istty; } clite.io.mkdir = function(pid,path,mode) { - if (typeof mode !== 'string' || mode.length < 9 || mode.length > 10) - mode = 'drwxr-xr-x'; - if (mode.length == 9) - mode = 'd'+mode; - if (mode[0] != 'd') - mode = 'd'+mode.substring(0,9); + if (typeof mode != 'number') + return false; + mode &= ~clite.io.modes.S_IFMT; + mode |= clite.io.modes.S_IFDIR; var uid = clite.proc.getUID(pid); var r = vfsapi.mkDir(uid,path); if (!r) @@ -1470,7 +1423,7 @@ clite.io = { var n = vfsapi.getNode(uid,path); if (!n) return false; - n.perms = mode; + n.mode = mode; return true; } @@ -1871,6 +1824,33 @@ clite.io = { O_TRUNC: parseInt('0x000100',16), // set file size to 0 before writing, requires O_RDWR or O_WRONLY O_TTY_INIT: parseInt('0x0',16) // no op }, + modes:{ + // permissions + S_IRWXU: parseInt('00700',8), // Read, write, execute/search by owner. + S_IRUSR: parseInt('00400',8), // Read permission, owner. + S_IWUSR: parseInt('00200',8), // Write permission, owner. + S_IXUSR: parseInt('00100',8), // Execute/search permission, owner. + S_IRWXG: parseInt('00070',8), // Read, write, execute/search by group. + S_IRGRP: parseInt('00040',8), // Read permission, group. + S_IWGRP: parseInt('00020',8), // Write permission, group. + S_IXGRP: parseInt('00010',8), // Execute/search permission, group. + S_IRWXO: parseInt('00007',8), // Read, write, execute/search by others. + S_IROTH: parseInt('00004',8), // Read permission, others. + S_IWOTH: parseInt('00002',8), // Write permission, others. + S_IXOTH: parseInt('00001',8), // Execute/search permission, others. + S_ISUID: parseInt('04000',8), // Set-user-ID on execution. + S_ISGID: parseInt('02000',8), // Set-group-ID on execution. + S_ISVTX: parseInt('01000',8), // On directories, restricted deletion flag. + // file types + S_IFMT: parseInt('110000',8), // format (file type) mask + S_IFBLK: parseInt('010000',8), // Block special + S_IFCHR: parseInt('020000',8), // Character special + S_IFIFO: parseInt('040000',8), // FIFO special + S_IFREG: parseInt('000000',8), // Regular file + S_IFDIR: parseInt('100000',8), // Directory + S_IFLNK: parseInt('200000',8), // Symbolic link + S_IFSOCK: parseInt('400000',8), // Socket + }, creat:null, open:null, close:null, @@ -1910,22 +1890,22 @@ clite.vfs = { function checkCanOpen(uid,node) { if (!uid) return true; - if (node.perms[7] == 'r') + if ((node.mode&clite.io.modes.S_IROTH) == clite.io.modes.S_IROTH) return true; - if (clite.user.checkGID(uid,node.gid) && node.perms[4] == 'r') + if (clite.user.checkGID(uid,node.gid) && (node.mode&clite.io.modes.S_IRGRP) == clite.io.modes.S_IRGRP) return true; - if (node.uid == uid && node.perms[1] == 'r') + if (node.uid == uid && (node.mode&clite.io.modes.S_IRUSR) == clite.io.modes.S_IRUSR) return true; return false; } function checkCanWrite(uid,node) { if (!uid) return true; - if (node.perms[8] == 'w') + if ((node.mode&clite.io.modes.S_IWOTH) == clite.io.modes.S_IWOTH) return true; - if (clite.user.checkGID(uid,node.gid) && node.perms[5] == 'w') + if (clite.user.checkGID(uid,node.gid) && (node.mode&clite.io.modes.S_IWGRP) == clite.io.modes.S_IWGRP) return true; - if (node.uid == uid && node.perms[2] == 'w') + if (node.uid == uid && (node.mode&clite.io.modes.S_IWUSR) == clite.io.modes.S_IWUSR) return true; return false; } @@ -1934,7 +1914,7 @@ clite.vfs = { name: '', uid: 0, gid: 0, - perms:'-rw-r--r--', + mode:clite.io.modes.S_IRUSR|clite.io.modes.S_IWUSR|clite.io.modes.S_IRGRP|clite.io.modes.S_IROTH, time:{ access:clite.time.sec(), modify:clite.time.sec(), @@ -1957,7 +1937,7 @@ clite.vfs = { vfsdata.fs = mkNode(); vfsdata.fs.data.content = []; vfsdata.fs.data.isdir = true; - vfsdata.fs.perms = 'drwxr-xr-x'; + vfsdata.fs.mode = clite.lib.modestr('drwxr-xr-x'); clite.vfs.getApi = function() { if (clite.state.runlevel == 1) @@ -2015,7 +1995,7 @@ clite.vfs = { n.data.parent = parent; n.data.content = []; n.data.isdir = true; - n.perms = 'drwxr-xr-x'; + n.mode = clite.lib.modestr('drwxr-xr-x'); n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); @@ -2039,7 +2019,7 @@ clite.vfs = { n.name = name; n.data.parent = parent; n.data.content = ''; - n.perms = '-rw-r--r--'; + n.mode = clite.lib.modestr('-rw-r--r--'); n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); @@ -2064,7 +2044,7 @@ clite.vfs = { n.data.parent = parent; n.data.islink = true; n.data.content = target; - n.perms = 'lrw-r--r--'; + n.mode = clite.lib.modestr('lrw-r--r--'); n.uid = uid; n.gid = clite.user.getGID(uid); parent.data.content.push(n); @@ -2127,7 +2107,7 @@ clite.vfs = { var n = vfsdata.api.getNode(0,'/tmp'); if (n) - n.perms = 'drwxrwxrwx'; + n.mode = clite.lib.modestr('drwxrwxrwt'); clite.io.init(); vfsdata.api.isinit = true; @@ -2311,7 +2291,7 @@ clite.tty = { read:function(cb) {return clite.tty.read(n.data.content.ttyid,cb);}, write:function(data) {return clite.tty.write(n.data.content.ttyid,data);} }; - n.perms = 'crw-rw-rw-'; + n.mode = clite.lib.modestr('crw-rw-rw-'); n.data.isdev = true; n.data.istty = true; @@ -2683,6 +2663,216 @@ clite.lib = { } return clite.io.types.FT_UNKOWN; }, + checkNodeReadable:function(node,pid) { + var uid = clite.proc.getUID(pid); + if ((node.mode&clite.io.modes.S_IROTH) == clite.io.modes.S_IROTH) + return true; + if (clite.user.checkGID(uid,node.gid) && (node.mode&clite.io.modes.S_IRGRP) == clite.io.modes.S_IRGRP) + return true; + if (node.uid == uid && (node.mode&clite.io.modes.S_IRUSR) == clite.io.modes.S_IRUSR) + return true; + return false; + }, + checkNodeWritable:function(node,pid) { + var uid = clite.proc.getUID(pid); + if (node.uid == uid && (node.mode&clite.io.modes.S_IWUSR) == clite.io.modes.S_IWUSR) + return true; + // check for directory sticky bit on parent + if (node.parent && (node.parent.mode&clite.io.modes.S_ISVTX) == clite.io.modes.S_ISVTX && node.uid != uid) + return false; + if ((node.mode&clite.io.modes.S_IWOTH) == clite.io.modes.S_IWOTH) + return true; + if (clite.user.checkGID(uid,node.gid) && (node.mode&clite.io.modes.S_IWGRP) == clite.io.modes.S_IWGRP) + return true; + return false; + }, + checkNodeExecutable:function(node,pid) { + var uid = clite.proc.getUID(pid); + if ((node.mode&clite.io.modes.S_IXOTH) == clite.io.modes.S_IXOTH) + return true; + if (clite.user.checkGID(uid,node.gid) && (node.mode&clite.io.modes.S_IXGRP) == clite.io.modes.S_IXGRP) + return true; + if (node.uid == uid && (node.mode&clite.io.modes.S_IXUSR) == clite.io.modes.S_IXUSR) + return true; + return false; + }, + // creates a string from a file mode (0777 -> -rwxrwxrwx) + strmode:function(mode) { + var str = mode.toString(8); + var t = '0'; + var s = '0'; + + var su = false; + var sg = false; + var sd = false; + + var p = ''; + + var perms = ['---','---','---']; + + str = str.padStart(3,'0'); + + if (str.length > 4) { + t = str.substring(0,str.length-4); + str = str.substring(t.length); + } + t = t.padStart(2,'0'); + if (str.length == 4) { + s = str.substring(0,1); + str = str.substring(1); + } + + if (s != '0') { + var si = parseInt(s.padEnd(4,'0'),8); + if ((si & clite.io.modes.S_ISUID) == clite.io.modes.S_ISUID) + su = true; + if ((si & clite.io.modes.S_ISGID) == clite.io.modes.S_ISGID) + sg = true; + if ((si & clite.io.modes.S_ISVTX) == clite.io.modes.S_ISVTX) + sd = true; + } + switch (t) { + case '01': + p = 'b'; + break; + case '02': + p = 'c'; + break; + case '04': + p = 'f'; + break; + case '10': + p = 'd'; + break; + case '20': + p = 'l'; + break; + case '40': + p = 's'; + break; + case '00': + default: + p = '-'; + } + + + for (var i=0; i 0777) + modestr:function(perms) { + var m = 0; + perms = perms.padStart(10,'-'); + if (perms[0] != '-') { + switch (perms[0]) { + case 'b': + m |= clite.io.modes.S_IFBLK; + break; + case 'c': + m |= clite.io.modes.S_IFCHR; + break; + case 'f': + m |= clite.io.modes.S_IFIFO; + break; + case 'd': + m |= clite.io.modes.S_IFDIR; + break; + case 'l': + m |= clite.io.modes.S_IFLNK; + break; + case 's': + m |= clite.io.modes.S_IFSOCK; + break; + default:; + } + } + if (perms[1] == 'r') + m |= clite.io.modes.S_IRUSR; + if (perms[2] == 'w') + m |= clite.io.modes.S_IWUSR; + if (perms[3] == 'x') + m |= clite.io.modes.S_IXUSR; + if (perms[3] == 'S') + m |= clite.io.modes.S_ISUID; + if (perms[3] == 's') { + m |= clite.io.modes.S_IXUSR; + m |= clite.io.modes.S_ISUID; + } + if (perms[4] == 'r') + m |= clite.io.modes.S_IRGRP; + if (perms[5] == 'w') + m |= clite.io.modes.S_IWGRP; + if (perms[6] == 'x') + m |= clite.io.modes.S_IXGRP; + if (perms[6] == 'S') + m |= clite.io.modes.S_ISGID; + if (perms[6] == 's') { + m |= clite.io.modes.S_IXGRP; + m |= clite.io.modes.S_ISGID; + } + if (perms[7] == 'r') + m |= clite.io.modes.S_IROTH; + if (perms[8] == 'w') + m |= clite.io.modes.S_IWOTH; + if (perms[9] == 'x') + m |= clite.io.modes.S_IXOTH; + if (perms[9] == 'T') + m |= clite.io.modes.S_ISVTX; + if (perms[9] == 't') { + m |= clite.io.modes.S_IXOTH; + m |= clite.io.modes.S_ISVTX; + } + + return m; + }, fork:function(env,io,call) { var pid = clite.proc.add(io.pid,call); if (!pid) diff --git a/clite/libclite.js b/clite/libclite.js index 8bc5484..c6d33fd 100644 --- a/clite/libclite.js +++ b/clite/libclite.js @@ -128,6 +128,13 @@ return Object.create({ if (typeof ptr.value === 'undefined') return null; return ptr.value; + }, + + strmode:function(mode) { + return clite.lib.strmode(mode); + }, + modestr:function(perms) { + return clite.lib.modestr(perms); } }); diff --git a/clite/libstdio.js b/clite/libstdio.js index 09a300c..58f0f32 100644 --- a/clite/libstdio.js +++ b/clite/libstdio.js @@ -10,6 +10,7 @@ return Object.create({ types:clite.io.types, flags:clite.io.flags, + modes:clite.io.modes, creat:function(path,type) { return clite.io.creat(io.pid,path,type); @@ -92,6 +93,15 @@ return Object.create({ isatty:function(fd) { return clite.io.isatty(io.pid,fd); }, + isreadable(fd) { + return clite.lib.checkNodeReadable(fd.node,io.pid); + }, + iswritable(fd) { + return clite.lib.checkNodeWritable(fd.node,io.pid); + }, + isexecutable(fd) { + return clite.lib.checkNodeExecutable(fd.node,io.pid); + }, mkdir:function(path,mode) { return clite.io.mkdir(io.pid,path,mode); diff --git a/readme-libs.txt b/readme-libs.txt index 7c08351..16e558d 100644 --- a/readme-libs.txt +++ b/readme-libs.txt @@ -131,6 +131,52 @@ clite (libclite.so): io.include('clite') clite.strToArgs('ls -l /var') -> ['ls','-l','var'] + strmode(mode) + returns a string representation of a file mode such as '-rw-rw-r--'; + + modestr('string') + returns a file mode generated from a permissions string. + + The permission string is a 9 or 10 character string describing the + file permissions. The optional first character describes the + file type, and cannot be changed by calls to chmod(). Attempting + to change the first character will not cause the function to + fail, but only the permissions will be changed. + + 10 character string: -rwxrwxrwx + 9 character string: rwxrwxrwx + + After the optional first character, the mode string is comprised + of 3 sets of permissions for Read, Write, and eXecute, one each + for the user, group, and others. + + - file type + rwx permissions for the file's owner + rwx permissions for users in the file's group + rwx permissions for other users + + Replacing any of the permissions with a dash '-' indicate the + permission is not set: + + -rwxr-xr-- + The user has all permissions, the group has read and execute + permissions, others have only read permissions. + + setuid, setgid are represented by an 's' in the respective + execute field: + + -rwsr-sr-x + The file is executable by all, and the new process will run with + uid and gid set to the file's owner and group ids. + + Sticky bits on directories are represented by a 't' in the other + execute field: + + drwxrwxrwt + The directory is readable, writable, and searchable by all, but + only the file's owner may delete a file in the directory. + + stdio (libio.so): io.include('stdio') Provides access to io functions and types for file access @@ -166,6 +212,34 @@ stdio (libio.so): io.include('stdio') O_TRUNC: set file size to 0 before writing, requires O_RDWR or O_WRONLY O_TTY_INIT: no op + stdio.modes: + object containing values for creating file modes (permissions) + These values may be combined via bitwise OR to create the file permission + S_IRWXU: Read, write, execute/search by owner. + S_IRUSR: Read permission, owner. + S_IWUSR: Write permission, owner. + S_IXUSR: Execute/search permission, owner. + S_IRWXG: Read, write, execute/search by group. + S_IRGRP: Read permission, group. + S_IWGRP: Write permission, group. + S_IXGRP: Execute/search permission, group. + S_IRWXO: Read, write, execute/search by others. + S_IROTH: Read permission, others. + S_IWOTH: Write permission, others. + S_IXOTH: Execute/search permission, others. + S_ISUID: Set-user-ID on execution. + S_ISGID: Set-group-ID on execution. + S_ISVTX: On directories, restricted deletion flag. + A mode may contain one of these values to indicate the file type + S_IFMT: format (file type) mask + S_IFBLK: Block special + S_IFCHR: Character special + S_IFIFO: FIFO special + S_IFREG: Regular file + S_IFDIR: Directory + S_IFLNK: Symbolic link + S_IFSOCK: Socket + creat('path','-') creates a new file at path returns true on success @@ -298,18 +372,11 @@ stdio (libio.so): io.include('stdio') var st = stdio.fstatat(fd,0); Stat object contents: - st.name: string containing the file name - st.type: file type identifier, see stdio.types above for more info - st.uid: numeric id of the file owner - st.gid: numeric id of the file group - st.size: file size, or 0 for non text files - st.perms: the permissions string for the file, see chmod below. - st.name: string containing the file namefd.node.name, st.type: file type identifier, see stdio.types above for more info st.st_dev: device id, always 0 st.st_ino: file serial number, always 0 - st.st_mode: future integer mode (permission) value + st.st_mode: integer mode (permissions) value st.st_nlink: number of hard links to the file, always 0 st.st_uid: numeric id of the file owner st.st_gid: numeric id of the file group @@ -317,36 +384,15 @@ stdio (libio.so): io.include('stdio') st.st_atim: timeval object, the file's last access time st.st_mtim: timeval object, the file's last modify time st.st_ctim: timeval object, the file's last change time - st.perms: the permissions string for the file, see chmod below. - chmod('path','mode') - fchmod(fd,'mode') + chmod('path',mode) + fchmod(fd,mode) Change a file's mode (permissions). Returns true on success. - The mode string is a 9 or 10 character string describing the - file permissions. The optional first character describes the - file type, and cannot be changed. Attempting to change the first - character will not cause the function to fail, but only the - permissions will be changed. - - 10 character string: -rwxrwxrwx - 9 character string: rwxrwxrwx - - After the option first character, the mode string is comprised of - 3 sets of permissions for Read, Write, and eXecute, one each for - the user, group, and others. - - rwx permissions for the file's owner - rwx permissions for users in the file's group - rwx permissions for other users - - Replacing any of the permissions with a dash '-' will remove that - permission from that set: - - rwxr-xr-- - The user has all permissions, the group has read and execute - permissions, others have only read permissions. + mode is an integer value made from a bitwise OR of values in + stdio.modes. Alternatively, the mode can be generated by passing + a permissions string to clite.modestr(). isatty(fd) returns true if fd refers to a tty.