1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-30 16:24:09 +03:00

finished authentication, implemented port/dir protection

git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@60 9a5d90b5-6617-0410-8a86-bb477d3ed2e3
This commit is contained in:
cameronrich
2007-02-10 05:31:17 +00:00
parent 30a1970bb2
commit 36ac01f46a
19 changed files with 351 additions and 255 deletions

View File

@ -35,6 +35,7 @@ static void urldecode(char *buf);
static void buildactualfile(struct connstruct *cn);
static int sanitizefile(const char *buf);
static int sanitizehost(char *buf);
static int htaccess_check(struct connstruct *cn);
#if defined(CONFIG_HTTP_DIRECTORIES)
static void urlencode(const uint8_t *s, uint8_t *t);
@ -63,11 +64,10 @@ static int procheadelem(struct connstruct *cn, char *buf)
*delim = 0;
value = delim+1;
printf("BUF %s - value %s\n", buf, value);
if (strcmp(buf, "GET") == 0 ||
strcmp(buf, "HEAD") == 0 ||
strcmp(buf, "POST") == 0)
/* printf("name: %s, value: %s\n", buf, value); */
if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 ||
strcmp(buf, "POST") == 0)
{
if (buf[0] == 'H')
cn->reqtype = TYPE_HEAD;
@ -76,13 +76,13 @@ static int procheadelem(struct connstruct *cn, char *buf)
if ((delim = strchr(value, ' ')) == NULL) /* expect HTTP type */
return 0;
*delim = 0;
*delim = 0;
urldecode(value);
if (sanitizefile(value) == 0)
{
send_error(cn, 404);
send_error(cn, 403);
return 0;
}
@ -94,7 +94,6 @@ static int procheadelem(struct connstruct *cn, char *buf)
my_strncpy(cn->cgiargs, value+1, MAXREQUESTLENGTH);
}
#endif
}
else if (strcmp(buf, "Host:") == 0)
{
@ -117,11 +116,14 @@ static int procheadelem(struct connstruct *cn, char *buf)
}
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
else if (strcmp(buf, "Authorization:") == 0 &&
strncmp(value, "Basic ", 6) == 0)
strncmp(value, "Basic ", 6) == 0)
{
int size;
if (base64_decode(&value[6], strlen(&value[6]),
cn->authorization, NULL))
cn->authorization, &size))
cn->authorization[0] = 0; /* error */
else
cn->authorization[size] = 0;
}
#endif
@ -319,36 +321,42 @@ void procsendhead(struct connstruct *cn)
time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT;
char date[32];
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
if (auth_check(cn))
/* are we trying to access a file over the HTTP connection instead of a
* HTTPS connection? Or is this directory disabled? */
if (htaccess_check(cn))
{
send_error(cn, 403);
return;
}
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
if (auth_check(cn)) /* see if there is a '.htpasswd' file */
{
#ifdef CONFIG_HTTP_VERBOSE
printf("axhttpd: access to %s denied\n", cn->actualfile); TTY_FLUSH();
#endif
removeconnection(cn);
return;
}
#endif
strcpy(date, ctime(&now));
if (stat(cn->actualfile, &stbuf) == -1)
if (stat(cn->actualfile, &stbuf) == -1)
{
#if defined(CONFIG_HTTP_HAS_CGI)
if (trycgi_withpathinfo(cn) == 0)
if (stat(cn->actualfile, &stbuf) == -1 && trycgi_withpathinfo(cn) == 0)
{
/* We Try To Find A CGI */
proccgi(cn, 1);
return;
}
#endif
send_error(cn, 404);
return;
}
#if defined(CONFIG_HTTP_HAS_CGI)
if (iscgi(cn->actualfile))
{
#ifndef WIN32
/* Set up CGI script */
/* An executable file? */
if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile))
{
send_error(cn, 404);
@ -396,6 +404,8 @@ void procsendhead(struct connstruct *cn)
#endif
}
strcpy(date, ctime(&now));
if (cn->modified_since)
{
/* file has already been read before */
@ -407,20 +417,6 @@ void procsendhead(struct connstruct *cn)
return;
}
#ifdef CONFIG_HTTP_VERBOSE
printf("axhttpd: %s send %s\n",
cn->is_ssl ? "https" : "http", cn->actualfile);
TTY_FLUSH();
#endif
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n"
"Content-Type: %s\nContent-Length: %ld\n"
"Date: %sLast-Modified: %s\n", VERSION,
getmimetype(cn->actualfile), (long) stbuf.st_size,
date, ctime(&(stbuf.st_mtime))); /* ctime() has a \n on the end */
special_write(cn, buf, strlen(buf));
if (cn->reqtype == TYPE_HEAD)
{
removeconnection(cn);
@ -437,10 +433,23 @@ void procsendhead(struct connstruct *cn)
if (cn->filedesc == -1)
{
send_error(cn, 404);
removeconnection(cn);
return;
}
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n"
"Content-Type: %s\nContent-Length: %ld\n"
"Date: %sLast-Modified: %s\n", VERSION,
getmimetype(cn->actualfile), (long) stbuf.st_size,
date, ctime(&(stbuf.st_mtime))); /* ctime() has a \n on the end */
special_write(cn, buf, strlen(buf));
#ifdef CONFIG_HTTP_VERBOSE
printf("axhttpd: %s send %s\n",
cn->is_ssl ? "https" : "http", cn->actualfile);
TTY_FLUSH();
#endif
#ifdef WIN32
for (;;)
{
@ -659,10 +668,8 @@ static int trycgi_withpathinfo(struct connstruct *cn)
/* We've found our CGI file! */
my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH);
my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH);
offset = (fr_rs[i] + strlen(fr_rs[i])) - fr_str;
my_strncpy(cn->cgipathinfo, cn->filereq+offset, MAXREQUESTLENGTH);
return 0;
}
@ -678,11 +685,10 @@ static int trycgi_withpathinfo(struct connstruct *cn)
static int iscgi(const char *fn)
{
struct cgiextstruct *tp;
struct cgiextstruct *tp = cgiexts;
int fnlen, extlen;
fnlen = strlen(fn);
tp = cgiexts;
while (tp != NULL)
{
@ -784,6 +790,7 @@ static int hexit(char c)
static void buildactualfile(struct connstruct *cn)
{
char *cp;
snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s", cn->filereq);
/* Add directory slash if not there */
@ -791,12 +798,23 @@ static void buildactualfile(struct connstruct *cn)
cn->actualfile[strlen(cn->actualfile)-1] != '/')
strcat(cn->actualfile, "/");
/* work out the directory name */
strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
if ((cp = strrchr(cn->dirname, '/')) == NULL)
cn->dirname[0] = 0;
else
*cp = 0;
#ifdef WIN32
/* convert all the forward slashes to back slashes */
{
char *t = cn->actualfile;
while ((t = strchr(t, '/')))
*t++ = '\\';
t = cn->dirname;
while ((t = strchr(t, '/')))
*t++ = '\\';
}
#endif
}
@ -844,9 +862,14 @@ static int sanitizehost(char *buf)
return 1;
}
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
#define AUTH_FILE ".htpasswd"
static FILE * exist_check(struct connstruct *cn, const char *check_file)
{
char pathname[MAXREQUESTLENGTH];
snprintf(pathname, MAXREQUESTLENGTH, "%s/%s", cn->dirname, check_file);
return fopen(pathname, "r");
}
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
static void send_authenticate(struct connstruct *cn, const char *realm)
{
char buf[1024];
@ -857,30 +880,29 @@ static void send_authenticate(struct connstruct *cn, const char *realm)
special_write(cn, buf, strlen(buf));
}
static int check_digest(char *b64_file_passwd, const char *msg_passwd)
static int check_digest(char *salt, const char *msg_passwd)
{
uint8_t real_salt[MAXREQUESTLENGTH];
uint8_t real_passwd[MAXREQUESTLENGTH];
int real_passwd_size, real_salt_size;
char *b64_pwd;
uint8_t b256_salt[MAXREQUESTLENGTH];
uint8_t real_passwd[MD5_SIZE];
int salt_size;
char *b64_passwd;
uint8_t md5_result[MD5_SIZE];
MD5_CTX ctx;
/* retrieve the salt */
if ((b64_pwd = strchr(b64_file_passwd, '$')) == NULL)
if ((b64_passwd = strchr(salt, '$')) == NULL)
return -1;
*b64_pwd++ = 0;
if (base64_decode(b64_file_passwd, strlen(b64_file_passwd),
real_salt, &real_salt_size))
*b64_passwd++ = 0;
if (base64_decode(salt, strlen(salt), b256_salt, &salt_size))
return -1;
if (base64_decode(b64_pwd, strlen(b64_pwd), real_passwd, &real_passwd_size))
if (base64_decode(b64_passwd, strlen(b64_passwd), real_passwd, NULL))
return -1;
/* very simple MD5 crypt algorithm, but then the salt we use is large */
MD5Init(&ctx);
MD5Update(&ctx, real_salt, real_salt_size); /* process the salt */
MD5Update(&ctx, b256_salt, salt_size); /* process the salt */
MD5Update(&ctx, msg_passwd, strlen(msg_passwd)); /* process the password */
MD5Final(&ctx, md5_result);
return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */
@ -888,36 +910,15 @@ static int check_digest(char *b64_file_passwd, const char *msg_passwd)
static int auth_check(struct connstruct *cn)
{
char dirname[MAXREQUESTLENGTH];
char authpath[MAXREQUESTLENGTH];
char line[MAXREQUESTLENGTH];
FILE *fp;
char *cp;
FILE *fp = NULL;
struct stat auth_stat;
strncpy(dirname, cn->actualfile, MAXREQUESTLENGTH);
cp = strrchr(dirname, '/');
if (cp == NULL)
dirname[0] = 0;
else
*cp = 0;
/* check that the file is not the AUTH_FILE itself */
if (strcmp(cn->actualfile, AUTH_FILE) == 0)
{
send_error(cn, 403);
goto error;
}
snprintf(authpath, MAXREQUESTLENGTH, "%s/%s", dirname, AUTH_FILE);
if (stat(authpath, &auth_stat) < 0) /* no auth file, so let though */
return 0;
if ((fp = exist_check(cn, ".htpasswd")) == NULL)
return 0; /* no .htpasswd file, so let though */
if (cn->authorization[0] == 0)
{
send_authenticate(cn, dirname);
return -1;
}
goto error;
/* cn->authorization is in form "username:password" */
if ((cp = strchr(cn->authorization, ':')) == NULL)
@ -925,8 +926,6 @@ static int auth_check(struct connstruct *cn)
else
*cp++ = 0; /* cp becomes the password */
fp = fopen(authpath, "r");
while (fgets(line, sizeof(line), fp) != NULL)
{
char *b64_file_passwd;
@ -952,14 +951,41 @@ static int auth_check(struct connstruct *cn)
}
}
fclose(fp);
error:
send_authenticate(cn, dirname);
fclose(fp);
send_authenticate(cn, cn->virtualhostreq);
return -1;
}
#endif
static int htaccess_check(struct connstruct *cn)
{
char line[MAXREQUESTLENGTH];
FILE *fp;
int ret = 0;
if ((fp = exist_check(cn, ".htaccess")) == NULL)
return 0; /* no .htaccess file, so let though */
while (fgets(line, sizeof(line), fp) != NULL)
{
if (!cn->is_ssl && strstr(line, "SSLRequireSSL"))
{
ret = -1; /* SSL port access required */
break;
}
if (strstr(line, "Deny all"))
{
ret = -1; /* access to this dir denied */
break;
}
}
fclose(fp);
return ret;
}
static void send_error(struct connstruct *cn, int err)
{
char buf[1024];
@ -971,6 +997,10 @@ static void send_error(struct connstruct *cn, int err)
case 403:
title = "Forbidden";
text = "File is protected";
#ifdef CONFIG_HTTP_VERBOSE
printf("axhttpd: access to %s:/%s denied\n",
cn->is_ssl ? "https" : "http", cn->actualfile); TTY_FLUSH();
#endif
break;
case 404:
@ -979,9 +1009,12 @@ static void send_error(struct connstruct *cn, int err)
break;
}
sprintf(buf, "HTTP/1.1 %d %s\nContent-Type: text/html\n"
"<html><body>\n<title>%d %s</title>"
"<h1>%d %s</h1>\n</body></html>\n",
sprintf(buf, "HTTP/1.1 %d %s\n"
"Content-Type: text/html\n"
"Cache-Control: no-cache,no-store\n"
"Connection: close\n\n"
"<html>\n<head>\n<title>%d %s</title></head>\n"
"<body><h1>%d %s</h1>\n</body></html>\n",
err, title, err, title, err, text);
special_write(cn, buf, strlen(buf));
removeconnection(cn);