You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by la...@apache.org on 2001/10/01 02:27:11 UTC

cvs commit: jakarta-tomcat/src/native/mod_jk/iis jk_isapi_plugin.c

larryi      01/09/30 17:27:11

  Modified:    src/native/mod_jk/iis jk_isapi_plugin.c
  Log:
  Port Apache routines to decode and normalize the URI from IIS. Also, block
  access to META-INF and refactor the error response handling a little.
  
  Revision  Changes    Path
  1.9       +158 -20   jakarta-tomcat/src/native/mod_jk/iis/jk_isapi_plugin.c
  
  Index: jk_isapi_plugin.c
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/native/mod_jk/iis/jk_isapi_plugin.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- jk_isapi_plugin.c	2001/09/22 21:08:16	1.8
  +++ jk_isapi_plugin.c	2001/10/01 00:27:11	1.9
  @@ -57,7 +57,7 @@
    * Description: ISAPI plugin for IIS/PWS                                   *
    * Author:      Gal Shachor <sh...@il.ibm.com>                           *
    * Author:      Ignacio J. Ortega <na...@apache.org>                       *
  - * Version:     $Revision: 1.8 $                                           *
  + * Version:     $Revision: 1.9 $                                           *
    ***************************************************************************/
   
   // This define is needed to include wincrypt,h, needed to get client certificates
  @@ -96,6 +96,9 @@
   #define REGISTRY_LOCATION       ("Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0")
   #define EXTENSION_URI_TAG       ("extension_uri")
   
  +#define BAD_REQUEST		-1
  +#define BAD_PATH		-2
  +
   #define GET_SERVER_VARIABLE_VALUE(name, place) {    \
       (place) = NULL;                                   \
       huge_buf_sz = sizeof(huge_buf);                 \
  @@ -189,6 +192,108 @@
                                 int len);
   
   
  +static char x2c(const char *what)
  +{
  +    register char digit;
  +
  +    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
  +    digit *= 16;
  +    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
  +    return (digit);
  +}
  +
  +static int unescape_url(char *url)
  +{
  +    register int x, y, badesc, badpath;
  +
  +    badesc = 0;
  +    badpath = 0;
  +    for (x = 0, y = 0; url[y]; ++x, ++y) {
  +        if (url[y] != '%')
  +            url[x] = url[y];
  +        else {
  +            if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) {
  +                badesc = 1;
  +                url[x] = '%';
  +            }
  +            else {
  +                url[x] = x2c(&url[y + 1]);
  +                y += 2;
  +                if (url[x] == '/' || url[x] == '\0')
  +                    badpath = 1;
  +            }
  +        }
  +    }
  +    url[x] = '\0';
  +    if (badesc)
  +            return BAD_REQUEST;
  +    else if (badpath)
  +            return BAD_PATH;
  +    else
  +            return 0;
  +}
  +
  +static void getparents(char *name)
  +{
  +    int l, w;
  +
  +    /* Four paseses, as per RFC 1808 */
  +    /* a) remove ./ path segments */
  +
  +    for (l = 0, w = 0; name[l] != '\0';) {
  +        if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))
  +            l += 2;
  +        else
  +            name[w++] = name[l++];
  +    }
  +
  +    /* b) remove trailing . path, segment */
  +    if (w == 1 && name[0] == '.')
  +        w--;
  +    else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
  +        w--;
  +    name[w] = '\0';
  +
  +    /* c) remove all xx/../ segments. (including leading ../ and /../) */
  +    l = 0;
  +
  +    while (name[l] != '\0') {
  +        if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
  +            (l == 0 || name[l - 1] == '/')) {
  +            register int m = l + 3, n;
  +
  +            l = l - 2;
  +            if (l >= 0) {
  +                while (l >= 0 && name[l] != '/')
  +                    l--;
  +                l++;
  +            }
  +            else
  +                l = 0;
  +            n = l;
  +            while ((name[n] = name[m]))
  +                (++n, ++m);
  +        }
  +        else
  +            ++l;
  +    }
  +
  +    /* d) remove trailing xx/.. segment. */
  +    if (l == 2 && name[0] == '.' && name[1] == '.')
  +        name[0] = '\0';
  +    else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {
  +        l = l - 4;
  +        if (l >= 0) {
  +            while (l >= 0 && name[l] != '/')
  +                l--;
  +            l++;
  +        }
  +        else
  +            l = 0;
  +        name[l] = '\0';
  +    }
  +}
  +
   static int uri_is_web_inf(char *uri)
   {
       char *c = uri;
  @@ -199,10 +304,34 @@
       if(strstr(uri, "web-inf")) {
           return JK_TRUE;
       }
  +    if(strstr(uri, "meta-inf")) {
  +        return JK_TRUE;
  +    }
   
       return JK_FALSE;
   }
   
  +static void write_error_response(PHTTP_FILTER_CONTEXT pfc,char *status,char * msg)
  +{
  +    char crlf[3] = { (char)13, (char)10, '\0' };
  +    char ctype[30];
  +    DWORD len = strlen(msg);
  +
  +    sprintf(ctype, 
  +            "Content-Type:text/html%s%s", 
  +            crlf, 
  +            crlf);
  +
  +    /* reject !!! */
  +    pfc->ServerSupportFunction(pfc, 
  +                               SF_REQ_SEND_RESPONSE_HEADER,
  +                               status,
  +                               (DWORD)crlf,
  +                               (DWORD)ctype);
  +    pfc->WriteClient(pfc, msg, &len, 0);
  +}
  +
  +
   static int JK_METHOD start_response(jk_ws_service_t *s,
                                       int status,
                                       const char *reason,
  @@ -439,11 +568,32 @@
           }
   
           if(strlen(uri)) {
  +            int rc;
               char *worker=0;
               query = strchr(uri, '?');
               if(query) {
                   *query = '\0';
               }
  +
  +            rc = unescape_url(uri);
  +            if (rc == BAD_REQUEST) {
  +                jk_log(logger, JK_LOG_ERROR, 
  +                       "HttpFilterProc [%s] contains on or more invalid escape sequences.\n", 
  +                       uri);
  +                write_error_response(pfc,"400 Bad Request",
  +                        "<HTML><BODY><H1>Request contains invalid encoding</H1></BODY></HTML>");
  +                return SF_STATUS_REQ_FINISHED;
  +            }
  +            else if(rc == BAD_PATH) {
  +                jk_log(logger, JK_LOG_EMERG, 
  +                       "HttpFilterProc [%s] contains forbidden escape sequences.\n", 
  +                       uri);
  +                write_error_response(pfc,"403 Forbidden",
  +                        "<HTML><BODY><H1>Access is Forbidden</H1></BODY></HTML>");
  +                return SF_STATUS_REQ_FINISHED;
  +            }
  +            getparents(uri);
  +
   			if(p->GetHeader(pfc, "Host:", (LPVOID)Host, (LPDWORD)&szHost)) {
   				strcat(snuri,Host);
   				strcat(snuri,uri);
  @@ -491,28 +641,12 @@
                      uri);
   
               if(uri_is_web_inf(uri)) {
  -                char crlf[3] = { (char)13, (char)10, '\0' };
  -                char ctype[30];
  -                char *msg = "<HTML><BODY><H1>Access is Forbidden</H1></BODY></HTML>";
  -                DWORD len = strlen(msg);
  -
                   jk_log(logger, JK_LOG_EMERG, 
  -                       "HttpFilterProc [%s] points to the web-inf directory.\nSomebody try to hack into the site!!!\n", 
  +                       "HttpFilterProc [%s] points to the web-inf or meta-inf directory.\nSomebody try to hack into the site!!!\n", 
                          uri);
  -
  -                sprintf(ctype, 
  -                        "Content-Type:text/html%s%s", 
  -                        crlf, 
  -                        crlf);
  -
  -                /* reject !!! */
  -                pfc->ServerSupportFunction(pfc, 
  -                                           SF_REQ_SEND_RESPONSE_HEADER,
  -                                           "403 Forbidden",
  -                                           (DWORD)crlf,
  -                                           (DWORD)ctype);
  -                pfc->WriteClient(pfc, msg, &len, 0);
   
  +                write_error_response(pfc,"403 Forbidden",
  +                        "<HTML><BODY><H1>Access is Forbidden</H1></BODY></HTML>");
                   return SF_STATUS_REQ_FINISHED;
               }
           }
  @@ -867,6 +1001,9 @@
           s->query_string = private_data->lpEcb->lpszQueryString;
           *worker_name    = JK_AJP12_WORKER_NAME;
           GET_SERVER_VARIABLE_VALUE("URL", s->req_uri);       
  +        if (unescape_url(s->req_uri) < 0)
  +            return JK_FALSE;
  +        getparents(s->req_uri);
       }
       
       GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type);
  @@ -1164,3 +1301,4 @@
       *p++ = '\0';
       return p - encoded;
   }
  +