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