summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibaut Mattern <tmattern@users.sourceforge.net>2003-11-26 08:09:58 +0000
committerThibaut Mattern <tmattern@users.sourceforge.net>2003-11-26 08:09:58 +0000
commit6ec50a1fc262ec7c67ab20f0952524c0a8d4a766 (patch)
tree63dc8d214af1078b9a4bc04f975cd054805378fb
parentc7b9b54657e30dae0e9d49d040d91d384113f3b8 (diff)
downloadxine-lib-6ec50a1fc262ec7c67ab20f0952524c0a8d4a766.tar.gz
xine-lib-6ec50a1fc262ec7c67ab20f0952524c0a8d4a766.tar.bz2
http_helper:
add a http url parser input_http: use http_helper try to fix potential security holes CVS patchset: 5783 CVS date: 2003/11/26 08:09:58
-rw-r--r--src/input/Makefile.am4
-rw-r--r--src/input/http_helper.c258
-rw-r--r--src/input/http_helper.h38
-rw-r--r--src/input/input_http.c216
4 files changed, 353 insertions, 163 deletions
diff --git a/src/input/Makefile.am b/src/input/Makefile.am
index 0645e9173..dfa6c631f 100644
--- a/src/input/Makefile.am
+++ b/src/input/Makefile.am
@@ -92,7 +92,7 @@ xineplug_inp_rtp_la_SOURCES = input_rtp.c
xineplug_inp_rtp_la_LIBADD = $(XINE_LIB)
xineplug_inp_rtp_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
-xineplug_inp_http_la_SOURCES = input_http.c net_buf_ctrl.c
+xineplug_inp_http_la_SOURCES = input_http.c net_buf_ctrl.c http_helper.c
xineplug_inp_http_la_LIBADD = $(XINE_LIB)
xineplug_inp_http_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
@@ -125,4 +125,4 @@ xineplug_inp_pvr_la_LIBADD = $(XINE_LIB)
xineplug_inp_pvr_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
include_HEADERS = input_plugin.h
-noinst_HEADERS = net_buf_ctrl.h mms.h mmsh.h pnm.h media_helper.h videodev2.h
+noinst_HEADERS = net_buf_ctrl.h mms.h mmsh.h pnm.h media_helper.h videodev2.h http_helper.h
diff --git a/src/input/http_helper.c b/src/input/http_helper.c
new file mode 100644
index 000000000..730deccad
--- /dev/null
+++ b/src/input/http_helper.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2000-2003 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine 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.
+ *
+ * xine 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * URL helper functions
+ *
+ * $Id: http_helper.c,v 1.1 2003/11/26 08:09:58 tmattern Exp $
+ */
+#include "xine_internal.h"
+#include "http_helper.h"
+
+static char *_strndup(const char *s, size_t n) {
+ char *ret;
+
+ ret = malloc (n + 1);
+ strncpy(ret, s, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+int _x_parse_url (char *url, char **proto, char** host, int *port,
+ char **user, char **password, char **uri) {
+ char *start = NULL;
+ char *authcolon = NULL;
+ char *at = NULL;
+ char *portcolon = NULL;
+ char *slash = NULL;
+ char *end = NULL;
+ char *strtol_err = NULL;
+
+ if (!url) abort();
+ if (!proto) abort();
+ if (!user) abort();
+ if (!password) abort();
+ if (!host) abort();
+ if (!port) abort();
+ if (!uri) abort();
+
+ *proto = NULL;
+ *port = 0;
+ *user = NULL;
+ *host = NULL;
+ *password = NULL;
+ *uri = NULL;
+
+ /* proto */
+ start = strstr(url, "://");
+ end = start + strlen(start) - 1;
+ if (!start || (start == url))
+ goto error;
+
+ *proto = _strndup(url, start - url);
+
+ /* user:password */
+ start += 3;
+ at = strchr(start, '@');
+ slash = strchr(start, '/');
+
+ if (at && slash && (at > slash))
+ at = NULL;
+
+ if (at) {
+ authcolon = strchr(start, ':');
+ if(authcolon && authcolon < at) {
+ *user = _strndup(start, authcolon - start);
+ *password = _strndup(authcolon + 1, at - authcolon - 1);
+ if ((authcolon == start) || (at == (authcolon + 1))) goto error;
+ } else {
+ /* no password */
+ *user = _strndup(start, at - start);
+ if (at == start) goto error;
+ }
+ start = at + 1;
+ }
+
+ /* host:port (ipv4) */
+ /* [host]:port (ipv6) */
+ if (*start != '[')
+ {
+ /* ipv4*/
+ portcolon = strchr(start, ':');
+ if (slash) {
+ if (portcolon && portcolon < slash) {
+ *host = _strndup(start, portcolon - start);
+ if (portcolon == start) goto error;
+ *port = strtol(portcolon + 1, &strtol_err, 10);
+ if ((strtol_err != slash) || (strtol_err == portcolon + 1))
+ goto error;
+ } else {
+ *host = _strndup(start, slash - start);
+ if (slash == start) goto error;
+ }
+ } else {
+ if (portcolon) {
+ *host = _strndup(start, portcolon - start);
+ if (portcolon < end) {
+ *port = strtol(portcolon + 1, &strtol_err, 10);
+ if (*strtol_err != '\0') goto error;
+ } else {
+ goto error;
+ }
+ } else {
+ if (*start == '\0') goto error;
+ *host = strdup(start);
+ }
+ }
+ } else {
+ /* ipv6*/
+ char *hostendbracket;
+
+ hostendbracket = strchr(start, ']');
+ if (hostendbracket != NULL) {
+ if (hostendbracket == start + 1) goto error;
+ *host = _strndup(start + 1, hostendbracket - start - 1);
+
+ if (hostendbracket < end) {
+ /* Might have a trailing port */
+ if (*(hostendbracket + 1) == ':') {
+ portcolon = hostendbracket + 1;
+ if (portcolon < end) {
+ *port = strtol(portcolon + 1, &strtol_err, 10);
+ if ((*strtol_err != '\0') && (*strtol_err != '/')) goto error;
+ } else {
+ goto error;
+ }
+ }
+ }
+ } else {
+ goto error;
+ }
+ }
+
+ /* uri */
+ start = slash;
+ if (start)
+ *uri = strdup(start);
+ else
+ *uri = strdup("/");
+
+ return 1;
+
+error:
+ if (*proto) {
+ free (*proto);
+ *proto = NULL;
+ }
+ if (*user) {
+ free (*user);
+ *user = NULL;
+ }
+ if (*password) {
+ free (*password);
+ *password = NULL;
+ }
+ if (*host) {
+ free (*host);
+ *host = NULL;
+ }
+ if (*port) {
+ *port = 0;
+ }
+ if (*uri) {
+ free (*uri);
+ *uri = NULL;
+ }
+ return 0;
+}
+
+
+#ifdef TEST_URL
+/*
+ * url parser test program
+ */
+
+static int check_url(char *url, int ok) {
+ char *proto, *host, *user, *password, *uri;
+ int port;
+ int res;
+
+ printf("--------------------------------\n");
+ printf("url=%s\n", url);
+ res = _x_parse_url (url,
+ &proto, &host, &port, &user, &password, &uri);
+ if (res) {
+ printf("proto=%s, host=%s, port=%d, user=%s, password=%s, uri=%s\n",
+ proto, host, port, user, password, uri);
+ free(proto);
+ free(host);
+ free(user);
+ free(password);
+ free(uri);
+ } else {
+ printf("bad url\n");
+ }
+ if (res == ok) {
+ printf("test OK\n", url);
+ return 1;
+ } else {
+ printf("test KO\n", url);
+ return 0;
+ }
+}
+
+int main(int argc, char** argv) {
+ char *proto, host, port, user, password, uri;
+ int res = 0;
+
+ res += check_url("http://www.toto.com/test1.asx", 1);
+ res += check_url("http://www.toto.com:8080/test2.asx", 1);
+ res += check_url("http://titi:pass@www.toto.com:8080/test3.asx", 1);
+ res += check_url("http://www.toto.com", 1);
+ res += check_url("http://www.toto.com/", 1);
+ res += check_url("http://www.toto.com:80", 1);
+ res += check_url("http://www.toto.com:80/", 1);
+ res += check_url("http://www.toto.com:", 0);
+ res += check_url("http://www.toto.com:/", 0);
+ res += check_url("http://www.toto.com:abc", 0);
+ res += check_url("http://www.toto.com:abc/", 0);
+ res += check_url("http://titi@www.toto.com:8080/test4.asx", 1);
+ res += check_url("http://@www.toto.com:8080/test5.asx", 0);
+ res += check_url("http://:@www.toto.com:8080/test6.asx", 0);
+ res += check_url("http:///test6.asx", 0);
+ res += check_url("http://:/test7.asx", 0);
+ res += check_url("http://", 0);
+ res += check_url("http://:", 0);
+ res += check_url("http://@", 0);
+ res += check_url("http://:@", 0);
+ res += check_url("http://:/@", 0);
+ res += check_url("http://www.toto.com:80a/", 0);
+ res += check_url("http://[www.toto.com]", 1);
+ res += check_url("http://[www.toto.com]/", 1);
+ res += check_url("http://[www.toto.com]:80", 1);
+ res += check_url("http://[www.toto.com]:80/", 1);
+ res += check_url("http://[12:12]:80/", 1);
+ res += check_url("http://user:pass@[12:12]:80/", 1);
+ printf("================================\n");
+ if (res != 28) {
+ printf("result: KO\n");
+ } else {
+ printf("result: OK\n");
+ }
+}
+#endif
diff --git a/src/input/http_helper.h b/src/input/http_helper.h
new file mode 100644
index 000000000..a89f93c3b
--- /dev/null
+++ b/src/input/http_helper.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2000-2003 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine 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.
+ *
+ * xine 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * URL helper functions
+ *
+ * $Id: http_helper.h,v 1.1 2003/11/26 08:09:58 tmattern Exp $
+ */
+
+/*
+ * url parser
+ * {proto}://{user}:{password}@{host}:{port}{uri}
+ * {proto}://{user}:{password}@{[host]}:{port}{uri}
+ *
+ * return:
+ * 0 invalid url
+ * 1 valid url
+ */
+#ifndef HTTP_HELPER_H
+#define HTTP_HELPER_H
+int _x_parse_url (char *url, char **proto, char** host, int *port,
+ char **user, char **password, char **uri);
+#endif /* HTTP_HELPER_H */
diff --git a/src/input/input_http.c b/src/input/input_http.c
index 176cee289..e1a7bb9fa 100644
--- a/src/input/input_http.c
+++ b/src/input/input_http.c
@@ -19,7 +19,7 @@
*
* input plugin for http network streams
*
- * $Id: input_http.c,v 1.74 2003/11/16 23:33:44 f1rmb Exp $
+ * $Id: input_http.c,v 1.75 2003/11/26 08:09:58 tmattern Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -46,7 +46,7 @@
#include "xineutils.h"
#include "input_plugin.h"
#include "net_buf_ctrl.h"
-#include "io_helper.h"
+#include "http_helper.h"
/*
#define LOG
@@ -70,18 +70,17 @@ typedef struct {
off_t contentlength;
char buf[BUFSIZE];
- char mrlbuf[BUFSIZE];
- char mrlbuf2[BUFSIZE]; /* icecast */
char proxybuf[BUFSIZE];
char auth[BUFSIZE];
char proxyauth[BUFSIZE];
+ char *proto;
char *user;
char *password;
char *host;
int port;
- char *filename;
+ char *uri;
char preview[MAX_PREVIEW_SIZE];
off_t preview_size;
@@ -143,122 +142,6 @@ static void proxy_port_change_cb(void *data, xine_cfg_entry_t *cfg) {
this->proxyport = cfg->num_value;
}
-static int http_plugin_parse_url (char *urlbuf, char **user, char **password,
- char** host, int *port, char **filename) {
- char *start = NULL;
- char *authcolon = NULL;
- char *at = NULL;
- char *portcolon = NULL;
- char *slash = NULL;
-
- if (user != NULL)
- *user = NULL;
-
- if (password != NULL)
- *password = NULL;
-
- if (host != NULL)
- *host = NULL;
-
- if (filename != NULL)
- *filename = NULL;
-
- if (port != NULL)
- *port = 0;
-
- start = strstr(urlbuf, "://");
- if (start != NULL)
- start += 3;
- else
- start = urlbuf;
-
- at = strchr(start, '@');
- slash = strchr(start, '/');
-
- if (at != NULL && slash != NULL && at > slash)
- at = NULL;
-
- if (at != NULL)
- {
- authcolon = strchr(start, ':');
- if(authcolon != NULL && authcolon > at)
- authcolon = NULL;
-
- portcolon = strchr(at, ':');
- } else
- portcolon = strchr(start, ':');
-
- if (portcolon != NULL && slash != NULL && portcolon > slash)
- portcolon = NULL;
-
- if (at != NULL)
- {
- *at = '\0';
-
- if (user != NULL)
- *user = start;
-
- if (authcolon != NULL)
- {
- *authcolon = '\0';
-
- if (password != NULL)
- *password = authcolon + 1;
- }
-
- if (host != NULL)
- *host = at + 1;
- } else
- if (host != NULL)
- *host = start;
-
-#ifdef ENABLE_IPV6
- /* Add support for RFC 2732 */
- {
- char *hostbracket, *hostendbracket;
-
- hostbracket = strchr(start, '[');
- if (hostbracket != NULL) {
-
- hostendbracket = strchr(hostbracket, ']');
-
- if (hostendbracket != NULL) {
-
- *hostendbracket = '\0';
- *host = (hostbracket + 1);
-
- /* Might have a trailing port */
-
- if (*(hostendbracket+1) == ':') {
- portcolon = (hostendbracket + 1);
- }
- }
- }
- }
-#endif
-
- if (slash != 0)
- {
- *slash = '\0';
-
- if (filename != NULL)
- *filename = slash + 1;
- } else {
- if (filename != NULL)
- *filename = urlbuf + strlen(urlbuf);
- }
-
- if (portcolon != NULL)
- {
- *portcolon = '\0';
-
- if (port != NULL)
- *port = atoi(portcolon + 1);
- }
-
- return 0;
-}
-
static int http_plugin_basicauth (const char *user, const char *password, char* dest, int len) {
static char *enctable="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
char *tmp;
@@ -563,8 +446,8 @@ static uint32_t http_plugin_get_capabilities (input_plugin_t *this_gen) {
uint32_t caps = INPUT_CAP_PREVIEW;
/* Nullsoft asked to not allow saving streaming nsv files */
- if (this->filename &&
- !strncmp(this->filename + strlen(this->filename) - 4, ".nsv", 4))
+ if (this->uri &&
+ !strncmp(this->uri + strlen(this->uri) - 4, ".nsv", 4))
caps |= INPUT_CAP_RIP_FORBIDDEN;
return caps;
@@ -622,7 +505,7 @@ static off_t http_plugin_seek(input_plugin_t *this_gen, off_t offset, int origin
static char* http_plugin_get_mrl (input_plugin_t *this_gen) {
http_input_plugin_t *this = (http_input_plugin_t *) this_gen;
- return this->mrlbuf2;
+ return this->mrl;
}
static int http_plugin_get_optional_data (input_plugin_t *this_gen,
@@ -655,6 +538,12 @@ static void http_plugin_dispose (input_plugin_t *this_gen ) {
this->nbc = NULL;
}
+ if (this->mrl) free(this->mrl);
+ if (this->proto) free(this->proto);
+ if (this->host) free(this->host);
+ if (this->user) free(this->user);
+ if (this->password) free(this->password);
+ if (this->uri) free(this->uri);
free (this);
}
@@ -676,10 +565,10 @@ static void report_progress (xine_stream_t *stream, int p) {
static int http_plugin_open (input_plugin_t *this_gen ) {
http_input_plugin_t *this = (http_input_plugin_t *) this_gen;
http_input_class_t *this_class = (http_input_class_t *) this->input_plugin.input_class;
- int done,len,linenum;
+ int done, len, linenum;
int shoutcast = 0, httpcode;
- int length;
int res, progress;
+ int buflen;
this->shoutcast_pos = 0;
@@ -698,10 +587,11 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
}
- if (http_plugin_parse_url (this->mrlbuf, &this->user, &this->password,
- &this->host, &this->port, &this->filename))
+ if (!_x_parse_url(this->mrl, &this->proto, &this->host, &this->port,
+ &this->user, &this->password, &this->uri)) {
+ _x_message(this->stream, XINE_MSG_GENERAL_WARNING, "malformed url", NULL);
return 0;
-
+ }
if (this->port == 0)
this->port = DEFAULT_HTTP_PORT;
@@ -745,40 +635,46 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
if (this_class->proxyhost && strlen(this_class->proxyhost)) {
if (this->port != DEFAULT_HTTP_PORT) {
- sprintf (this->buf, "GET http://%s:%d/%s HTTP/1.0\015\012",
- this->host, this->port, this->filename);
+ snprintf (this->buf, BUFSIZE, "GET http://%s:%d%s HTTP/1.0\015\012",
+ this->host, this->port, this->uri);
} else {
- sprintf (this->buf, "GET http://%s/%s HTTP/1.0\015\012",
- this->host, this->filename);
+ snprintf (this->buf, BUFSIZE, "GET http://%s%s HTTP/1.0\015\012",
+ this->host, this->uri);
}
}
else
- sprintf (this->buf, "GET /%s HTTP/1.0\015\012", this->filename);
+ snprintf (this->buf, BUFSIZE, "GET %s HTTP/1.0\015\012", this->uri);
+ buflen = strlen(this->buf);
if (this->port != DEFAULT_HTTP_PORT)
- sprintf (this->buf + strlen(this->buf), "Host: %s:%d\015\012",
+ snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s:%d\015\012",
this->host, this->port);
else
- sprintf (this->buf + strlen(this->buf), "Host: %s\015\012",
+ snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s\015\012",
this->host);
- if (this_class->proxyuser && strlen(this_class->proxyuser))
- sprintf (this->buf + strlen(this->buf), "Proxy-Authorization: Basic %s\015\012",
- this->proxyauth);
-
- if (this->user && strlen(this->user))
- sprintf (this->buf + strlen(this->buf), "Authorization: Basic %s\015\012",
- this->auth);
-
- sprintf (this->buf + strlen(this->buf), "User-Agent: xine/%s\015\012",
- VERSION);
- strcat (this->buf, "Accept: */*\015\012"); /* * */
- strcat (this->buf, "Icy-MetaData: 1\015\012");
+ buflen = strlen(this->buf);
+ if (this_class->proxyuser && strlen(this_class->proxyuser)) {
+ snprintf (this->buf + buflen, BUFSIZE - buflen,
+ "Proxy-Authorization: Basic %s\015\012", this->proxyauth);
+ buflen = strlen(this->buf);
+ }
+ if (this->user && strlen(this->user)) {
+ snprintf (this->buf + buflen, BUFSIZE - buflen,
+ "Authorization: Basic %s\015\012", this->auth);
+ buflen = strlen(this->buf);
+ }
- strcat (this->buf, "\015\012");
-
- length = strlen(this->buf);
- if (_x_io_tcp_write (this->stream, this->fh, this->buf, length) != length) {
+ snprintf (this->buf + buflen, BUFSIZE - buflen,
+ "User-Agent: xine/%s\015\012", VERSION);
+ buflen = strlen(this->buf);
+ strncat (this->buf, "Accept: */*\015\012", BUFSIZE - buflen); /* * */
+ buflen = strlen(this->buf);
+ strncat (this->buf, "Icy-MetaData: 1\015\012", BUFSIZE - buflen);
+ buflen = strlen(this->buf);
+ strncat (this->buf, "\015\012", BUFSIZE - buflen);
+ buflen = strlen(this->buf);
+ if (_x_io_tcp_write (this->stream, this->fh, this->buf, buflen) != buflen) {
_x_message(this->stream, XINE_MSG_CONNECTION_REFUSED, "couldn't send request", NULL);
xprintf(this_class->xine, XINE_VERBOSITY_DEBUG, "input_http: couldn't send request\n");
return 0;
@@ -861,8 +757,8 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
lprintf ("input_http: trying to open target of redirection: >%s<\n", href);
- strncpy (this->mrlbuf, href, BUFSIZE);
- strncpy (this->mrlbuf2, href, BUFSIZE);
+ free(this->mrl);
+ this->mrl = strdup(href);
return http_plugin_open(this_gen);
}
}
@@ -891,10 +787,10 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
this->shoutcast_songtitle = NULL;
if (shoutcast ||
!strncasecmp(this->preview, "ICY", 3)) {
- this->mrlbuf2[0] = 'i';
- this->mrlbuf2[1] = 'c';
- this->mrlbuf2[2] = 'e';
- this->mrlbuf2[3] = ' ';
+ this->mrl[0] = 'i';
+ this->mrl[1] = 'c';
+ this->mrl[2] = 'e';
+ this->mrl[3] = ' ';
if (read_shoutcast_header(this)) {
/* problem when reading shoutcast header */
_x_message(this->stream, XINE_MSG_CONNECTION_REFUSED, "can't read shoutcast header", NULL);
@@ -923,9 +819,7 @@ static input_plugin_t *http_class_get_instance (input_class_t *cls_gen, xine_str
}
this = (http_input_plugin_t *) xine_xmalloc(sizeof(http_input_plugin_t));
- strncpy (this->mrlbuf, mrl, BUFSIZE);
- strncpy (this->mrlbuf2, mrl, BUFSIZE);
- this->mrl = this->mrlbuf2;
+ this->mrl = strdup(mrl);
this->stream = stream;
this->fh = -1;
this->nbc = nbc_init (this->stream);