X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fhttpd.c;h=f217f7d57abf2d5d59b783e620d8a20fd7f46e5e;hb=aed69fef6220413ac7cd26d36d294ba4c9156015;hp=c06d3651edcc39fbd87e9b2e8ce48e63f5b655d7;hpb=f59392ef8d88190f0ad891222c405741147ad499;p=vlc diff --git a/src/misc/httpd.c b/src/misc/httpd.c index c06d3651ed..f217f7d57a 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -1,7 +1,7 @@ /***************************************************************************** * httpd.c ***************************************************************************** - * Copyright (C) 2004-2005 VideoLAN + * Copyright (C) 2004-2005 the VideoLAN team * $Id$ * * Authors: Laurent Aimar @@ -30,6 +30,7 @@ #include "vlc_httpd.h" #include "network.h" #include "vlc_tls.h" +#include "vlc_acl.h" #include #include @@ -234,9 +235,10 @@ struct httpd_url_t vlc_mutex_t lock; - char *psz_url; - char *psz_user; - char *psz_password; + char *psz_url; + char *psz_user; + char *psz_password; + vlc_acl_t *p_acl; struct { @@ -362,8 +364,8 @@ static void b64_decode( char *dest, char *src ) static struct { - char *psz_ext; - char *psz_mime; + const char *psz_ext; + const char *psz_mime; } http_mime[] = { { ".htm", "text/html" }, @@ -407,7 +409,7 @@ static struct /* end */ { NULL, NULL } }; -static char *httpd_MimeFromUrl( char *psz_url ) +static const char *httpd_MimeFromUrl( const char *psz_url ) { char *psz_ext; @@ -464,7 +466,7 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, if( query->i_type != HTTPD_MSG_HEAD ) { - char *psz_args = query->psz_args; + uint8_t *psz_args = query->psz_args; if( query->i_type == HTTPD_MSG_POST ) { /* Check that */ @@ -487,15 +489,16 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_file_t *httpd_FileNew( httpd_host_t *host, - char *psz_url, char *psz_mime, - char *psz_user, char *psz_password, - httpd_file_callback_t pf_fill, + const char *psz_url, const char *psz_mime, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys ) { httpd_file_t *file = malloc( sizeof( httpd_file_t ) ); if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, p_acl ) + ) == NULL ) { free( file ); return NULL; @@ -561,16 +564,22 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, answer->psz_status = strdup( "Moved Permanently" ); p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Redirection\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

You should be redirected

\n", rdir->psz_dst ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "\n" + "\n" + "\n" + "\n" + "Redirection\n" + "\n" + "\n" + "

You should be " + "redirected

\n" + "
\n" + "

VideoLAN\n

" + "
\n" + "\n" + "\n", rdir->psz_dst ); answer->i_body = p - answer->p_body; /* XXX check if it's ok or we need to set an absolute url */ @@ -581,12 +590,12 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, return VLC_SUCCESS; } -httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, - char *psz_url_src ) +httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst, + const char *psz_url_src ) { httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) ); - if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) ) + if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, NULL ) ) ) { free( rdir ); return NULL; @@ -760,13 +769,15 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, } httpd_stream_t *httpd_StreamNew( httpd_host_t *host, - char *psz_url, char *psz_mime, - char *psz_user, char *psz_password ) + const char *psz_url, const char *psz_mime, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, p_acl ) + ) == NULL ) { free( stream ); return NULL; @@ -890,6 +901,9 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, vlc_value_t lockval; int i; + if( psz_hostname == NULL ) + psz_hostname = ""; + psz_host = strdup( psz_hostname ); if( psz_host == NULL ) { @@ -1088,9 +1102,9 @@ void httpd_HostDelete( httpd_host_t *host ) } /* register a new url */ -static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password, - vlc_bool_t b_check ) +static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl, vlc_bool_t b_check ) { httpd_url_t *url; int i; @@ -1117,6 +1131,7 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, url->psz_url = strdup( psz_url ); url->psz_user = strdup( psz_user ? psz_user : "" ); url->psz_password = strdup( psz_password ? psz_password : "" ); + url->p_acl = ACL_Duplicate( host, p_acl ); for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; @@ -1129,18 +1144,20 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, return url; } -httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) +httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_FALSE ); + psz_password, p_acl, VLC_FALSE ); } -httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) +httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_TRUE ); + psz_password, p_acl, VLC_TRUE ); } /* register callback on a url */ @@ -1169,6 +1186,7 @@ void httpd_UrlDelete( httpd_url_t *url ) free( url->psz_url ); free( url->psz_user ); free( url->psz_password ); + ACL_Destroy( url->p_acl ); for( i = 0; i < host->i_client; i++ ) { @@ -1311,55 +1329,14 @@ void httpd_ClientModeBidir( httpd_client_t *cl ) cl->i_mode = HTTPD_CLIENT_BIDIR; } -/* - * FIXME: use vlc_getnameinfo - */ -char* httpd_ClientIP( httpd_client_t *cl ) +char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { -#ifdef HAVE_GETNAMEINFO - char sz_ip[INET6_ADDRSTRLEN + 2]; - int i; - - if( (cl->sock.ss_family == AF_INET6) && - IN6_IS_ADDR_V4MAPPED( &((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr) ) - { - /* If client is using IPv4 but server is using IPv6 */ - struct sockaddr_in a; - - memset( &a, 0, sizeof( a ) ); - a.sin_family = AF_INET; - a.sin_port = ((const struct sockaddr_in6 *)&cl->sock)->sin6_port; - a.sin_addr.s_addr = ((const uint32_t *)&((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr)[3]; - i = getnameinfo( (const struct sockaddr *)&a, sizeof( a ), - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST ); - } - else - i = getnameinfo( (const struct sockaddr *)&cl->sock, cl->i_sock_size, - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, - NI_NUMERICHOST ); - - if( i != 0 ) - /* FIXME: msg_Err */ - return NULL; - - if( strchr( &sz_ip[1], ':' ) != NULL ) - { - *sz_ip = '['; - i = strlen( sz_ip ); - sz_ip[i++] = ']'; - sz_ip[i] = '\0'; - - return strdup( sz_ip ); - } - - return strdup( &sz_ip[1] ); + return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip; +} -#else - /* FIXME not thread safe */ - return strdup( inet_ntoa( ((const struct sockaddr_in *)&cl->sock)->sin_addr ) ); -#endif +char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) +{ + return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip; } static void httpd_ClientClean( httpd_client_t *cl ) @@ -1400,7 +1377,7 @@ static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock, } -static int httpd_NetRecv( httpd_client_t *cl, char *p, int i_len ) +static int httpd_NetRecv( httpd_client_t *cl, uint8_t *p, int i_len ) { tls_session_t *p_tls; @@ -1412,7 +1389,7 @@ static int httpd_NetRecv( httpd_client_t *cl, char *p, int i_len ) } -static int httpd_NetSend( httpd_client_t *cl, const char *p, int i_len ) +static int httpd_NetSend( httpd_client_t *cl, const uint8_t *p, int i_len ) { tls_session_t *p_tls; @@ -1453,19 +1430,19 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_buffer = 0; } - else if( !strncmp( cl->p_buffer, "HTTP", 4 ) ) + else if( !memcmp( cl->p_buffer, "HTTP", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_type = HTTPD_MSG_ANSWER; } - else if( !strncmp( cl->p_buffer, "RTSP", 4 ) ) + else if( !memcmp( cl->p_buffer, "RTSP", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; cl->query.i_type = HTTPD_MSG_ANSWER; } - else if( !strncmp( cl->p_buffer, "GET", 3 ) || - !strncmp( cl->p_buffer, "HEAD", 4 ) || - !strncmp( cl->p_buffer, "POST", 4 ) ) + else if( !memcmp( cl->p_buffer, "GET", 3 ) || + !memcmp( cl->p_buffer, "HEAD", 4 ) || + !memcmp( cl->p_buffer, "POST", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_type = HTTPD_MSG_NONE; @@ -1508,8 +1485,8 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_buffer_size += 1024; cl->p_buffer = realloc( cl->p_buffer, cl->i_buffer_size ); } - if( ( cl->i_buffer >= 2 && !strncmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )|| - ( cl->i_buffer >= 4 && !strncmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) ) + if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )|| + ( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) ) { char *p; @@ -1518,8 +1495,12 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( cl->query.i_type == HTTPD_MSG_ANSWER ) { + /* FIXME: + * assume strlen( "HTTP/1.x" ) = 8 + */ cl->query.i_status = - strtol( &cl->p_buffer[strlen( "HTTP/1.x" )], &p, 0 ); + strtol( (char *)&cl->p_buffer[8], + &p, 0 ); while( *p == ' ' ) { p++; @@ -1558,10 +1539,10 @@ static void httpd_ClientRecv( httpd_client_t *cl ) for( i = 0; msg_type[i].name != NULL; i++ ) { - if( !strncmp( cl->p_buffer, msg_type[i].name, + if( !strncmp( (char *)cl->p_buffer, msg_type[i].name, strlen( msg_type[i].name ) ) ) { - p = &cl->p_buffer[strlen(msg_type[i].name) + 1 ]; + p = (char *)&cl->p_buffer[strlen((char *)msg_type[i].name) + 1 ]; cl->query.i_type = msg_type[i].i_type; if( cl->query.i_proto != msg_type[i].i_proto ) { @@ -1574,11 +1555,11 @@ static void httpd_ClientRecv( httpd_client_t *cl ) } if( p == NULL ) { - if( strstr( cl->p_buffer, "HTTP/1." ) ) + if( strstr( (char *)cl->p_buffer, "HTTP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; } - else if( strstr( cl->p_buffer, "RTSP/1." ) ) + else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; } @@ -1608,7 +1589,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( ( p3 = strchr( cl->query.psz_url, '?' ) ) ) { *p3++ = '\0'; - cl->query.psz_args = strdup( p3 ); + cl->query.psz_args = (uint8_t *)strdup( p3 ); } if( p2 ) { @@ -1778,7 +1759,7 @@ static void httpd_ClientSend( httpd_client_t *cl ) free( cl->p_buffer ); cl->p_buffer = malloc( i_size ); } - p = cl->p_buffer; + p = (char *)cl->p_buffer; p += sprintf( p, "%s/1.%d %d %s\r\n", cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP", @@ -1941,14 +1922,6 @@ static void httpd_HostThread( httpd_host_t *host ) ( cl->i_activity_timeout > 0 && cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) ) { - char *ip; - - // FIXME: it sucks to allocate memory on the stack for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "connection closed(%s)", - (ip != NULL) ? ip : "unknown" ); - free( ip ); - httpd_ClientClean( cl ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); @@ -2052,16 +2025,20 @@ static void httpd_HostThread( httpd_host_t *host ) p = answer->p_body = malloc( 1000 ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 501\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

501 Unimplemented

\n" ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 501\n" + "\n" + "\n" + "

501 Unimplemented

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n" ); answer->i_body = p - answer->p_body; httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); @@ -2073,6 +2050,7 @@ static void httpd_HostThread( httpd_host_t *host ) else { vlc_bool_t b_auth_failed = VLC_FALSE; + vlc_bool_t b_hosts_failed = VLC_FALSE; int i; /* Search the url and trigger callbacks */ @@ -2084,6 +2062,22 @@ static void httpd_HostThread( httpd_host_t *host ) { if( url->catch[i_msg].cb ) { + if( answer && ( url->p_acl != NULL ) ) + { + char ip[NI_MAXNUMERICHOST]; + + if( httpd_ClientIP( cl, ip ) != NULL ) + { + if( ACL_Check( url->p_acl, ip ) ) + { + b_hosts_failed = VLC_TRUE; + break; + } + } + else + b_hosts_failed = VLC_TRUE; + } + if( answer && ( *url->psz_user || *url->psz_password ) ) { /* create the headers */ @@ -2142,21 +2136,46 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_version= 0; p = answer->p_body = malloc( 1000 + strlen(query->psz_url) ); - if( b_auth_failed ) + if( b_hosts_failed ) + { + answer->i_status = 403; + answer->psz_status = strdup( "Forbidden" ); + + /* FIXME: lots of code duplication */ + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 403\n" + "\n" + "\n" + "

403 Forbidden (%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); + } + else if( b_auth_failed ) { answer->i_status = 401; answer->psz_status = strdup( "Authorization Required" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 401\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

401 Authorization Required (%s)

\n", query->psz_url ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 401\n" + "\n" + "\n" + "

401 Authorization Required (%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); } else { @@ -2164,16 +2183,20 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_status = 404; answer->psz_status = strdup( "Not found" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 404\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

404 Resource not found(%s)

\n", query->psz_url ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 404\n" + "\n" + "\n" + "

404 Resource not found(%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); } answer->i_body = p - answer->p_body; @@ -2283,7 +2306,11 @@ static void httpd_HostThread( httpd_host_t *host ) if( i_ret == -1 && errno != EINTR ) { - msg_Warn( host, "cannot select sockets" ); +#if defined(WIN32) || defined(UNDER_CE) + msg_Warn( host, "cannot select sockets (%d)", WSAGetLastError( ) ); +#else + msg_Warn( host, "cannot select sockets : %s", strerror( errno ) ); +#endif msleep( 1000 ); continue; } @@ -2297,7 +2324,7 @@ static void httpd_HostThread( httpd_host_t *host ) { if( FD_ISSET( fd, &fds_read ) ) { - int i_sock_size = sizeof( struct sockaddr_storage ); + socklen_t i_sock_size = sizeof( struct sockaddr_storage ); struct sockaddr_storage sock; fd = accept( fd, (struct sockaddr *)&sock, &i_sock_size ); @@ -2338,7 +2365,6 @@ static void httpd_HostThread( httpd_host_t *host ) if( fd >= 0 ) { - char *ip; httpd_client_t *cl; cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); @@ -2349,13 +2375,6 @@ static void httpd_HostThread( httpd_host_t *host ) if( i_state != 0 ) cl->i_state = i_state; // override state for TLS - - // FIXME: it sucks to allocate memory for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "new connection (%s)", - ip != NULL ? ip : "unknown" ); - if( ip != NULL) - free( ip ); } } } @@ -2411,15 +2430,28 @@ httpd_host_t *httpd_HostNew( vlc_object_t *a, char *b, int c ) msg_Err( a, "HTTP daemon support is disabled" ); return 0; } -void httpd_HostDelete( httpd_host_t *a ){} -httpd_url_t *httpd_UrlNew( httpd_host_t *a, char *b ){ return 0; } -httpd_url_t *httpd_UrlNewUnique( httpd_host_t *a, char *b, char *c, - char *d ){ return 0; } +void httpd_HostDelete( httpd_host_t *a ) +{ +} +httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} +httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} int httpd_UrlCatch( httpd_url_t *a, int b, httpd_callback_t c, httpd_callback_sys_t *d ){ return 0; } void httpd_UrlDelete( httpd_url_t *a ){} -char *httpd_ClientIP( httpd_client_t *a ){ return 0; } +char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { return NULL; } +char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) { return NULL; } + void httpd_ClientModeStream( httpd_client_t *a ){} void httpd_ClientModeBidir( httpd_client_t *a ){}