Add basic auth to the webserver ##sync
This commit is contained in:
parent
7185d6ca0a
commit
de40266908
|
@ -28,6 +28,8 @@ static int usage (int v) {
|
|||
" -d run in daemon mode (background)\n"
|
||||
" -h show this help message\n"
|
||||
" -s run in sandbox mode\n"
|
||||
" -u enable http Authorization access\n"
|
||||
" -t user:password authentification file\n"
|
||||
" -p [port] specify listening port (defaults to 8080)\n");
|
||||
return !v;
|
||||
}
|
||||
|
@ -39,14 +41,18 @@ static int showversion() {
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
RSocket *s;
|
||||
RSocketHTTPOptions so;
|
||||
RSocketHTTPRequest *rs;
|
||||
int c, timeout = 3;
|
||||
int c;
|
||||
int dodaemon = 0;
|
||||
int dosandbox = 0;
|
||||
bool listenlocal = true;
|
||||
const char *port = "8080";
|
||||
const char *httpauthfile = NULL;
|
||||
char *pfile = NULL;
|
||||
memset (&so, 0, sizeof (so));
|
||||
|
||||
while ((c = getopt (argc, argv, "adhp:sv")) != -1) {
|
||||
while ((c = getopt (argc, argv, "adhup:t:sv")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
listenlocal = false;
|
||||
|
@ -61,6 +67,12 @@ int main(int argc, char **argv) {
|
|||
return usage (1);
|
||||
case 'v':
|
||||
return showversion ();
|
||||
case 'u':
|
||||
so.httpauth = true;
|
||||
break;
|
||||
case 't':
|
||||
httpauthfile = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = optarg;
|
||||
break;
|
||||
|
@ -72,6 +84,24 @@ int main(int argc, char **argv) {
|
|||
return usage (0);
|
||||
}
|
||||
|
||||
so.accept_timeout = 0;
|
||||
so.timeout = 3;
|
||||
|
||||
if (so.httpauth) {
|
||||
if (!httpauthfile) {
|
||||
eprintf ("No authentification user list set\n");
|
||||
return usage (0);
|
||||
}
|
||||
|
||||
int sz;
|
||||
pfile = r_file_slurp (httpauthfile, &sz);
|
||||
if (pfile) {
|
||||
so.authtokens = r_str_split_list (pfile, "\n");
|
||||
} else {
|
||||
eprintf ("Empty list of HTTP users\\n");
|
||||
return usage (0);
|
||||
}
|
||||
}
|
||||
#if USE_IOS_JETSAM
|
||||
memorystatus_control (MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT, getpid (), 256, NULL, 0);
|
||||
#endif
|
||||
|
@ -95,6 +125,9 @@ int main(int argc, char **argv) {
|
|||
eprintf ("http://localhost:%d/\n", s->port);
|
||||
if (dosandbox && !r_sandbox_enable (true)) {
|
||||
eprintf ("sandbox: Cannot be enabled.\n");
|
||||
free (pfile);
|
||||
r_list_free (so.authtokens);
|
||||
r_socket_free (s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -104,10 +137,13 @@ int main(int argc, char **argv) {
|
|||
char *result_heap = NULL;
|
||||
const char *result = page_index;
|
||||
|
||||
rs = r_socket_http_accept (s, 0, timeout);
|
||||
rs = r_socket_http_accept (s, &so);
|
||||
if (!rs) {
|
||||
continue;
|
||||
}
|
||||
if (!rs->auth) {
|
||||
r_socket_http_response (rs, 401, "", 0, NULL);
|
||||
}
|
||||
if (!strcmp (rs->method, "GET")) {
|
||||
if (!strncmp (rs->path, "/proc/kill/", 11)) {
|
||||
// TODO: show page here?
|
||||
|
@ -138,6 +174,8 @@ int main(int argc, char **argv) {
|
|||
result = result_heap = malloc (1024 + escaped_len);
|
||||
if (!result) {
|
||||
perror ("malloc");
|
||||
free (pfile);
|
||||
r_list_free (so.authtokens);
|
||||
return 1;
|
||||
}
|
||||
sprintf (result_heap,
|
||||
|
@ -155,6 +193,8 @@ int main(int argc, char **argv) {
|
|||
result_heap = NULL;
|
||||
}
|
||||
r_cons_free ();
|
||||
free (pfile);
|
||||
r_list_free (so.authtokens);
|
||||
r_socket_free (s);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3026,6 +3026,10 @@ R_API int r_core_config_init(RCore *core) {
|
|||
SETPREF ("http.upget", "false", "/up/ answers GET requests, in addition to POST");
|
||||
SETPREF ("http.upload", "false", "Enable file uploads to /up/<filename>");
|
||||
SETPREF ("http.uri", "", "Address of HTTP proxy");
|
||||
SETPREF ("http.auth", "false", "Enable/Disable HTTP Authentification");
|
||||
SETPREF ("http.authtok", "r2admin:r2admin", "HTTP Authentification user:password token");
|
||||
p = r_sys_getenv ("R2_HTTP_AUTHFILE");
|
||||
SETPREF ("http.authfile", p? p : "", "HTTP Authentification user file");
|
||||
tmpdir = r_file_tmpdir ();
|
||||
r_config_set (cfg, "http.uproot", tmpdir);
|
||||
free (tmpdir);
|
||||
|
|
|
@ -417,14 +417,17 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
char buf[32];
|
||||
int ret = 0;
|
||||
RSocket *s;
|
||||
RSocketHTTPOptions so;
|
||||
char *dir;
|
||||
int iport, timeout = r_config_get_i (core->config, "http.timeout");
|
||||
int iport;
|
||||
const char *host = r_config_get (core->config, "http.bind");
|
||||
const char *root = r_config_get (core->config, "http.root");
|
||||
const char *homeroot = r_config_get (core->config, "http.homeroot");
|
||||
const char *port = r_config_get (core->config, "http.port");
|
||||
const char *allow = r_config_get (core->config, "http.allow");
|
||||
const char *httpui = r_config_get (core->config, "http.ui");
|
||||
const char *httpauthfile = r_config_get (core->config, "http.authfile");
|
||||
char *pfile = NULL;
|
||||
|
||||
if (!r_file_is_directory (root)) {
|
||||
if (!r_file_is_directory (homeroot)) {
|
||||
|
@ -480,6 +483,7 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
} else {
|
||||
s->local = true;
|
||||
}
|
||||
memset (&so, 0, sizeof (so));
|
||||
}
|
||||
if (!r_socket_listen (s, port, NULL)) {
|
||||
r_socket_free (s);
|
||||
|
@ -493,6 +497,30 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
browser, host, atoi (port), path? path:"");
|
||||
}
|
||||
|
||||
so.httpauth = r_config_get_i (core->config, "http.auth");
|
||||
|
||||
if (so.httpauth) {
|
||||
if (!httpauthfile) {
|
||||
r_socket_free (s);
|
||||
eprintf ("No user list set for HTTP Authentification\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sz;
|
||||
pfile = r_file_slurp (httpauthfile, &sz);
|
||||
|
||||
if (pfile) {
|
||||
so.authtokens = r_str_split_list (pfile, "\n");
|
||||
} else {
|
||||
r_socket_free (s);
|
||||
eprintf ("Empty list of HTTP users\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
so.timeout = r_config_get_i (core->config, "http.timeout");
|
||||
so.accept_timeout = 1;
|
||||
}
|
||||
|
||||
origcfg = core->config;
|
||||
newcfg = r_config_clone (core->config);
|
||||
core->config = newcfg;
|
||||
|
@ -523,6 +551,8 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
newblk = malloc (core->blocksize);
|
||||
if (!newblk) {
|
||||
r_socket_free (s);
|
||||
r_list_free (so.authtokens);
|
||||
free (pfile);
|
||||
return 1;
|
||||
}
|
||||
memcpy (newblk, core->block, core->blocksize);
|
||||
|
@ -552,7 +582,7 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
activateDieTime (core);
|
||||
|
||||
void *bed = r_cons_sleep_begin ();
|
||||
rs = r_socket_http_accept (s, 1, timeout);
|
||||
rs = r_socket_http_accept (s, &so);
|
||||
r_cons_sleep_end (bed);
|
||||
|
||||
origoff = core->offset;
|
||||
|
@ -608,6 +638,10 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
}
|
||||
dir = NULL;
|
||||
|
||||
if (!rs->auth) {
|
||||
r_socket_http_response (rs, 401, "", 0, NULL);
|
||||
}
|
||||
|
||||
if (r_config_get_i (core->config, "http.verbose")) {
|
||||
char *peer = r_socket_to_string (rs->s);
|
||||
http_logf (core, "[HTTP] %s %s\n", peer, rs->path);
|
||||
|
@ -658,7 +692,7 @@ static int r_core_rtr_http_run(RCore *core, int launch, int browse, const char *
|
|||
free (path);
|
||||
}
|
||||
} else {
|
||||
r_socket_http_response (rs, 403, "Permission denied\n", 0, NULL);
|
||||
r_socket_http_response (rs, 403, "", 0, NULL);
|
||||
}
|
||||
} else if (!strncmp (rs->path, "/cmd/", 5)) {
|
||||
char *cmd = rs->path + 5;
|
||||
|
@ -862,6 +896,7 @@ the_end:
|
|||
}
|
||||
r_cons_break_pop ();
|
||||
core->http_up = false;
|
||||
free (pfile);
|
||||
r_socket_free (s);
|
||||
r_config_free (newcfg);
|
||||
if (restoreSandbox) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "r_types.h"
|
||||
#include "r_bind.h"
|
||||
#include "r_list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -71,6 +72,14 @@ typedef struct r_socket_t {
|
|||
#endif
|
||||
} RSocket;
|
||||
|
||||
typedef struct r_socket_http_options {
|
||||
RList *authtokens;
|
||||
bool accept_timeout;
|
||||
int timeout;
|
||||
bool httpauth;
|
||||
} RSocketHTTPOptions;
|
||||
|
||||
|
||||
#define R_SOCKET_PROTO_TCP IPPROTO_TCP
|
||||
#define R_SOCKET_PROTO_UDP IPPROTO_UDP
|
||||
#define R_SOCKET_PROTO_UNIX 0x1337
|
||||
|
@ -136,9 +145,10 @@ typedef struct r_socket_http_request {
|
|||
char *referer;
|
||||
ut8 *data;
|
||||
int data_length;
|
||||
bool auth;
|
||||
} RSocketHTTPRequest;
|
||||
|
||||
R_API RSocketHTTPRequest *r_socket_http_accept(RSocket *s, int accept_timeout, int timeout);
|
||||
R_API RSocketHTTPRequest *r_socket_http_accept(RSocket *s, RSocketHTTPOptions *so);
|
||||
R_API void r_socket_http_response(RSocketHTTPRequest *rs, int code, const char *out, int x, const char *headers);
|
||||
R_API void r_socket_http_close(RSocketHTTPRequest *rs);
|
||||
R_API ut8 *r_socket_http_handle_upload(const ut8 *str, int len, int *olen);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* radare - LGPL - Copyright 2012-2016 - pancake */
|
||||
|
||||
#include <r_socket.h>
|
||||
#include <r_util.h>
|
||||
|
||||
static bool *breaked = NULL;
|
||||
|
||||
|
@ -8,7 +9,7 @@ R_API void r_socket_http_server_set_breaked(bool *b) {
|
|||
breaked = b;
|
||||
}
|
||||
|
||||
R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, int accept_timeout, int timeout) {
|
||||
R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, RSocketHTTPOptions *so) {
|
||||
int content_length = 0, xx, yy;
|
||||
int pxx = 1, first = 0;
|
||||
char buf[1500], *p, *q;
|
||||
|
@ -16,7 +17,7 @@ R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, int accept_timeout,
|
|||
if (!hr) {
|
||||
return NULL;
|
||||
}
|
||||
if (accept_timeout > 0) {
|
||||
if (so->accept_timeout) {
|
||||
hr->s = r_socket_accept_timeout (s, 1);
|
||||
} else {
|
||||
hr->s = r_socket_accept (s);
|
||||
|
@ -25,9 +26,10 @@ R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, int accept_timeout,
|
|||
free (hr);
|
||||
return NULL;
|
||||
}
|
||||
if (timeout > 0) {
|
||||
r_socket_block_time (hr->s, 1, timeout);
|
||||
if (so->timeout > 0) {
|
||||
r_socket_block_time (hr->s, 1, so->timeout);
|
||||
}
|
||||
hr->auth = !so->httpauth;
|
||||
for (;;) {
|
||||
#if __WINDOWS__
|
||||
if (breaked)
|
||||
|
@ -63,15 +65,39 @@ R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, int accept_timeout,
|
|||
} else {
|
||||
if (!hr->referer && !strncmp (buf, "Referer: ", 9)) {
|
||||
hr->referer = strdup (buf + 9);
|
||||
} else
|
||||
if (!hr->agent && !strncmp (buf, "User-Agent: ", 12)) {
|
||||
} else if (!hr->agent && !strncmp (buf, "User-Agent: ", 12)) {
|
||||
hr->agent = strdup (buf + 12);
|
||||
} else
|
||||
if (!hr->host && !strncmp (buf, "Host: ", 6)) {
|
||||
} else if (!hr->host && !strncmp (buf, "Host: ", 6)) {
|
||||
hr->host = strdup (buf + 6);
|
||||
} else
|
||||
if (!strncmp (buf, "Content-Length: ", 16)) {
|
||||
content_length = atoi (buf+16);
|
||||
} else if (!strncmp (buf, "Content-Length: ", 16)) {
|
||||
content_length = atoi (buf + 16);
|
||||
} else if (so->httpauth && !strncmp (buf, "Authorization: Basic ", 21)) {
|
||||
char *authtoken = buf + 21;
|
||||
size_t authlen = strlen (authtoken);
|
||||
char *curauthtoken;
|
||||
RListIter *iter;
|
||||
char *decauthtoken = calloc (4, authlen + 1);
|
||||
if (!decauthtoken) {
|
||||
eprintf ("Could not allocate decoding buffer\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (r_base64_decode ((ut8 *)decauthtoken, authtoken, authlen) == -1) {
|
||||
eprintf ("Could not decode authorization token\n");
|
||||
} else {
|
||||
r_list_foreach (so->authtokens, iter, curauthtoken) {
|
||||
if (!strcmp (decauthtoken, curauthtoken)) {
|
||||
hr->auth = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (decauthtoken);
|
||||
|
||||
if (!hr->auth) {
|
||||
eprintf ("Failed attempt login from '%s'\n", hr->host);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,15 +114,17 @@ R_API RSocketHTTPRequest *r_socket_http_accept (RSocket *s, int accept_timeout,
|
|||
R_API void r_socket_http_response (RSocketHTTPRequest *rs, int code, const char *out, int len, const char *headers) {
|
||||
const char *strcode = \
|
||||
code==200?"ok":
|
||||
code==301?"moved permanently":
|
||||
code==301?"Moved permanently":
|
||||
code==302?"Found":
|
||||
code==401?"Unauthorized":
|
||||
code==403?"Permission denied":
|
||||
code==404?"not found":
|
||||
"UNKNOWN";
|
||||
if (len < 1) {
|
||||
len = out ? strlen (out) : 0;
|
||||
}
|
||||
if (!headers) {
|
||||
headers = "";
|
||||
headers = code == 401 ? "WWW-Authenticate: Basic realm=\"R2 Web UI Access\"\n" : "";
|
||||
}
|
||||
r_socket_printf (rs->s, "HTTP/1.0 %d %s\r\n%s"
|
||||
"Connection: close\r\nContent-Length: %d\r\n\r\n",
|
||||
|
|
|
@ -18,6 +18,10 @@ Run in daemon mode
|
|||
Show help prompt
|
||||
.It Fl s, Cm sandbox
|
||||
Run in sandbox mode
|
||||
.It Fl u, Cm httpauth
|
||||
Enable HTTP Authentification support
|
||||
.It Fl t, Cm httpauthfile
|
||||
user:password authentification file
|
||||
.It Fl p, Cm port Ar PORT
|
||||
Specify listening port for the agent
|
||||
.It Fl v
|
||||
|
|
Loading…
Reference in New Issue