CLIte/clite/user.js
2023-12-17 14:11:07 +10:00

414 lines
8 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') {
io.exit(0);
return;
}
if (str != 'yes') {
cookies();
return;
}
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(args) {
var user = 'root';
var shellnext = false;
var accept = false;
for (var i=1; i<args.length; i++) {
if (shellnext == true) {
shell = args[i];
shellnext = false;
}else if (args[i] == '-') {
preserve = false;
}else if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[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',args[i][j]);
}
}
}else{
user = args[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') {
preLogin('yes');
return null;
}
cookies();
return null;
}
return main(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 shell = null;
var group = 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 main(args) {
let add = false;
let rem = false;
let user = null;
let shellnext = false;
let groupnext = false;
for (var i=1; i<args.length; i++) {
if (shellnext == true) {
shell = args[i];
shellnext = false;
}else if (groupnext == true) {
group = args[i];
groupnext = false;
}else if (args[i][0] == '-') {
for (var j=1; j<args[i].length; j++) {
switch (args[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',args[i][j]);
}
}
}else{
user = args[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)
return addUser(user);
if (rem)
return delUser(user);
stdio.write(io.stderr,'no option specified\n');
return 1;
}
return main(args);
},true);
}