Added decoder for HTML-encoded and URL-encoded passwords and usernames.

This prevents special characters from not being recognized. Reported by P.H.Vos.
Also updated gnulib and added c-strncasecmp
This commit is contained in:
Nikos Mavrogiannopoulos
2013-07-10 15:52:26 +02:00
parent 90c2f89c4d
commit 2af67c4aff
22 changed files with 356 additions and 33 deletions

1
NEWS
View File

@@ -10,6 +10,7 @@
- Added test suite. It requires "make check" to be run as root (in order
to be able to run the server).
- Bypass the AnyConnect auto-download mechanism. Patch by Kevin Cernekee.
- Unescape HTML-formatted passwords, or usernames. Reported by P.H. Vos.
* Version 0.1.4 (released 2013-06-15)

View File

@@ -1088,15 +1088,7 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* _GL_INLINE is a portable alternative to ISO C99 plain 'inline'.
_GL_EXTERN_INLINE is a portable alternative to 'extern inline'.
_GL_INLINE_HEADER_BEGIN contains useful stuff to put
in an include file, before uses of _GL_INLINE.
It suppresses GCC's bogus "no previous prototype for 'FOO'" diagnostic,
when FOO is an inline function in the header; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>.
_GL_INLINE_HEADER_END contains useful stuff to put
in the same include file, after uses of _GL_INLINE.
/* Please see the Gnulib manual for how to use these macros.
Suppress extern inline with HP-UX cc, as it appears to be broken; see
<http://lists.gnu.org/archive/html/bug-texinfo/2013-02/msg00030.html>.
@@ -1119,7 +1111,8 @@
&& !defined __APPLE__)
# define _GL_INLINE inline
# define _GL_EXTERN_INLINE extern inline
#elif 2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __APPLE__
#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \
&& !defined __APPLE__)
# if __GNUC_GNU_INLINE__
/* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */
# define _GL_INLINE extern inline __attribute__ ((__gnu_inline__))
@@ -1139,6 +1132,10 @@
# define _GL_INLINE_HEADER_CONST_PRAGMA \
_Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=const\"")
# endif
/* Suppress GCC's bogus "no previous prototype for 'FOO'"
and "no previous declaration for 'FOO'" diagnostics,
when FOO is an inline function in the header; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>. */
# define _GL_INLINE_HEADER_BEGIN \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wmissing-prototypes\"") \

View File

@@ -2,8 +2,8 @@
# all should succeed.
# Options: certificate, pam.
#auth = "certificate"
#auth = "plain[./sample.passwd]"
auth = "pam"
auth = "plain[./sample.passwd]"
#auth = "pam"
# A banner to be displayed on clients
#banner = "Welcome"

View File

@@ -1 +1,2 @@
test:tost:$5$i6SNmLDCgBNjyJ7q$SZ4bVJb7I/DLgXo3txHBVohRFBjOtdbxGQZp.DOnrA.
tost:*:$5$qc1CKWjcmlrFREe2$h9zQJcD3AeuQmwMncdIqqls47TDOUvu2r2nXQ7aDfcD

View File

@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --lgpl=2 --no-conditional-dependencies --no-libtool --macro-prefix=gl c-ctype cloexec getline getpass memmem minmax
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --lgpl=2 --no-conditional-dependencies --no-libtool --macro-prefix=gl c-ctype c-strcase cloexec getline getpass memmem minmax
AUTOMAKE_OPTIONS = 1.9.6 gnits
@@ -55,6 +55,12 @@ libgnu_a_SOURCES += c-ctype.h c-ctype.c
## end gnulib module c-ctype
## begin gnulib module c-strcase
libgnu_a_SOURCES += c-strcase.h c-strcasecmp.c c-strncasecmp.c
## end gnulib module c-strcase
## begin gnulib module cloexec
libgnu_a_SOURCES += cloexec.c

View File

@@ -136,7 +136,8 @@ extern int c_tolower (int c) _GL_ATTRIBUTE_CONST;
extern int c_toupper (int c) _GL_ATTRIBUTE_CONST;
#if defined __GNUC__ && defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ && !defined NO_C_CTYPE_MACROS
#if (defined __GNUC__ && !defined __STRICT_ANSI__ && defined __OPTIMIZE__ \
&& !defined __OPTIMIZE_SIZE__ && !defined NO_C_CTYPE_MACROS)
/* ASCII optimizations. */

56
gl/c-strcase.h Normal file
View File

@@ -0,0 +1,56 @@
/* Case-insensitive string comparison functions in C locale.
Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2013 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef C_STRCASE_H
#define C_STRCASE_H
#include <stddef.h>
/* The functions defined in this file assume the "C" locale and a character
set without diacritics (ASCII-US or EBCDIC-US or something like that).
Even if the "C" locale on a particular system is an extension of the ASCII
character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
is ISO-8859-1), the functions in this file recognize only the ASCII
characters. More precisely, one of the string arguments must be an ASCII
string; the other one can also contain non-ASCII characters (but then
the comparison result will be nonzero). */
#ifdef __cplusplus
extern "C" {
#endif
/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
greater than zero if S1 is lexicographically less than, equal to or greater
than S2. */
extern int c_strcasecmp (const char *s1, const char *s2) _GL_ATTRIBUTE_PURE;
/* Compare no more than N characters of strings S1 and S2, ignoring case,
returning less than, equal to or greater than zero if S1 is
lexicographically less than, equal to or greater than S2. */
extern int c_strncasecmp (const char *s1, const char *s2, size_t n)
_GL_ATTRIBUTE_PURE;
#ifdef __cplusplus
}
#endif
#endif /* C_STRCASE_H */

56
gl/c-strcasecmp.c Normal file
View File

@@ -0,0 +1,56 @@
/* c-strcasecmp.c -- case insensitive string comparator in C locale
Copyright (C) 1998-1999, 2005-2006, 2009-2013 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
/* Specification. */
#include "c-strcase.h"
#include <limits.h>
#include "c-ctype.h"
int
c_strcasecmp (const char *s1, const char *s2)
{
register const unsigned char *p1 = (const unsigned char *) s1;
register const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
if (p1 == p2)
return 0;
do
{
c1 = c_tolower (*p1);
c2 = c_tolower (*p2);
if (c1 == '\0')
break;
++p1;
++p2;
}
while (c1 == c2);
if (UCHAR_MAX <= INT_MAX)
return c1 - c2;
else
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
}

56
gl/c-strncasecmp.c Normal file
View File

@@ -0,0 +1,56 @@
/* c-strncasecmp.c -- case insensitive string comparator in C locale
Copyright (C) 1998-1999, 2005-2006, 2009-2013 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
/* Specification. */
#include "c-strcase.h"
#include <limits.h>
#include "c-ctype.h"
int
c_strncasecmp (const char *s1, const char *s2, size_t n)
{
register const unsigned char *p1 = (const unsigned char *) s1;
register const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
if (p1 == p2 || n == 0)
return 0;
do
{
c1 = c_tolower (*p1);
c2 = c_tolower (*p2);
if (--n == 0 || c1 == '\0')
break;
++p1;
++p2;
}
while (c1 == c2);
if (UCHAR_MAX <= INT_MAX)
return c1 - c2;
else
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
}

View File

@@ -19,7 +19,7 @@
/* Specification. */
#include <stdio.h>
/* Get off_t and lseek. */
/* Get off_t, lseek, _POSIX_VERSION. */
#include <unistd.h>
#include "stdio-impl.h"
@@ -99,8 +99,14 @@ fseeko (FILE *fp, off_t offset, int whence)
#elif defined EPLAN9 /* Plan9 */
if (fp->rp == fp->buf
&& fp->wp == fp->buf)
#elif FUNC_FFLUSH_STDIN < 0 && 200809 <= _POSIX_VERSION
/* Cross-compiling to some other system advertising conformance to
POSIX.1-2008 or later. Assume fseeko and fflush work as advertised.
If this assumption is incorrect, please report the bug to
bug-gnulib. */
if (0)
#else
#error "Please port gnulib fseeko.c to your platform! Look at the code in fpurge.c, then report this to bug-gnulib."
#error "Please port gnulib fseeko.c to your platform! Look at the code in fseeko.c, then report this to bug-gnulib."
#endif
{
/* We get here when an fflush() call immediately preceded this one (or

View File

@@ -8,15 +8,7 @@ dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_EXTERN_INLINE],
[
AH_VERBATIM([extern_inline],
[/* _GL_INLINE is a portable alternative to ISO C99 plain 'inline'.
_GL_EXTERN_INLINE is a portable alternative to 'extern inline'.
_GL_INLINE_HEADER_BEGIN contains useful stuff to put
in an include file, before uses of _GL_INLINE.
It suppresses GCC's bogus "no previous prototype for 'FOO'" diagnostic,
when FOO is an inline function in the header; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>.
_GL_INLINE_HEADER_END contains useful stuff to put
in the same include file, after uses of _GL_INLINE.
[/* Please see the Gnulib manual for how to use these macros.
Suppress extern inline with HP-UX cc, as it appears to be broken; see
<http://lists.gnu.org/archive/html/bug-texinfo/2013-02/msg00030.html>.
@@ -39,7 +31,8 @@ AC_DEFUN([gl_EXTERN_INLINE],
&& !defined __APPLE__)
# define _GL_INLINE inline
# define _GL_EXTERN_INLINE extern inline
#elif 2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __APPLE__
#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \
&& !defined __APPLE__)
# if __GNUC_GNU_INLINE__
/* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */
# define _GL_INLINE extern inline __attribute__ ((__gnu_inline__))
@@ -59,6 +52,10 @@ AC_DEFUN([gl_EXTERN_INLINE],
# define _GL_INLINE_HEADER_CONST_PRAGMA \
_Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=const\"")
# endif
/* Suppress GCC's bogus "no previous prototype for 'FOO'"
and "no previous declaration for 'FOO'" diagnostics,
when FOO is an inline function in the header; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>. */
# define _GL_INLINE_HEADER_BEGIN \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wmissing-prototypes\"") \

View File

@@ -1,4 +1,4 @@
# fseeko.m4 serial 16
# fseeko.m4 serial 17
dnl Copyright (C) 2007-2013 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -37,7 +37,7 @@ AC_DEFUN([gl_FUNC_FSEEKO],
fi
m4_ifdef([gl_FUNC_FFLUSH_STDIN], [
gl_FUNC_FFLUSH_STDIN
if test $gl_cv_func_fflush_stdin = no; then
if test $gl_cv_func_fflush_stdin != yes; then
REPLACE_FSEEKO=1
fi
])

View File

@@ -27,12 +27,13 @@
# Specification in the form of a command-line invocation:
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --lgpl=2 --no-conditional-dependencies --no-libtool --macro-prefix=gl c-ctype cloexec getline getpass memmem minmax
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --lgpl=2 --no-conditional-dependencies --no-libtool --macro-prefix=gl c-ctype c-strcase cloexec getline getpass memmem minmax
# Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([])
gl_MODULES([
c-ctype
c-strcase
cloexec
getline
getpass

View File

@@ -39,6 +39,7 @@ AC_DEFUN([gl_EARLY],
m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable
AC_REQUIRE([gl_PROG_AR_RANLIB])
# Code from module c-ctype:
# Code from module c-strcase:
# Code from module cloexec:
# Code from module close:
# Code from module dup2:
@@ -370,6 +371,9 @@ AC_DEFUN([gl_FILE_LIST], [
build-aux/snippet/warn-on-use.h
lib/c-ctype.c
lib/c-ctype.h
lib/c-strcase.h
lib/c-strcasecmp.c
lib/c-strncasecmp.c
lib/cloexec.c
lib/cloexec.h
lib/close.c

View File

@@ -28,7 +28,7 @@
# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
static void cdecl
static void __cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
@@ -45,7 +45,7 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
# if defined _MSC_VER
static void cdecl
static void __cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
@@ -94,7 +94,7 @@ gl_msvc_inval_current (void)
}
}
static void cdecl
static void __cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,

View File

@@ -18,7 +18,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
worker-extras.c main-auth.h \
worker-extras.c main-auth.h html.c html.h \
main-user.c worker-misc.c setproctitle.h \
setproctitle.c worker-privs.c plain.c plain.h common.h common.c \
sec-mod.c sec-mod.h script-list.h system.c system.h icmp-ping.c icmp-ping.h \

104
src/html.c Normal file
View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <c-strcase.h>
#include "html.h"
char *unescape_html(const char *html, unsigned len, unsigned *out_len)
{
char *msg;
int pos;
unsigned i;
msg = malloc(len + 1);
if (msg == NULL)
return NULL;
for (i = pos = 0; i < len;) {
if (html[i] == '&') {
if (!c_strncasecmp(&html[i], "&lt;", 4)) {
msg[pos++] = '<';
i += 4;
} else if (!c_strncasecmp(&html[i], "&gt;", 4)) {
msg[pos++] = '>';
i += 4;
} else if (!c_strncasecmp(&html[i], "&nbsp;", 6)) {
msg[pos++] = ' ';
i += 6;
} else if (!c_strncasecmp(&html[i], "&quot;", 6)) {
msg[pos++] = '"';
i += 6;
} else if (!c_strncasecmp(&html[i], "&amp;", 5)) {
msg[pos++] = '&';
i += 5;
} else if (!c_strncasecmp(&html[i], "&apos;", 6)) {
msg[pos++] = '\'';
i += 6;
} else
msg[pos++] = html[i++];
} else
msg[pos++] = html[i++];
}
msg[pos] = 0;
if (out_len)
*out_len = pos;
return msg;
}
char *unescape_url(const char *url, unsigned len, unsigned *out_len)
{
char *msg;
int pos;
unsigned i;
msg = malloc(len + 1);
if (msg == NULL)
return NULL;
for (i = pos = 0; i < len;) {
if (url[i] == '%') {
char b[3];
unsigned int u;
b[0] = url[pos + 1];
b[1] = url[pos + 2];
b[2] = 0;
sscanf(b, "%02x", &u);
msg[pos++] = u;
i += 3;
} else
msg[pos++] = url[i++];
}
msg[pos] = 0;
if (out_len)
*out_len = pos;
return msg;
}

7
src/html.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef OC_HTML_H
# define OC_HTML_H
char* unescape_html(const char *html, unsigned len, unsigned *out_len);
char *unescape_url(const char *url, unsigned len, unsigned *out_len);
#endif

View File

@@ -133,6 +133,7 @@ struct plain_ctx_st* pctx = ctx;
if (pctx->cpass[0] != 0 && strcmp(crypt(pass, pctx->cpass), pctx->cpass) == 0)
return 0;
else {
fprintf(stderr, "pass: %s\n", pass);
syslog(LOG_AUTH, "error in plain authentication; error in user '%s'", pctx->username);
return ERR_AUTH_FAIL;
}

View File

@@ -34,6 +34,7 @@
#include <vpn.h>
#include "ipc.h"
#include "html.h"
#include <worker.h>
#include <cookies.h>
#include <tlslib.h>
@@ -471,6 +472,9 @@ char msg[MAX_BANNER_SIZE+32];
#define XMLUSER_END "</username>"
#define XMLPASS_END "</password>"
/* Returns the username and password in newly allocated
* buffers.
*/
static
int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** username, char** password)
{
@@ -506,6 +510,8 @@ int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** usern
}
p++;
}
*username = unescape_html(*username, strlen(*username), NULL);
}
if (password != NULL) {
@@ -516,7 +522,10 @@ int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** usern
break;
}
p++;
}
*password = unescape_html(*password, strlen(*password), NULL);
}
} else { /* non-xml version */
@@ -547,6 +556,8 @@ int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** usern
}
p++;
}
*username = unescape_url(*username, strlen(*username), NULL);
}
if (password != NULL) {
@@ -558,8 +569,17 @@ int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** usern
}
p++;
}
*password = unescape_url(*password, strlen(*password), NULL);
}
}
if (username != NULL && *username == NULL)
return -1;
if (password != NULL && *password == NULL)
return -1;
return 0;
}
@@ -583,6 +603,7 @@ struct cmd_auth_reply_st resp;
goto ask_auth;
snprintf(areq.user, sizeof(areq.user), "%s", username);
free(username);
areq.user_present = 1;
}
@@ -620,6 +641,7 @@ struct cmd_auth_reply_st resp;
goto ask_auth;
areq.pass_size = snprintf(areq.pass, sizeof(areq.pass), "%s", password);
free(password);
ret = auth_user_pass(ws, &areq);
if (ret < 0)

View File

@@ -39,6 +39,12 @@ echo "Connecting to obtain cookie with wrong username..."
( echo "tost" | openconnect -q localhost:4443 -u tost --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly >/dev/null 2>&1 ) &&
fail $PID "Received cookie when we shouldn't"
#test special characters
echo "Connecting to obtain cookie..."
( echo "!@#$%^&*()<>" | openconnect -q localhost:4443 -u special --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly >/dev/null 2>&1 ) ||
fail $PID "Could not receive cookie from server"
#echo "Normal connection..."
#( echo "test" | openconnect -q localhost:4443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --script=/bin/true ) ||
# fail $PID "Could not connect to server"

View File

@@ -1 +1,2 @@
test:tost:$5$i6SNmLDCgBNjyJ7q$SZ4bVJb7I/DLgXo3txHBVohRFBjOtdbxGQZp.DOnrA.
special:*:$5$kDNrlGibUoktiQ0n$mE/ys1XehvvoWQiSqAfB.Aw1WbAYayMV/ZYTX/6IlkC