1 /*
   2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <setjmp.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 
  30 #include "jni.h"
  31 #include "jvm.h"
  32 
  33 typedef unsigned short unicode;
  34 
  35 static char *
  36 skip_over_fieldname(char *name, jboolean slash_okay,
  37                     unsigned int len);
  38 static char *
  39 skip_over_field_signature(char *name, jboolean void_okay,
  40                           unsigned int len);
  41 
  42 /*
  43  * Return non-zero if the character is a valid in JVM class name, zero
  44  * otherwise.  The only characters currently disallowed from JVM class
  45  * names are given in the table below:
  46  *
  47  * Character    Hex     Decimal
  48  * '.'          0x2e    46
  49  * '/'          0x2f    47
  50  * ';'          0x3b    59
  51  * '['          0x5b    91
  52  *
  53  * (Method names have further restrictions dealing with the '<' and
  54  * '>' characters.)
  55  */
  56 static int isJvmIdentifier(unicode ch) {
  57   if( ch > 91 || ch < 46 )
  58     return 1;   /* Lowercase ASCII letters are > 91 */
  59   else { /* 46 <= ch <= 91 */
  60     if (ch <= 90 && ch >= 60) {
  61       return 1; /* Uppercase ASCII recognized here */
  62     } else { /* ch == 91 || 46 <= ch <= 59 */
  63       if (ch == 91 || ch == 59 || ch <= 47)
  64         return 0;
  65       else
  66         return 1;
  67     }
  68   }
  69 }
  70 
  71 static unicode
  72 next_utf2unicode(char **utfstring_ptr, int * valid)
  73 {
  74     unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
  75     unsigned char ch, ch2, ch3;
  76     int length = 1;             /* default length */
  77     unicode result = 0x80;      /* default bad result; */
  78     *valid = 1;
  79     switch ((ch = ptr[0]) >> 4) {
  80         default:
  81             result = ch;
  82             break;
  83 
  84         case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
  85             /* Shouldn't happen. */
  86             *valid = 0;
  87             break;
  88 
  89         case 0xC: case 0xD:
  90             /* 110xxxxx  10xxxxxx */
  91             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
  92                 unsigned char high_five = ch & 0x1F;
  93                 unsigned char low_six = ch2 & 0x3F;
  94                 result = (high_five << 6) + low_six;
  95                 length = 2;
  96             }
  97             break;
  98 
  99         case 0xE:
 100             /* 1110xxxx 10xxxxxx 10xxxxxx */
 101             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
 102                 if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
 103                     unsigned char high_four = ch & 0x0f;
 104                     unsigned char mid_six = ch2 & 0x3f;
 105                     unsigned char low_six = ch3 & 0x3f;
 106                     result = (((high_four << 6) + mid_six) << 6) + low_six;
 107                     length = 3;
 108                 } else {
 109                     length = 2;
 110                 }
 111             }
 112             break;
 113         } /* end of switch */
 114 
 115     *utfstring_ptr = (char *)(ptr + length);
 116     return result;
 117 }
 118 
 119 /* Take pointer to a string.  Skip over the longest part of the string that
 120  * could be taken as a fieldname.  Allow '/' if slash_okay is JNI_TRUE.
 121  *
 122  * Return a pointer to just past the fieldname.  Return NULL if no fieldname
 123  * at all was found, or in the case of slash_okay being true, we saw
 124  * consecutive slashes (meaning we were looking for a qualified path but
 125  * found something that was badly-formed).
 126  */
 127 static char *
 128 skip_over_fieldname(char *name, jboolean slash_okay,
 129                     unsigned int length)
 130 {
 131     char *p;
 132     unicode ch;
 133     unicode last_ch = 0;
 134     int valid = 1;
 135     /* last_ch == 0 implies we are looking at the first char. */
 136     for (p = name; p != name + length; last_ch = ch) {
 137         char *old_p = p;
 138         ch = *p;
 139         if (ch < 128) {
 140             p++;
 141             if (isJvmIdentifier(ch)) {
 142                 continue;
 143             }
 144         } else {
 145             char *tmp_p = p;
 146             ch = next_utf2unicode(&tmp_p, &valid);
 147             if (valid == 0)
 148               return 0;
 149             p = tmp_p;
 150             if (isJvmIdentifier(ch)) {
 151                         continue;
 152             }
 153         }
 154 
 155         if (slash_okay && ch == '/' && last_ch) {
 156             if (last_ch == '/') {
 157                 return 0;       /* Don't permit consecutive slashes */
 158             }
 159         } else if (ch == '_' || ch == '$') {
 160         } else {
 161             return last_ch ? old_p : 0;
 162         }
 163     }
 164     return last_ch ? p : 0;
 165 }
 166 
 167 /* Take pointer to a string.  Skip over the longest part of the string that
 168  * could be taken as a field signature.  Allow "void" if void_okay.
 169  *
 170  * Return a pointer to just past the signature.  Return NULL if no legal
 171  * signature is found.
 172  */
 173 
 174 static char *
 175 skip_over_field_signature(char *name, jboolean void_okay,
 176                           unsigned int length)
 177 {
 178     unsigned int array_dim = 0;
 179     for (;length > 0;) {
 180         switch (name[0]) {
 181             case JVM_SIGNATURE_VOID:
 182                 if (!void_okay) return 0;
 183                 /* FALL THROUGH */
 184             case JVM_SIGNATURE_BOOLEAN:
 185             case JVM_SIGNATURE_BYTE:
 186             case JVM_SIGNATURE_CHAR:
 187             case JVM_SIGNATURE_SHORT:
 188             case JVM_SIGNATURE_INT:
 189             case JVM_SIGNATURE_FLOAT:
 190             case JVM_SIGNATURE_LONG:
 191             case JVM_SIGNATURE_DOUBLE:
 192                 return name + 1;
 193 
 194             case JVM_SIGNATURE_CLASS: {
 195                 /* Skip over the classname, if one is there. */
 196                 char *p =
 197                     skip_over_fieldname(name + 1, JNI_TRUE, --length);
 198                 /* The next character better be a semicolon. */
 199                 if (p && p - name - 1 > 0 && p[0] == ';')
 200                     return p + 1;
 201                 return 0;
 202             }
 203 
 204             case JVM_SIGNATURE_ARRAY:
 205                 array_dim++;
 206                 /* JVMS 2nd ed. 4.10 */
 207                 /*   The number of dimensions in an array is limited to 255 ... */
 208                 if (array_dim > 255) {
 209                     return 0;
 210                 }
 211                 /* The rest of what's there better be a legal signature.  */
 212                 name++;
 213                 length--;
 214                 void_okay = JNI_FALSE;
 215                 break;
 216 
 217             default:
 218                 return 0;
 219         }
 220     }
 221     return 0;
 222 }
 223 
 224 
 225 /* Used in java/lang/Class.c */
 226 /* Determine if the specified name is legal
 227  * UTF name for a classname.
 228  *
 229  * Note that this routine expects the internal form of qualified classes:
 230  * the dots should have been replaced by slashes.
 231  */
 232 JNIEXPORT jboolean
 233 VerifyClassname(char *name, jboolean allowArrayClass)
 234 {
 235     unsigned int length = strlen(name);
 236     char *p;
 237 
 238     if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
 239         if (!allowArrayClass) {
 240             return JNI_FALSE;
 241         } else {
 242             /* Everything that's left better be a field signature */
 243             p = skip_over_field_signature(name, JNI_FALSE, length);
 244         }
 245     } else {
 246         /* skip over the fieldname.  Slashes are okay */
 247         p = skip_over_fieldname(name, JNI_TRUE, length);
 248     }
 249     return (p != 0 && p - name == (ptrdiff_t)length);
 250 }
 251 
 252 /*
 253  * Translates '.' to '/'.  Returns JNI_TRUE is any / were present.
 254  */
 255 JNIEXPORT jboolean
 256 VerifyFixClassname(char *name)
 257 {
 258     char *p = name;
 259     jboolean slashesFound = JNI_FALSE;
 260     int valid = 1;
 261 
 262     while (valid != 0 && *p != '\0') {
 263         if (*p == '/') {
 264             slashesFound = JNI_TRUE;
 265             p++;
 266         } else if (*p == '.') {
 267             *p++ = '/';
 268         } else {
 269             next_utf2unicode(&p, &valid);
 270         }
 271     }
 272 
 273     return slashesFound && valid != 0;
 274 }