CLIte/clite/user.js

828 lines
16 KiB
JavaScript

clite.commands.data = function() {
clite.commands.load('su',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var clite = io.include('clite');
var auth = io.include('auth');
var term = io.include('term');
var pw = null;
var preserve = true;
var shell = null;
function help() {
stdio.printf(`
su - switch users
Usage: su [OPTION]
Options:
-? Print this help information
-l Simulate a full login
-m Preserve the environment
-s <sh> Use the shell at <sh>
-c Automatically accept cookies when switching users
`);
}
function changeUser() {
if (!stdlib.setgid(pw.pw_gid)) {
stdio.write(io.stderr,'internal error (1)\n');
io.exit(1);
return;
}
if (!stdlib.setuid(pw.pw_uid)) {
stdio.write(io.stderr,'internal error (2)\n');
io.exit(1);
return;
}
var e = null;
if (preserve) {
e = structuredClone(env);
}else{
e = {};
e.USER = pw.pw_name;
e.PWD = pw.pw_dir;
e.HOME = pw.pw_dir;
e.SHELL = pw.pw_shell;
}
if (shell == null)
shell = e.SHELL;
var args = [shell];
var r = stdlib.exec(shell,args,e,io);
if (r == 0)
return;
stdio.write(io.stderr,'internal error (3)\n');
io.exit(1);
}
function doLogin(str) {
term.ttyctrl('echo',true);
if (!auth.checkpassuid(pw.pw_uid,str)) {
stdio.printf('authentication error\n');
io.exit(1);
return;
}
changeUser();
}
function preLogin(str) {
if (str == 'no') {
clite.setcookiestate(false);
io.exit(0);
return;
}
if (str != 'yes') {
cookies();
return;
}
clite.setcookiestate(true);
if (stdlib.getuid() != 0) {
stdio.write(io.stdout,'Password: ');
term.ttyctrl('echo',false);
if (!stdio.read(io.stdin,doLogin)) {
term.ttyctrl('echo',true);
stdio.write(io.stderr,'authentication error\n');
io.exit(1);
}
return;
}
changeUser();
}
function cookies() {
clite.cookienotice();
stdio.printf("Enter 'yes' to agree, or 'no' to cancel: ");
if (!stdio.read(io.stdin,preLogin)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function main(argc,argv) {
var user = 'root';
var shellnext = false;
var accept = false;
for (var i=1; i<argc; i++) {
if (shellnext == true) {
shell = argv[i];
shellnext = false;
}else if (argv[i] == '-') {
preserve = false;
}else if (argv[i][0] == '-') {
for (var j=1; j<argv[i].length; j++) {
switch (argv[i][j]) {
case '?':
help();
return 0;
break;
case 'l':
preserve = false;
break;
case 'm':
preserve = true;
break;
case 's':
shellnext = true;
break;
case 'c':
accept = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',argv[i][j]);
}
}
}else{
user = argv[i];
}
}
if (shellnext) {
stdio.write(io.stderr,'invalid arguments\n');
return 1;
}
if (!user) {
stdio.write(io.stderr,'no user specified\n');
return 1;
}
pw = stdlib.getpwnam(user);
if (!pw) {
stdio.fprintf(io.stderr,'invalid user: %s\n',user);
return 1;
}
if (!stdio.isatty(io.stdin)) {
stdio.write(io.stderr,'internal error\n');
return 1;
}
if (accept || user == 'root' || user == 'guest' || clite.getcookiestate() == true) {
preLogin('yes');
return null;
}
cookies();
return null;
}
return main(args.length,args);
},true);
clite.commands.load('user',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var auth = io.include('auth');
var clite = io.include('clite');
var shell = null;
var group = null;
let user = null;
function help() {
stdio.printf(`
user - manage user accounts
Usage: user <OPTION> [username]
Options:
-? Print this help information
-a Add a new user account
-d Delete a user account
-s <SH> Set the user's default shell to <SH>
-g <GR> Set the user's primary group to <GR>
`);
}
function validateName(n) {
const char = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_';
if (n.length < 2 || n.length > 12)
return false;
if (char.indexOf(n[0]) < 0)
return false;
for (var i=0; i<n.length; i++) {
if (chars.indexOf(n[i]) < 0)
return false;
}
return true;
}
function addUser(user) {
var gid = -1;
if (!validateName(user)) {
stdio.fprintf(io.stderr,'invalid user name: %s\n',user);
return 1;
}
// check user doesn't already exit
var pw = stdlib.getpwnam(user);
if (pw != null) {
stdio.fprintf(io.stderr,'user already exists: %s\n',user);
return 1;
}
// if group is set, check group exists
if (group != null) {
if (!validateName(group)) {
stdio.fprintf(io.stderr,'invalid group name: %s\n',user);
return 1;
}
let gr = stdlib.getgrnam(group);
if (gr == null) {
stdio.fprintf(io.stderr,'cannot assign user to nonexistant group: %s\n',group);
return 1;
}
gr.gr_mem.push(user);
if (!auth.setgrentry(gr)) {
stdio.fprintf(io.stderr,'could not add user to group: %s\n',group);
return 1;
}
gid = gr.gr_gid;
// if group is not set, create a group with the user's name
}else{
let gr = stdlib.getgrnam(user);
if (gr != null) {
stdio.fprintf(io.stderr,'group already exists: %s\n',user);
return 1;
}
gr = {
gr_name:user,
gr_gid:-1,
gr_mem:[user]
};
if (!auth.setgrentry(gr)) {
stdio.fprintf(io.stderr,'could not create group: %s\n',user);
return 1;
}
gr = stdlib.getgrnam(user);
if (gr == null) {
stdio.fprintf(io.stderr,'error creating group: %s\n',user);
return 1;
}
gid = gr.gr_gid;
}
if (gid < 0) {
stdio.fprintf(io.stderr,'error in group setting\n');
return 1;
}
if (shell == null)
shell = '/bin/sh';
// create passwd record
pw = {
pw_name:user,
pw_uid:-1,
pw_gid:gid,
pw_dir:'/usr/home/'+user,
pw_shell:shell
};
if (!auth.setpwentry(pw)) {
stdio.fprintf(io.stderr,'could not create user: %s\n',user);
return 1;
}
pw = stdlib.getpwnam(user);
if (pw == null) {
stdio.fprintf(io.stderr,'error creating user: %s\n',user);
return 1;
}
// create home directory
// set ownership and permission
if (!stdio.mkdir(pw.pw_dir,stdio.modes.S_IRWXU)) {
stdio.fprintf(io.stderr,'could not create home directory: %s\n',pw.pw_dir);
return 1;
}
if (!stdio.chown(pw.pw_dir,pw.pw_uid,pw.pw_gid)) {
stdio.fprintf(io.stderr,'error creating home directory: %s\n',pw.pw_dir);
return 1;
}
// password?
return 0;
}
function delUser(user) {
var pw = stdlib.getpwnam(user);
if (pw == null) {
stdio.fprintf(io.stderr,'user does not exists: %s\n',user);
return 1;
}
// check user is not current user
if (pw.pw_uid == stdlib.getuid() || pw.pw_uid == stdlib.geteuid()) {
stdio.fprintf(io.stderr,'cannot delete current user: %s\n',user);
return 1;
}
// delete passwd entry
if (!auth.removepw(pw.pw_uid)) {
stdio.fprintf(io.stderr,'could not delete user: %s\n',user);
return 1;
}
// delete home directory?
return 0;
}
function preLogin(str) {
if (str == 'no') {
clite.setcookiestate(false);
io.exit(0);
return;
}
if (str != 'yes') {
cookies();
return;
}
clite.setcookiestate(true);
let r = addUser(user);
io.exit(r);
}
function cookies() {
clite.cookienotice();
stdio.printf("Enter 'yes' to agree, or 'no' to cancel: ");
if (!stdio.read(io.stdin,preLogin)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function main(argc,argv) {
let add = false;
let rem = false;
let shellnext = false;
let groupnext = false;
for (var i=1; i<argc; i++) {
if (shellnext == true) {
shell = argv[i];
shellnext = false;
}else if (groupnext == true) {
group = argv[i];
groupnext = false;
}else if (argv[i][0] == '-') {
for (var j=1; j<argv[i].length; j++) {
switch (argv[i][j]) {
case '?':
help();
return 0;
break;
case 'a':
add = true;
break;
case 'd':
rem = true;
break;
case 's':
shellnext = true;
break;
case 'g':
groupnext = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',argv[i][j]);
}
}
}else{
user = argv[i];
}
}
if (user == null) {
stdio.write(io.stderr,'no user specified\n');
return 1;
}
if (user == 'guest' || user == 'root') {
stdio.write(io.stderr,'the guest and root accounts cannot be modified\n');
return 1;
}
if (add) {
if (clite.getcookiestate() == true)
return addUser(user);
cookies();
return null;
}
if (rem)
return delUser(user);
stdio.write(io.stderr,'no option specified\n');
return 1;
}
return main(args.length,args);
},true);
clite.commands.load('login',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var auth = io.include('auth');
var term = io.include('term');
var pw = null;
function help() {
stdio.printf(`
login - user login manager
Usage: login [OPTION]
Options:
-? Print this help information
`);
}
function doLogin(nenv,nio) {
let stdio = nio.include('stdio');
let stdlib = nio.include('stdlib');
if (!stdlib.setgid(pw.pw_gid)) {
stdio.fprintf(nio.stderr,'internal error (1) %d %d\n',stdlib.geteuid(),stdlib.getegid());
nio.exit(1);
return;
}
if (!stdlib.setuid(pw.pw_uid)) {
stdio.write(nio.stderr,'internal error (2)\n');
nio.exit(1);
return;
}
var r = stdlib.exec(pw.pw_shell,[pw.pw_shell],env,nio);
if (r == 0)
return;
stdio.write(nio.stderr,'internal error (3)\n');
nio.exit(1);
}
function preLogin() {
env.USER = pw.pw_name;
env.PWD = pw.pw_dir;
env.HOME = pw.pw_dir;
env.SHELL = pw.pw_shell;
var pid = stdlib.fork(env,io,doLogin);
if (pid < 1) {
getUser();
return;
}
stdlib.waitpid(pid,getUser);
}
function setPass(pass) {
if (pass == String.fromCharCode(4) || pass == 4) {
getUser();
return;
}
if (auth.checkpassuid(pw.pw_uid,pass)) {
preLogin();
return;
}
getUser();
}
function getPass() {
stdio.write(io.stdout,'Password: ');
term.ttyctrl('echo',false);
var r = stdio.read(io.stdin,function(p) {
term.ttyctrl('echo',true);
setPass(p);
});
if (!r)
getUser();
}
function setUser(name) {
if (name == String.fromCharCode(4) || name == 4) {
getUser();
return;
}
pw = stdlib.getpwnam(name);
if (!pw) {
getUser();
return;
}
if (name == 'guest') {
preLogin();
return;
}
getPass();
}
function getUser() {
term.clear();
stdio.write(io.stdout,'Username: ');
if (!stdio.read(io.stdin,setUser))
stdio.write(io.stderr,'internal error\n');
}
function main(argc,argv) {
let user = null;
for (var i=1; i<argc; i++) {
if (argv[i][0] == '-') {
for (var j=1; j<argv[i].length; j++) {
switch (argv[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',argv[i][j]);
}
}
}else{
user = argv[i];
}
}
if (!stdio.isatty(io.stdin) || !stdio.isatty(io.stdout)) {
stdio.fprintf(io.stderr,'invalid tty\n');
return 1;
}
if (stdlib.geteuid() != 0) {
stdio.fprintf(io.stderr,'requires root\n');
return 1;
}
term.ttyctrl('sane');
if (user != null) {
setUser(user);
return null;
}
getUser();
return null;
}
return main(args.length,args);
});
clite.commands.load('cookie',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var clite = io.include('clite');
function help() {
stdio.printf(`
cookie - set cookie options
Usage: cookie [OPTION]
Options:
-? Print this help information
-a Accept all cookies and local storage
-r Reject all cookies and local storage
-c Check the current state of cookies
`);
}
function checkState(str) {
if (str == 'no') {
clite.setcookiestate(false);
io.exit(0);
return;
}
if (str != 'yes') {
cookies();
return;
}
clite.setcookiestate(true);
io.exit(0);
}
function cookies() {
clite.cookienotice();
stdio.printf("Enter 'yes' to agree, or 'no' to cancel: ");
if (!stdio.read(io.stdin,checkState)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function main(argc,argv) {
let accept = false;
let reject = false;
let check = false;
for (var i=1; i<argc; i++) {
if (argv[i][0] == '-') {
for (var j=1; j<argv[i].length; j++) {
switch (argv[i][j]) {
case '?':
help();
return 0;
break;
case 'a':
accept = true;
break;
case 'c':
check = true;
break;
case 'r':
reject = true;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',argv[i][j]);
}
}
}else{
stdio.fprintf(io.stderr,'unknown argument: %s\n',argv[i]);
}
}
if (reject) {
clite.setcookiestate(false);
return 0;
}
if (accept) {
clite.setcookiestate(true);
return 0;
}
if (check) {
let s = clite.getcookiestate();
if (s == false) {
stdio.write(io.stdout,"Cookies are currently being rejected\n");
}else if (s == true) {
stdio.write(io.stdout,"Cookies are currently being accepted\n");
}else{
stdio.write(io.stdout,"You have not set a cookie preference (rejected by default)\n");
}
return 0;
}
cookies();
return null;
}
return main(args.length,args);
});
clite.commands.load('passwd',function(args,env,io) {
var stdio = io.include('stdio');
var stdlib = io.include('stdlib');
var term = io.include('term');
var auth = io.include('auth');
var user = null;
function help() {
stdio.printf(`
passwd - set user passwords
Usage: passwd [OPTION] [USER]
Options:
-? Print this help information
`);
}
function setPass(pass) {
if (pass == String.fromCharCode(4) || pass == 4) {
io.exit(1);
return;
}
if (!auth.setpassnam(user,pass)) {
stdio.write(io.stderr,'internal error\n');
io.exit(1);
return;
}
io.exit(0);
}
function getPass() {
stdio.write(io.stdout,'New Password: ');
term.ttyctrl('echo',false);
var r = stdio.read(io.stdin,function(p) {
term.ttyctrl('echo',true);
setPass(p);
});
if (!r) {
term.ttyctrl('echo',true);
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function checkPass(str) {
if (str == String.fromCharCode(4) || str == 4) {
io.exit(1);
return;
}
if (!auth.checkpassnam(user,str)) {
stdio.write(io.stderr,'authentication error\n');
io.exit(1);
return;
}
getPass();
}
function getCurPass() {
stdio.write(io.stdout,'Current Password: ');
term.ttyctrl('echo',false);
var r = stdio.read(io.stdin,function(p) {
term.ttyctrl('echo',true);
checkPass(p);
});
if (!r) {
term.ttyctrl('echo',true);
stdio.write(io.stderr,'internal error\n');
io.exit(1);
}
}
function main(argc,argv) {
for (var i=1; i<argc; i++) {
if (argv[i][0] == '-') {
for (var j=1; j<argv[i].length; j++) {
switch (argv[i][j]) {
case '?':
help();
return 0;
break;
default:
stdio.fprintf(io.stderr,'unknown argument: -%c\n',argv[i][j]);
}
}
}else{
user = argv[i];
}
}
if (!user) {
let uid = stdlib.getuid();
let pw = stdlib.getpwuid(uid);
if (pw)
user = pw.pw_name;
}else{
let pw = stdlib.getpwnam(user);
if (!pw)
user = null;
}
if (!user || user == 'guest') {
stdio.fprintf(io.stderr,'no valid user specified\n');
return 1;
}
stdio.printf('Changing password for user %s\n',user);
if (stdlib.geteuid() != 0) {
getCurPass();
return null;
}
getPass();
return null;
}
return main(args.length,args);
});
}