#!/usr/bin/nesla

/*
 * CMS sample prog by Dan Cahill
 * This is the Crappy Management system.
 * It lets you browse the filesystem, execute shell commands, and edit files,
 * and since there's no security, it lets everyone else do it, too... :-)
 *
 * build nesla.cgi and put it in /cgi-bin/
 * make a .htaccess file, add these three lines,
 *
 * Options +ExecCGI
 * AddHandler nes-script .ns
 * Action nes-script /cgi-bin/nesla.cgi
 * DirectoryIndex index.html index.ns index.php
 *
 * and that's about it..
 *
 * the most likely problem is file permissions, but you're on your own there.
 */

// This thing has serious limits that make its usefulness rather limited.

global MASTERPASSWORD="nesla";
if (typeof(_SERVER)!='table') exit;

function dologin() {
        var user="nobody";
        var pass=MASTERPASSWORD;

print("<HTML>
<TITLE>Nesla - Crappy Management system</TITLE>
<HEAD>
<STYLE TYPE=text/css>
A        { color: #0000FF; text-decoration: none; }
A:HOVER  { background-color: #E0E0FF; }
</STYLE>
</HEAD>
<BODY>
<CENTER>
<FORM ACTION='", _SERVER['PATH_INFO'], "' METHOD='POST' NAME='login'>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR><TD><B>&nbsp;Username&nbsp;</B></TD><TD><INPUT SIZE=50 style='width:200px' NAME='username' VALUE='", user, "'></TD></TR>
<TR><TD><B>&nbsp;Password&nbsp;</B></TD><TD><INPUT SIZE=50 style='width:200px' NAME='password' VALUE='", pass, "' TYPE=password></TD></TR>
<TR><TD ALIGN=CENTER COLSPAN=2><input type='submit' value='login' name='submit'></TD></TR>
</TABLE>
</FORM>
</CENTER>
</BODY>
</HTML>
");
        exit;
}
if (_POST['PASSWORD']!=null) {
        _GET['DOWNLOAD']='';
        if (_POST['PASSWORD']==MASTERPASSWORD) {
//		printf("Set-Cookie: wminfo=%.2s:%.4s:%s:%s:%s; path=%s/; expires=%s\r\n");
//		printf("Set-Cookie: wmpass=%s; path=%s/\r\n");
                _HEADER['SET-COOKIE']="NESLACMS="+_POST['PASSWORD'];
                print("<SCRIPT LANGUAGE=\"JavaScript\" TYPE=\"text/javascript\">\r\n<!--\r\nlocation.replace(\"", _SERVER['PATH_INFO'], "\");\r\n// -->\r\n</SCRIPT>\r\n");
                print("<NOSCRIPT><META HTTP-EQUIV=\"Refresh\" CONTENT=\"1; URL=", _SERVER['PATH_INFO'], "\"></NOSCRIPT>\r\n");
        } else {
                print("bad pass");
        }
        exit;
}
if (_COOKIE['NESLACMS']==null) {
        _GET['DOWNLOAD']='';
        dologin();
}
global MASTERPASSWORD="********";

// if user is logged in, and download request exists, process that instead
if (_GET['DOWNLOAD']!=null) {
        if (_GET['DOWNLOAD']!='') {
                sendfile(_GET['DOWNLOAD']);
                exit;
        }
}

if (_SERVER['REQUEST_METHOD']=='POST') {
        var opt=_POST['OPT'];
        if (opt=='browse') {
                // limit browsing to docroot
                if (_SERVER['DOCUMENT_ROOT']==null) {
                        print("you have no docroot");
                } else {
                        if (string.ncmp(_SERVER['DOCUMENT_ROOT'], _POST['PATH'], string.len(_SERVER['DOCUMENT_ROOT']))!=0) {
                                print("<B><font color=red>refusing to leave document root</font></B>");
                                parent=_SERVER['DOCUMENT_ROOT'];
                                _POST['PATH']=parent;
                        }
                }
                dir=dirlist(_POST['PATH']);
                x=string.split(_POST['PATH'], "/");
                for (i=0;;i++) {
                        if (x[i]==null) break;
                }
                parent="";
                for (j=0;j<i-1;j++) {
                        if (x[j]=='') { continue; }
                        parent=parent+'/'+x[j];
                }
                if (parent=='') parent='/';
                // limit browsing to docroot
                if (_SERVER['DOCUMENT_ROOT']==null) {
                        print("you have no docroot");
                } else {
                        if (string.ncmp(_SERVER['DOCUMENT_ROOT'], parent, string.len(_SERVER['DOCUMENT_ROOT']))!=0) {
                                parent=_SERVER['DOCUMENT_ROOT'];
                                _POST['PATH']=parent;
                        }
                }
                print("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>\n");
                for (i=0;;i++) {
                        var x=iname(dir, i);
                        if (typeof(dir[x])!='table') break;
                        if (string.cmp(x, '.')==0) {
                        } else if (string.cmp(x, '..')==0) {
                                print("<TR><TD COLSPAN=4 STYLE='border-style:solid'><IMG SRC=/icons/folder.open.png>&nbsp;<A HREF='javascript:newparent(\"", parent, "\");'>Parent Directory - ", parent, "</A></TD></TR>\n");
                        } else if (dir[x].type=='dir') {
                                print("<TR>");
                                print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid'>&nbsp;</TD>");
                                print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid' WIDTH=66%>dir - <A HREF='javascript:newparent(\"", _POST['PATH']+'/'+x, "\");'>", x, "/</A></TD>");
                                print("<TD ALIGN=right NOWRAP STYLE='border-style:solid'>&nbsp;</TD>");
                                print("<TD ALIGN=right NOWRAP STYLE='border-style:solid'>", time.sqldate(dir[x].mtime), " ", time.sqltime(dir[x].mtime), "</TD>");
                                print("</TR>\n");
                        }
                }
                for (i=0;;i++) {
                        var x=iname(dir, i);
                        if (typeof(dir[x])!='table') break;
                        if (string.cmp(x, '.')==0) {
                        } else if (string.cmp(x, '..')==0) {
                        } else if (dir[x].type=='dir') {
                        // hide htaccess files
                        } else if (string.cmp(x, '.htaccess')==0) {
                        } else {
                                print("<TR>");
                                print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid'><A HREF='javascript:nexthand(\"edit\", \"", _POST['PATH']+'/'+x, "\");'>edit</A></TD>");
//				print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid'>file - <A HREF='", x, "'>", x, "</A></TD>");
//				print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid' WIDTH=66%>file - <A HREF='javascript:download(\"", _POST['PATH']+'/'+x, "\");'>", x, "</A></TD>");
                                print("<TD ALIGN=left  NOWRAP STYLE='border-style:solid' WIDTH=66%>file - <A HREF=\"", _SERVER['PATH_INFO'], "?download=", _POST['PATH']+'/'+x, "\" TARGET=\"_blank\">", x, "</A></TD>");
                                print("<TD ALIGN=right NOWRAP STYLE='border-style:solid'>", math.ceil(dir[x].size/1024), " KiB</TD>");
                                print("<TD ALIGN=right NOWRAP STYLE='border-style:solid'>", time.sqldate(dir[x].mtime), " ", time.sqltime(dir[x].mtime), "</TD>");
                                print("</TR>\n");
                        }
                }
                print("</TABLE>\n");
        } else if (opt=='shell') {
                print("\n");
                system("cd "+_POST['PATH']+" && "+_POST['COMMAND']);
        } else if (opt=='edit') {
                system("chmod u+r "+_POST['FILE']);
                x=file.read(_POST['FILE']);
                if ((typeof(x)=='number')&&(x<0)) {
                        print("can't read file");
                } else {
                        print(x);
                }
        } else if (opt=='save') {
                if (_POST['ATTACHMENT1_SIZE']!=null) {
                        x=file.write(_POST['EDITNAME']+"-new", _POST['ATTACHMENT1']);
                } else {
                        x=file.write(_POST['EDITNAME']+"-new", _POST['EDITWINDOW']);
                }
                _POST['EDITWINDOW']="";
                if ((typeof(x)=='number')&&(x<0)) {
                        print("can't write file '", _POST['EDITNAME'], "'\n");
                } else {
                        system("chmod 644 "+_POST['EDITNAME']+"-new");
                        print("Wrote '", _POST['EDITNAME'], "' (", x, " bytes).\n");
                        print("<SCRIPT LANGUAGE=\"JavaScript\" TYPE=\"text/javascript\">\r\n<!--\r\nlocation.replace(\"", _SERVER['PATH_INFO'], "\");\r\n// -->\r\n</SCRIPT>\r\n");
                        print("<NOSCRIPT><META HTTP-EQUIV=\"Refresh\" CONTENT=\"1; URL=", _SERVER['PATH_INFO'], "\"></NOSCRIPT>\r\n");
                }
        } else {
                print("INVALID REQUEST");
                print("<pre>");
                printvar(_GLOBALS);
                print("</pre>");
        }
        exit;
}

function printjs() {
        print("<SCRIPT LANGUAGE=\"JavaScript\" TYPE=\"text/javascript\">\n<!--\n");
        print(
                "function newXMLHttpRequest() {\n",
                "	var xmlreq = false;\n",
                "\n",
                "	if (window.XMLHttpRequest) {\n",
                "		xmlreq = new XMLHttpRequest();\n",
                "	} else if (window.ActiveXObject) {\n",
                "		try {\n",
                "			xmlreq = new ActiveXObject('Msxml2.XMLHTTP');\n",
                "		} catch (e1) {\n",
                "			try {\n",
                "				xmlreq = new ActiveXObject('Microsoft.XMLHTTP');\n",
                "			} catch (e2) {\n",
                "				// Unable to create an XMLHttpRequest with ActiveX\n",
                "			}\n",
                "		}\n",
                "	}\n",
                "	return xmlreq;\n",
                "}\n"
        );
        print(
                "function doresponse(opt, c) {\n",
                "	return function () {\n",
                "		if (c.readyState==4) {\n",
//		"			alert('HTTP status: '+c.status+'\\nHTTP return: '+c.responseText);\n",
                "			if (c.status==200) {\n",
                "				redraw(opt, c);\n",
                "			} else {\n",
                "				alert('HTTP status: '+c.status+'\\nHTTP return: '+c.responseText);\n",
                "			}\n",
                "		}\n",
                "	}\n",
                "}\n"
        );
        print(
                "function nexthand(opt, filename) {\n",
                "	var c = newXMLHttpRequest();\n",
                "	var handlerFunction = doresponse(opt, c);\n",
                "	var fdata='';\n",
                "\n",
                "	fdata='opt='+opt;\n",
                "	if (opt=='edit') {\n",
                "		showpage(3);\n",
                "		document.editor.editname.value=filename;\n",
                "		document.editor.editwindow.innerText='';\n",
                "		fdata+='&file='+filename;\n",
                "	}\n",
                "	for (var i=0;i<document.shell.elements.length;i++) {\n",
//		"		alert(document.shell[i].name+'='+document.shell[i].value);\n",
                "		fdata+='&'+document.shell[i].name+'='+document.shell[i].value;\n",
                "	}\n",
                "	c.onreadystatechange = handlerFunction;\n",
                "	c.open('post', '", _SERVER['PATH_INFO'], "', true);\n",
                "	c.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n",
                "	c.setRequestHeader('Connection', 'close');\n",
                "	c.send(fdata);\n",
                "}\n"
        );
        print("function redraw(opt, c) {\n");
        print("	if (opt=='browse') {\n");
        print(
//		"		r=c.responseXML.documentElement;\n"
                "		r=c.responseText;\n",
                "		document.getElementById('browsewindow').innerHTML=r;\n"
//		"		document.getElementById('browsewindow').innerText=r;\n"
        );
        print("	} else if (opt=='shell') {\n");
        print("		r=c.responseText;\n");
        print("		document.shell.shellwindow.value=r;\n");
        print("	} else if (opt=='edit') {\n");
        print("		r=c.responseText;\n");
        print("		document.editor.editwindow.value=r;\n");
        print("	}\n");
        print("}\n");
        print("// -->\n</SCRIPT>\n");
print("
<SCRIPT LANGUAGE=\"JavaScript\" TYPE=\"text/javascript\">
<!--
function showpage(page) {
	for (var i=1;i<4;i++) {
		if (i==page) {
			document.getElementById('page'+i+'tab').style.borderBottom='solid 0px #000000';
			document.getElementById('page'+i+'tab').bgColor='#FFFFFF';
			document.getElementById('page'+i).style.display='block';
		} else {
			document.getElementById('page'+i+'tab').style.borderBottom='solid 1px #000000';
			document.getElementById('page'+i+'tab').bgColor='#D0D0D0';
			document.getElementById('page'+i).style.display='none';
		}
	}
}
function showdebug() {
	if (document.getElementById('debug').style.display=='none') {
		document.getElementById('debug').style.display='block';
	} else {
		document.getElementById('debug').style.display='none';
	}
}
function doshell() {
	showpage(2);
	nexthand('shell');
	return false;
}
function newparent(p) {
	showpage(1);
	document.shell.path.value=p;
	nexthand('browse');
}
// -->
</SCRIPT>
");
        return;
}

if (string.cmp(_SERVER['REQUEST_METHOD'], "POST")==0) {
        var path=_POST['PATH'];
        var command=_POST['COMMAND'];
} else {
        var path=_filepath;
        var command="ps auxw";
}
print("
<HTML>
<TITLE>Nesla - Crappy Management system</TITLE>
<HEAD>
<STYLE TYPE=text/css>
A        { color: #0000FF; text-decoration: none; }
A:HOVER  { background-color: #E0E0FF; }
</STYLE>
");
printjs();
print("
</HEAD>
<BODY>
<CENTER>
");
print("
<FORM ACTION='", _SERVER['PATH_INFO'], "' METHOD='POST' NAME='shell' onsubmit=\"return doshell();\">
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR><TD>Path   </TD><TD><INPUT SIZE=50 NAME='path'    VALUE='", path, "'></TD><TD VALIGN=BOTTOM ROWSPAN=2><input type='submit' value='run' name='submit'></TD></TR>
<TR><TD>Command</TD><TD><INPUT SIZE=50 NAME='command' VALUE='", command, "'></TD></TR>
</TABLE>
");
print("
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
<TR><TD ALIGN=LEFT><TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 STYLE='border-style:solid'>
<TR>
<TD ID=page1tab NOWRAP STYLE='border-style:solid'>&nbsp;<A ACCESSKEY=1 HREF='javascript:showpage(1);'>FILE BROWSER</A>&nbsp;</TD>
<TD ID=page2tab NOWRAP STYLE='border-style:solid'>&nbsp;<A ACCESSKEY=2 HREF='javascript:showpage(2);'>SHELL</A>&nbsp;</TD>
<TD ID=page3tab NOWRAP STYLE='border-style:solid'>&nbsp;<A ACCESSKEY=3 HREF='javascript:showpage(3);'>TEXT EDITOR</A>&nbsp;</TD>
</TR></TABLE></TD></TR>
<TR><TD VALIGN=TOP STYLE='padding:3px'><HR>

<DIV ID=page1 STYLE='display: block'>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
<TR><TD COLSPAN=2><B>&nbsp;Browser window&nbsp;</B></TD></TR>
<TR><TD><SPAN ID='browsewindow'></SPAN></TD></TR>
<TR><TD ALIGN=CENTER COLSPAN=2>[<A HREF='javascript:nexthand(\"browse\");'> BROWSE FILES </A>]</TD></TR>
</TABLE>
</DIV>

<DIV ID=page2 STYLE='display: block'>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
<TR><TD COLSPAN=2><B>&nbsp;Shell window&nbsp;</B></TD></TR>
<TR><TD ALIGN=CENTER COLSPAN=2><TEXTAREA WRAP=PHYSICAL NAME=shellwindow ROWS=25 COLS=80 style='width:100%'></TEXTAREA></TD></TR>
<TR><TD ALIGN=CENTER COLSPAN=2>[<A HREF='javascript:nexthand(\"shell\");'> RUN COMMAND </A>]</TD></TR>
</TABLE>
</FORM>
</DIV>


<DIV ID=page3 STYLE='display: block'>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
<FORM ACTION='", _SERVER['PATH_INFO'], "' METHOD='POST' NAME='editor' ENCTYPE='multipart/form-data'>
<!--FORM ACTION='", _SERVER['PATH_INFO'], "' METHOD='POST' NAME='editor'-->
<INPUT TYPE=hidden NAME=path VALUE='", path, "'>
<INPUT TYPE=hidden NAME=opt VALUE='save'>
<TR><TD COLSPAN=2><B>&nbsp;Editor window&nbsp;</B></TD></TR>
<TR><TD STYLE='padding:0px'>
<TR><TD><B>Filename</B></TD><TD ALIGN=RIGHT><INPUT SIZE=100 NAME='editname' VALUE='", "'></TD></TR>

<TR><TD ALIGN=CENTER COLSPAN=2><TEXTAREA WRAP=OFF NAME=editwindow ROWS=25 COLS=80 style='width:100%'></TEXTAREA></TD></TR>

<TR><TD><B>Upload File</B></TD><TD ALIGN=RIGHT><INPUT SIZE=100 NAME=ATTACHMENT1 TYPE=FILE></TD></TR>
<TR><TD ALIGN=CENTER COLSPAN=2><input type='submit' value='Save' name='submit'></TD></TR>
</TD></TR>
</FORM>
</TABLE>

</DIV>
<HR>
</TD></TR>
</TABLE>
");
print("
<SCRIPT LANGUAGE=\"JavaScript\" TYPE=\"text/javascript\">
<!--
document.shell.command.focus();
showpage(1);
nexthand('browse');
// -->
</SCRIPT>
");
print("<A HREF='javascript:showdebug();'>DEBUG</A>\n");
print("</CENTER>\n");
print("<DIV ID=debug STYLE='display:none'><PRE><FONT SIZE=2>\n");
printvar(_GLOBALS);
print("</FONT></PRE></DIV>\n");
print("</BODY>\n</HTML>\n");