/*
NETWOX
Network toolbox
Copyright(c) 1999-2006 Laurent Constantin
-----
Main server : http://www.laurentconstantin.com/
Backup servers : http://go.to/laurentconstantin/
http://laurentconstantin.est-la.com/
http://laurentconstantin.free.fr/
http://membres.lycos.fr/lauconstantin/
[my current email address is on the web servers]
-----
This file is part of Netwox.
Netwox is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Netwox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details (http://www.gnu.org/).
------------------------------------------------------------------------
*/
/*-------------------------------------------------------------*/
#include "../netwox.h"
/*-------------------------------------------------------------*/
netwib_conststring t000126_description[] = {
"This tool is a web server permitting clients to run a command.",
"",
NETWOX_DESC_allowedclients,
NETWOX_DESC_servertcpmul,
NETWOX_DESC_toolpriv_port1024,
NULL
};
netwox_toolarg t000126_args[] = {
NETWOX_SOCK_ARG_TCP_MULSERPORT("80"),
NETWOX_TOOLARG_OPT_BUF_LOGIN('l', "login", "login needed to access", NULL),
NETWOX_TOOLARG_OPT_BUF_PASSWORD('L', "password", "password needed to access",
NULL),
NETWOX_TOOLARG_OPTA_UINT32('T', "timeout", "timeout in ms", "60000"),
NETWOX_TOOLARG_OPTA_IPS_SU('c', "allowed-clients",
"clients allowed to connect", NULL),
NETWOX_TOOLARG_END
};
netwox_tooltreenodetype t000126_nodes[] = {
NETWOX_TOOLTREENODETYPE_SERVER_TCP_HTTP,
NETWOX_TOOLTREENODETYPE_REMADM,
NETWOX_TOOLTREENODETYPE_END
};
netwox_tool_info t000126_info = {
"HTTP remote administration server",
t000126_description,
"exec, run, web",
t000126_args,
t000126_nodes,
};
/*-------------------------------------------------------------*/
static netwib_err t000126_send_error(netwox_httpserctx *pctx,
netwib_io *pio,
netwox_httphdr_statuscode statuscode,
netwib_conststring statusmessage)
{
netwib_buf *pbuf;
/* write headers */
netwib_er(netwox_httpserresphdrs_init(pctx, pio, statuscode, statusmessage));
netwib_er(netwib_bufpool_buf_init(pctx->pbufpool, &pbuf));
netwib_er(netwox_httphdr_contenttype("text/html", pbuf));
netwib_er(netwox_httphdr_endheader(pbuf));
netwib_er(netwib_io_write(pio, pbuf));
/* write body */
netwib__buf_reinit(pbuf);
netwib_er(netwib_buf_append_string("
", pbuf));
netwib_er(netwib_buf_append_fmt(pbuf, "Error %{uint32} : %s", statuscode,
statusmessage));
netwib_er(netwib_buf_append_string("", pbuf));
netwib_er(netwib_io_write(pio, pbuf));
/* close */
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pbuf));
return(NETWIB_ERR_OK);
}
/*-------------------------------------------------------------*/
static netwib_err t000126_send_form(netwox_httpserctx *pctx,
netwib_io *pio,
netwib_constbuf *pcmd)
{
netwib_buf *pbuf;
netwib_io *pexecio;
netwib_bool exitednormally;
netwib_uint32 returnedvalue;
netwib_err ret;
netwib_er(netwib_bufpool_buf_init(pctx->pbufpool, &pbuf));
/* write headers */
netwib_er(netwox_httpserresphdrs_init(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_OK, "Ok"));
netwib_er(netwox_httphdr_contenttype("text/html", pbuf));
netwib_er(netwox_httphdr_endheader(pbuf));
netwib_er(netwib_io_write(pio, pbuf));
/* write form */
netwib__buf_reinit(pbuf);
netwib_er(netwib_buf_append_string("
\nCommand : ", pbuf));
netwib_er(netwib_buf_append_string("
\n", pbuf));
netwib_er(netwib_buf_append_string("Examples: /bin/ls, /bin/sh -c \"pwd;ls\", cmd /c dir c:
\n", pbuf));
netwib_er(netwib_buf_append_string("Note: full path has to be specified
\n", pbuf));
netwib_er(netwib_buf_append_string("Note: cannot use 'prog1 | prog2', 'program > file' or 'program < file'
\n", pbuf));
netwib_er(netwib_buf_append_string("Note: program must not expect keyboard presses (stdin) from user
\n", pbuf));
netwib_er(netwib_buf_append_string("
", pbuf));
netwib_er(netwib_io_write(pio, pbuf));
/* leave now if command is empty */
if (netwib__buf_ref_data_size(pcmd) == 0) {
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pbuf));
return(NETWIB_ERR_OK);
}
/* write body */
ret = netwib_io_init_exec(pcmd, NETWIB_IO_WAYTYPE_READ, NETWIB_FALSE,
&exitednormally, &returnedvalue, &pexecio);
if (ret != NETWIB_ERR_OK) {
netwib__buf_reinit(pbuf);
netwib_er(netwib_buf_append_string("Cannot run this command", pbuf));
netwib_er(netwib_io_write(pio, pbuf));
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pbuf));
return(NETWIB_ERR_OK);
}
netwib_er(netwox_httpbody_write_io_close(pctx->pbufpool, pexecio, pio));
netwib_er(netwib_io_close(&pexecio));
/* write result */
netwib__buf_reinit(pbuf);
netwib_er(netwib_buf_append_string("
", pbuf));
if (exitednormally) {
netwib_er(netwib_buf_append_fmt(pbuf, "Program exited with return code %{uint32}
\n", returnedvalue));
} else {
netwib_er(netwib_buf_append_string("Program was interrupted
\n", pbuf));
}
netwib_er(netwib_buf_append_string("", pbuf));
netwib_er(netwib_io_write(pio, pbuf));
/* close */
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pbuf));
return(NETWIB_ERR_OK);
}
/*-------------------------------------------------------------*/
static netwib_err t000126_answer(netwox_httpserctx *pctx,
netwib_io *pio,
netwox_httpserreqhdrs *preqhdrs)
{
netwib_buf query, *pquery, cmd, *pcmd;
netwib_bool auth;
netwib_cmp cmp;
netwib_err ret;
/* check method */
if (preqhdrs->method != NETWOX_HTTPHDR_METHOD_GET &&
preqhdrs->method != NETWOX_HTTPHDR_METHOD_POST) {
return(t000126_send_error(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_NOTIMPLEMENTED,
"Only GET and POST methods are implemented"));
}
/* check authentication */
if (netwib__buf_ref_data_size(&pctx->login)) {
auth = NETWIB_FALSE;
if (preqhdrs->authbasicset) {
netwib_er(netwib_buf_cmp(&pctx->login, &preqhdrs->authbasiclogin, &cmp));
if (cmp == NETWIB_CMP_EQ) {
netwib_er(netwib_buf_cmp(&pctx->password, &preqhdrs->authbasicpassword,
&cmp));
if (cmp == NETWIB_CMP_EQ) {
auth = NETWIB_TRUE;
}
}
}
if (!auth) {
return(t000126_send_error(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_UNAUTHORIZED,
"Bad login and password"));
}
}
/* obtain query */
netwib_er(netwib_bufpool_buf_init(pctx->pbufpool, &pquery));
if (preqhdrs->method == NETWOX_HTTPHDR_METHOD_GET) {
ret = netwox_url_pqf_decode(&preqhdrs->uri, NULL, &query, NULL);
if (ret != NETWIB_ERR_OK) {
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pquery));
return(t000126_send_error(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_BADREQUEST,
"URI not decoded"));
}
netwib_er(netwib_buf_append_buf(&query, pquery));
} else {
ret = netwox_httpbody_read_buf(pctx->timeoutms,
preqhdrs->contentlengthset,
preqhdrs->contentlength, pio, pquery);
if (ret != NETWIB_ERR_OK) {
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pquery));
return(t000126_send_error(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_BADREQUEST,
"Timeout"));
}
}
/*netwib_er(netwib_fmt_display("query=%{buf}\n", pquery));*/
/* obtain command parameter */
netwib_er(netwib_bufpool_buf_init(pctx->pbufpool, &pcmd));
if (netwib__buf_ref_data_size(pquery)) {
netwib_er(netwib_buf_init_ext_string("cmd", &cmd));
ret = netwox_url_query_decode(pquery, &cmd, NULL, pcmd);
if (ret != NETWIB_ERR_OK) {
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pcmd));
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pquery));
return(t000126_send_error(pctx, pio,
NETWOX_HTTPHDR_STATUSCODE_BADREQUEST,
"URI/POST does not contain a valid command"));
}
}
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pquery));
/*netwib_er(netwib_fmt_display("cmd=%{buf}\n", pcmd));*/
/* display form and run command */
netwib_er(t000126_send_form(pctx, pio, pcmd));
netwib_er(netwib_bufpool_buf_close(pctx->pbufpool, &pcmd));
return(NETWIB_ERR_OK);
}
/*-------------------------------------------------------------*/
static netwib_err t000126_srv(netwib_io *psockio,
netwib_ptr pinfos)
{
netwox_httpserctx *pctx = (netwox_httpserctx *)pinfos;
netwib_io *pio;
netwox_httpserreqhdrs reqhdrs;
netwib_ip remoteip;
netwib_port remoteport;
netwib_bool allowed;
netwib_err ret=NETWIB_ERR_OK;
/* check client */
if (pctx->pallowedclients != NULL) {
netwib_er(netwib_sock_ctl_get_remote(psockio, &remoteip, &remoteport));
netwib_er(netwib_ips_contains_ip(pctx->pallowedclients, &remoteip,
&allowed));
if (!allowed) {
netwib_fmt_display("IP address %{ip} is not allowed\n", &remoteip);
/*ignore*/t000126_send_error(pctx, psockio,
NETWOX_HTTPHDR_STATUSCODE_FORBIDDEN,
"Your address is forbidden");
return(NETWIB_ERR_OK);
}
}
/* prepare a read by line io */
netwib_er(netwib_io_init_data(NETWIB_IO_INIT_DATA_TYPE_LINE,
NETWIB_IO_INIT_DATA_TYPE_TRANSPARENT, &pio));
netwib_er(netwib_io_plug_rdwr(pio, psockio));
/* read request */
netwib_er(netwox_httpserreqhdrs_init(&reqhdrs));
ret = netwox_httpserreqhdrs_decode(pctx, pio, &reqhdrs);
/* answer */
if (ret == NETWIB_ERR_OK) {
ret = t000126_answer(pctx, pio, &reqhdrs);
}
if (ret != NETWIB_ERR_OK) {
netwib_er(netwox_err_display(ret, NETWIB_ERR_ENCODETYPE_TEXT));
}
/* close */
netwib_er(netwox_httpserreqhdrs_close(&reqhdrs));
netwib_er(netwib_io_unplug_next_supported(pio, NULL));
netwib_er(netwib_io_close(&pio));
return(NETWIB_ERR_OK);
}
/*-------------------------------------------------------------*/
netwib_err t000126_core(int argc, char *argv[])
{
netwox_arg *parg;
netwox_sockinfo sockinfo;
netwox_httpserctx ctx;
netwib_buf buf;
/* obtain parameters */
netwib_er(netwox_arg_init(argc, argv, &t000126_info, &parg));
netwib_er(netwox_sockinfo_init_arg_tcp_mulser(parg, &sockinfo));
netwib_er(netwox_httpserctx_init(&ctx));
netwib_er(netwox_arg_buf(parg, 'l', &buf));
buf.flags |= NETWIB_BUF_FLAGS_SENSITIVE;
buf.flags |= NETWIB_BUF_FLAGS_SENSITIVE_READONLY;
netwib_er(netwib_buf_append_buf(&buf, &ctx.login));
netwib_er(netwox_arg_buf(parg, 'L', &buf));
buf.flags |= NETWIB_BUF_FLAGS_SENSITIVE;
buf.flags |= NETWIB_BUF_FLAGS_SENSITIVE_READONLY;
netwib_er(netwib_buf_append_buf(&buf, &ctx.password));
netwib_er(netwox_arg_uint32(parg, 'T', &ctx.timeoutms));
netwib_er(netwox_arg_ips(parg, 'c', &ctx.pallowedclients));
netwib_er(netwib_buf_append_string("HTTP Server", &ctx.realm));
/* main loop */
netwib_er(netwox_sock_tcp_mulser(&sockinfo, &t000126_srv, &ctx));
/* close */
netwib_er(netwox_httpserctx_close(&ctx));
netwib_er(netwox_sockinfo_close(&sockinfo));
netwib_er(netwox_arg_close(&parg));
return(NETWIB_ERR_OK);
}