Home | History | Annotate | Line # | Download | only in sample
hostcheck.c revision 1.1.1.1.2.2
      1  1.1.1.1.2.2  pgoyette /*	$NetBSD: hostcheck.c,v 1.1.1.1.2.2 2017/03/20 06:52:23 pgoyette Exp $	*/
      2  1.1.1.1.2.2  pgoyette /***************************************************************************
      3  1.1.1.1.2.2  pgoyette  *                                  _   _ ____  _
      4  1.1.1.1.2.2  pgoyette  *  Project                     ___| | | |  _ \| |
      5  1.1.1.1.2.2  pgoyette  *                             / __| | | | |_) | |
      6  1.1.1.1.2.2  pgoyette  *                            | (__| |_| |  _ <| |___
      7  1.1.1.1.2.2  pgoyette  *                             \___|\___/|_| \_\_____|
      8  1.1.1.1.2.2  pgoyette  *
      9  1.1.1.1.2.2  pgoyette  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel (at) haxx.se>, et al.
     10  1.1.1.1.2.2  pgoyette  *
     11  1.1.1.1.2.2  pgoyette  * This software is licensed as described in the file COPYING, which
     12  1.1.1.1.2.2  pgoyette  * you should have received as part of this distribution. The terms
     13  1.1.1.1.2.2  pgoyette  * are also available at http://curl.haxx.se/docs/copyright.html.
     14  1.1.1.1.2.2  pgoyette  *
     15  1.1.1.1.2.2  pgoyette  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     16  1.1.1.1.2.2  pgoyette  * copies of the Software, and permit persons to whom the Software is
     17  1.1.1.1.2.2  pgoyette  * furnished to do so, under the terms of the COPYING file.
     18  1.1.1.1.2.2  pgoyette  *
     19  1.1.1.1.2.2  pgoyette  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     20  1.1.1.1.2.2  pgoyette  * KIND, either express or implied.
     21  1.1.1.1.2.2  pgoyette  *
     22  1.1.1.1.2.2  pgoyette  ***************************************************************************/
     23  1.1.1.1.2.2  pgoyette 
     24  1.1.1.1.2.2  pgoyette /* This file is an amalgamation of hostcheck.c and most of rawstr.c
     25  1.1.1.1.2.2  pgoyette    from cURL.  The contents of the COPYING file mentioned above are:
     26  1.1.1.1.2.2  pgoyette 
     27  1.1.1.1.2.2  pgoyette COPYRIGHT AND PERMISSION NOTICE
     28  1.1.1.1.2.2  pgoyette 
     29  1.1.1.1.2.2  pgoyette Copyright (c) 1996 - 2013, Daniel Stenberg, <daniel (at) haxx.se>.
     30  1.1.1.1.2.2  pgoyette 
     31  1.1.1.1.2.2  pgoyette All rights reserved.
     32  1.1.1.1.2.2  pgoyette 
     33  1.1.1.1.2.2  pgoyette Permission to use, copy, modify, and distribute this software for any purpose
     34  1.1.1.1.2.2  pgoyette with or without fee is hereby granted, provided that the above copyright
     35  1.1.1.1.2.2  pgoyette notice and this permission notice appear in all copies.
     36  1.1.1.1.2.2  pgoyette 
     37  1.1.1.1.2.2  pgoyette THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     38  1.1.1.1.2.2  pgoyette IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     39  1.1.1.1.2.2  pgoyette FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
     40  1.1.1.1.2.2  pgoyette NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     41  1.1.1.1.2.2  pgoyette DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     42  1.1.1.1.2.2  pgoyette OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
     43  1.1.1.1.2.2  pgoyette OR OTHER DEALINGS IN THE SOFTWARE.
     44  1.1.1.1.2.2  pgoyette 
     45  1.1.1.1.2.2  pgoyette Except as contained in this notice, the name of a copyright holder shall not
     46  1.1.1.1.2.2  pgoyette be used in advertising or otherwise to promote the sale, use or other dealings
     47  1.1.1.1.2.2  pgoyette in this Software without prior written authorization of the copyright holder.
     48  1.1.1.1.2.2  pgoyette */
     49  1.1.1.1.2.2  pgoyette 
     50  1.1.1.1.2.2  pgoyette #include "hostcheck.h"
     51  1.1.1.1.2.2  pgoyette #include <string.h>
     52  1.1.1.1.2.2  pgoyette 
     53  1.1.1.1.2.2  pgoyette /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
     54  1.1.1.1.2.2  pgoyette    its behavior is altered by the current locale. */
     55  1.1.1.1.2.2  pgoyette static char Curl_raw_toupper(char in)
     56  1.1.1.1.2.2  pgoyette {
     57  1.1.1.1.2.2  pgoyette   switch (in) {
     58  1.1.1.1.2.2  pgoyette   case 'a':
     59  1.1.1.1.2.2  pgoyette     return 'A';
     60  1.1.1.1.2.2  pgoyette   case 'b':
     61  1.1.1.1.2.2  pgoyette     return 'B';
     62  1.1.1.1.2.2  pgoyette   case 'c':
     63  1.1.1.1.2.2  pgoyette     return 'C';
     64  1.1.1.1.2.2  pgoyette   case 'd':
     65  1.1.1.1.2.2  pgoyette     return 'D';
     66  1.1.1.1.2.2  pgoyette   case 'e':
     67  1.1.1.1.2.2  pgoyette     return 'E';
     68  1.1.1.1.2.2  pgoyette   case 'f':
     69  1.1.1.1.2.2  pgoyette     return 'F';
     70  1.1.1.1.2.2  pgoyette   case 'g':
     71  1.1.1.1.2.2  pgoyette     return 'G';
     72  1.1.1.1.2.2  pgoyette   case 'h':
     73  1.1.1.1.2.2  pgoyette     return 'H';
     74  1.1.1.1.2.2  pgoyette   case 'i':
     75  1.1.1.1.2.2  pgoyette     return 'I';
     76  1.1.1.1.2.2  pgoyette   case 'j':
     77  1.1.1.1.2.2  pgoyette     return 'J';
     78  1.1.1.1.2.2  pgoyette   case 'k':
     79  1.1.1.1.2.2  pgoyette     return 'K';
     80  1.1.1.1.2.2  pgoyette   case 'l':
     81  1.1.1.1.2.2  pgoyette     return 'L';
     82  1.1.1.1.2.2  pgoyette   case 'm':
     83  1.1.1.1.2.2  pgoyette     return 'M';
     84  1.1.1.1.2.2  pgoyette   case 'n':
     85  1.1.1.1.2.2  pgoyette     return 'N';
     86  1.1.1.1.2.2  pgoyette   case 'o':
     87  1.1.1.1.2.2  pgoyette     return 'O';
     88  1.1.1.1.2.2  pgoyette   case 'p':
     89  1.1.1.1.2.2  pgoyette     return 'P';
     90  1.1.1.1.2.2  pgoyette   case 'q':
     91  1.1.1.1.2.2  pgoyette     return 'Q';
     92  1.1.1.1.2.2  pgoyette   case 'r':
     93  1.1.1.1.2.2  pgoyette     return 'R';
     94  1.1.1.1.2.2  pgoyette   case 's':
     95  1.1.1.1.2.2  pgoyette     return 'S';
     96  1.1.1.1.2.2  pgoyette   case 't':
     97  1.1.1.1.2.2  pgoyette     return 'T';
     98  1.1.1.1.2.2  pgoyette   case 'u':
     99  1.1.1.1.2.2  pgoyette     return 'U';
    100  1.1.1.1.2.2  pgoyette   case 'v':
    101  1.1.1.1.2.2  pgoyette     return 'V';
    102  1.1.1.1.2.2  pgoyette   case 'w':
    103  1.1.1.1.2.2  pgoyette     return 'W';
    104  1.1.1.1.2.2  pgoyette   case 'x':
    105  1.1.1.1.2.2  pgoyette     return 'X';
    106  1.1.1.1.2.2  pgoyette   case 'y':
    107  1.1.1.1.2.2  pgoyette     return 'Y';
    108  1.1.1.1.2.2  pgoyette   case 'z':
    109  1.1.1.1.2.2  pgoyette     return 'Z';
    110  1.1.1.1.2.2  pgoyette   }
    111  1.1.1.1.2.2  pgoyette   return in;
    112  1.1.1.1.2.2  pgoyette }
    113  1.1.1.1.2.2  pgoyette 
    114  1.1.1.1.2.2  pgoyette /*
    115  1.1.1.1.2.2  pgoyette  * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
    116  1.1.1.1.2.2  pgoyette  * to be locale independent and only compare strings we know are safe for
    117  1.1.1.1.2.2  pgoyette  * this.  See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
    118  1.1.1.1.2.2  pgoyette  * some further explanation to why this function is necessary.
    119  1.1.1.1.2.2  pgoyette  *
    120  1.1.1.1.2.2  pgoyette  * The function is capable of comparing a-z case insensitively even for
    121  1.1.1.1.2.2  pgoyette  * non-ascii.
    122  1.1.1.1.2.2  pgoyette  */
    123  1.1.1.1.2.2  pgoyette 
    124  1.1.1.1.2.2  pgoyette static int Curl_raw_equal(const char *first, const char *second)
    125  1.1.1.1.2.2  pgoyette {
    126  1.1.1.1.2.2  pgoyette   while(*first && *second) {
    127  1.1.1.1.2.2  pgoyette     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
    128  1.1.1.1.2.2  pgoyette       /* get out of the loop as soon as they don't match */
    129  1.1.1.1.2.2  pgoyette       break;
    130  1.1.1.1.2.2  pgoyette     first++;
    131  1.1.1.1.2.2  pgoyette     second++;
    132  1.1.1.1.2.2  pgoyette   }
    133  1.1.1.1.2.2  pgoyette   /* we do the comparison here (possibly again), just to make sure that if the
    134  1.1.1.1.2.2  pgoyette      loop above is skipped because one of the strings reached zero, we must not
    135  1.1.1.1.2.2  pgoyette      return this as a successful match */
    136  1.1.1.1.2.2  pgoyette   return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
    137  1.1.1.1.2.2  pgoyette }
    138  1.1.1.1.2.2  pgoyette 
    139  1.1.1.1.2.2  pgoyette static int Curl_raw_nequal(const char *first, const char *second, size_t max)
    140  1.1.1.1.2.2  pgoyette {
    141  1.1.1.1.2.2  pgoyette   while(*first && *second && max) {
    142  1.1.1.1.2.2  pgoyette     if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
    143  1.1.1.1.2.2  pgoyette       break;
    144  1.1.1.1.2.2  pgoyette     }
    145  1.1.1.1.2.2  pgoyette     max--;
    146  1.1.1.1.2.2  pgoyette     first++;
    147  1.1.1.1.2.2  pgoyette     second++;
    148  1.1.1.1.2.2  pgoyette   }
    149  1.1.1.1.2.2  pgoyette   if(0 == max)
    150  1.1.1.1.2.2  pgoyette     return 1; /* they are equal this far */
    151  1.1.1.1.2.2  pgoyette 
    152  1.1.1.1.2.2  pgoyette   return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
    153  1.1.1.1.2.2  pgoyette }
    154  1.1.1.1.2.2  pgoyette 
    155  1.1.1.1.2.2  pgoyette /*
    156  1.1.1.1.2.2  pgoyette  * Match a hostname against a wildcard pattern.
    157  1.1.1.1.2.2  pgoyette  * E.g.
    158  1.1.1.1.2.2  pgoyette  *  "foo.host.com" matches "*.host.com".
    159  1.1.1.1.2.2  pgoyette  *
    160  1.1.1.1.2.2  pgoyette  * We use the matching rule described in RFC6125, section 6.4.3.
    161  1.1.1.1.2.2  pgoyette  * http://tools.ietf.org/html/rfc6125#section-6.4.3
    162  1.1.1.1.2.2  pgoyette  */
    163  1.1.1.1.2.2  pgoyette 
    164  1.1.1.1.2.2  pgoyette static int hostmatch(const char *hostname, const char *pattern)
    165  1.1.1.1.2.2  pgoyette {
    166  1.1.1.1.2.2  pgoyette   const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
    167  1.1.1.1.2.2  pgoyette   int wildcard_enabled;
    168  1.1.1.1.2.2  pgoyette   size_t prefixlen, suffixlen;
    169  1.1.1.1.2.2  pgoyette   pattern_wildcard = strchr(pattern, '*');
    170  1.1.1.1.2.2  pgoyette   if(pattern_wildcard == NULL)
    171  1.1.1.1.2.2  pgoyette     return Curl_raw_equal(pattern, hostname) ?
    172  1.1.1.1.2.2  pgoyette       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
    173  1.1.1.1.2.2  pgoyette 
    174  1.1.1.1.2.2  pgoyette   /* We require at least 2 dots in pattern to avoid too wide wildcard
    175  1.1.1.1.2.2  pgoyette      match. */
    176  1.1.1.1.2.2  pgoyette   wildcard_enabled = 1;
    177  1.1.1.1.2.2  pgoyette   pattern_label_end = strchr(pattern, '.');
    178  1.1.1.1.2.2  pgoyette   if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
    179  1.1.1.1.2.2  pgoyette      pattern_wildcard > pattern_label_end ||
    180  1.1.1.1.2.2  pgoyette      Curl_raw_nequal(pattern, "xn--", 4)) {
    181  1.1.1.1.2.2  pgoyette     wildcard_enabled = 0;
    182  1.1.1.1.2.2  pgoyette   }
    183  1.1.1.1.2.2  pgoyette   if(!wildcard_enabled)
    184  1.1.1.1.2.2  pgoyette     return Curl_raw_equal(pattern, hostname) ?
    185  1.1.1.1.2.2  pgoyette       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
    186  1.1.1.1.2.2  pgoyette 
    187  1.1.1.1.2.2  pgoyette   hostname_label_end = strchr(hostname, '.');
    188  1.1.1.1.2.2  pgoyette   if(hostname_label_end == NULL ||
    189  1.1.1.1.2.2  pgoyette      !Curl_raw_equal(pattern_label_end, hostname_label_end))
    190  1.1.1.1.2.2  pgoyette     return CURL_HOST_NOMATCH;
    191  1.1.1.1.2.2  pgoyette 
    192  1.1.1.1.2.2  pgoyette   /* The wildcard must match at least one character, so the left-most
    193  1.1.1.1.2.2  pgoyette      label of the hostname is at least as large as the left-most label
    194  1.1.1.1.2.2  pgoyette      of the pattern. */
    195  1.1.1.1.2.2  pgoyette   if(hostname_label_end - hostname < pattern_label_end - pattern)
    196  1.1.1.1.2.2  pgoyette     return CURL_HOST_NOMATCH;
    197  1.1.1.1.2.2  pgoyette 
    198  1.1.1.1.2.2  pgoyette   prefixlen = pattern_wildcard - pattern;
    199  1.1.1.1.2.2  pgoyette   suffixlen = pattern_label_end - (pattern_wildcard+1);
    200  1.1.1.1.2.2  pgoyette   return Curl_raw_nequal(pattern, hostname, prefixlen) &&
    201  1.1.1.1.2.2  pgoyette     Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen,
    202  1.1.1.1.2.2  pgoyette                     suffixlen) ?
    203  1.1.1.1.2.2  pgoyette     CURL_HOST_MATCH : CURL_HOST_NOMATCH;
    204  1.1.1.1.2.2  pgoyette }
    205  1.1.1.1.2.2  pgoyette 
    206  1.1.1.1.2.2  pgoyette int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
    207  1.1.1.1.2.2  pgoyette {
    208  1.1.1.1.2.2  pgoyette   if(!match_pattern || !*match_pattern ||
    209  1.1.1.1.2.2  pgoyette       !hostname || !*hostname) /* sanity check */
    210  1.1.1.1.2.2  pgoyette     return 0;
    211  1.1.1.1.2.2  pgoyette 
    212  1.1.1.1.2.2  pgoyette   if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */
    213  1.1.1.1.2.2  pgoyette     return 1;
    214  1.1.1.1.2.2  pgoyette 
    215  1.1.1.1.2.2  pgoyette   if(hostmatch(hostname,match_pattern) == CURL_HOST_MATCH)
    216  1.1.1.1.2.2  pgoyette     return 1;
    217  1.1.1.1.2.2  pgoyette   return 0;
    218  1.1.1.1.2.2  pgoyette }
    219