]>
Commit | Line | Data |
---|---|---|
ca02e0ec | 1 | /* |
5b74111a | 2 | * Copyright (C) 1996-2018 The Squid Software Foundation and contributors |
ca02e0ec AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
b1218840 AJ |
8 | |
9 | /* | |
10 | * ----------------------------------------------------------------------------- | |
11 | * | |
12 | * Author: Markus Moeller (markus_moeller at compuserve.com) | |
13 | * | |
14 | * Copyright (C) 2007 Markus Moeller. All rights reserved. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | |
29 | * | |
30 | * ----------------------------------------------------------------------------- | |
31 | */ | |
32 | ||
f7f3304a | 33 | #include "squid.h" |
b1218840 AJ |
34 | #include "util.h" |
35 | ||
1a22a39e | 36 | #if HAVE_LDAP |
b1218840 AJ |
37 | |
38 | #include "support.h" | |
39 | ||
40 | struct gdstruct *init_gd(void); | |
4ebcf1ce | 41 | void free_gd(struct gdstruct *gdsp); |
b1218840 AJ |
42 | |
43 | struct gdstruct * | |
2e881a6f | 44 | init_gd(void) { |
b1218840 AJ |
45 | struct gdstruct *gdsp; |
46 | gdsp = (struct gdstruct *) xmalloc(sizeof(struct gdstruct)); | |
47 | gdsp->group = NULL; | |
48 | gdsp->domain = NULL; | |
49 | gdsp->next = NULL; | |
50 | return gdsp; | |
51 | } | |
52 | ||
4ad7aabf | 53 | void |
4a07fc72 A |
54 | free_gd(struct gdstruct *gdsp) |
55 | { | |
56 | while (gdsp) { | |
4ad7aabf AJ |
57 | struct gdstruct *gdspn = gdsp->next; |
58 | xfree(gdsp->group); | |
59 | xfree(gdsp->domain); | |
60 | xfree(gdsp); | |
61 | gdsp = gdspn; | |
62 | } | |
63 | } | |
64 | ||
b1218840 AJ |
65 | char *utf8dup(struct main_args *margs); |
66 | ||
67 | char * | |
68 | utf8dup(struct main_args *margs) | |
69 | { | |
4ebcf1ce | 70 | size_t c = 0; |
b1218840 AJ |
71 | size_t n; |
72 | char *src; | |
1a22a39e | 73 | unsigned char *p; |
b1218840 AJ |
74 | |
75 | src = margs->glist; | |
76 | if (!src) | |
2e881a6f | 77 | return NULL; |
a2f5277a | 78 | for (n = 0; n < strlen(src); ++n) |
2e881a6f | 79 | if ((unsigned char) src[n] > 127) |
755494da | 80 | ++c; |
b1218840 | 81 | if (c != 0) { |
1a22a39e | 82 | unsigned char *dupp; |
2e881a6f | 83 | p = (unsigned char *) xmalloc(strlen(src) + c); |
af920dee | 84 | dupp = p; |
a2f5277a | 85 | for (n = 0; n < strlen(src); ++n) { |
1a22a39e | 86 | unsigned char s; |
2e881a6f A |
87 | s = (unsigned char) src[n]; |
88 | if (s > 127 && s < 192) { | |
89 | *p = 194; | |
755494da | 90 | ++p; |
2e881a6f | 91 | *p = s; |
4ebcf1ce | 92 | } else if (s > 191) { |
2e881a6f | 93 | *p = 195; |
755494da | 94 | ++p; |
2e881a6f A |
95 | *p = s - 64; |
96 | } else | |
97 | *p = s; | |
755494da | 98 | ++p; |
2e881a6f A |
99 | } |
100 | *p = '\0'; | |
af920dee AJ |
101 | debug((char *) "%s| %s: INFO: Group %s as UTF-8: %s\n", LogTime(), PROGRAM, src, dupp); |
102 | return (char *) dupp; | |
b1218840 | 103 | } else |
2e881a6f | 104 | return xstrdup(src); |
b1218840 AJ |
105 | } |
106 | ||
107 | char *hex_utf_char(struct main_args *margs, int flag); | |
108 | /* | |
109 | * UTF8 = UTF1 / UTFMB | |
110 | * UTFMB = UTF2 / UTF3 / UTF4 | |
2e881a6f | 111 | * |
b1218840 AJ |
112 | * UTF0 = %x80-BF |
113 | * UTF1 = %x00-7F | |
114 | * UTF2 = %xC2-DF UTF0 | |
115 | * UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) / | |
116 | * %xED %x80-9F UTF0 / %xEE-EF 2(UTF0) | |
117 | * UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) / | |
118 | * %xF4 %x80-8F 2(UTF0) | |
2e881a6f | 119 | * |
b1218840 AJ |
120 | * http://www.utf8-chartable.de/unicode-utf8-table.pl |
121 | */ | |
122 | ||
123 | char * | |
124 | hex_utf_char(struct main_args *margs, int flag) | |
125 | { | |
4ad7aabf | 126 | int ival, ichar; |
b1218840 AJ |
127 | int iUTF2, iUTF3, iUTF4; |
128 | ||
4ad7aabf | 129 | char *up = (flag ? margs->ulist : margs->tlist); |
b1218840 | 130 | if (!up) |
2e881a6f | 131 | return NULL; |
b1218840 | 132 | |
4ad7aabf | 133 | char *upd = strrchr(up, '@'); |
4ebcf1ce | 134 | size_t a = (upd ? (size_t)(upd - up) : strlen(up) ); |
b1218840 | 135 | |
4ad7aabf AJ |
136 | char *ul = (char *) xmalloc(strlen(up)+1); |
137 | size_t n = 0; | |
138 | int nl = 0; | |
b1218840 AJ |
139 | iUTF2 = 0; |
140 | iUTF3 = 0; | |
141 | iUTF4 = 0; | |
142 | ||
4ad7aabf | 143 | while (n < strlen(up)) { |
2e881a6f A |
144 | if (flag && n == a) |
145 | break; | |
146 | if (up[n] == '@') { | |
147 | ul[nl] = '@'; | |
755494da FC |
148 | ++nl; |
149 | ++n; | |
2e881a6f A |
150 | continue; |
151 | } | |
152 | ival = up[n]; | |
153 | if (ival > 64 && ival < 71) | |
154 | ichar = (ival - 55) * 16; | |
155 | else if (ival > 96 && ival < 103) | |
156 | ichar = (ival - 87) * 16; | |
157 | else if (ival > 47 && ival < 58) | |
158 | ichar = (ival - 48) * 16; | |
159 | else { | |
160 | debug((char *) "%s| %s: WARNING: Invalid Hex value %c\n", LogTime(), PROGRAM, ival); | |
b656d212 | 161 | xfree(ul); |
2e881a6f A |
162 | return NULL; |
163 | } | |
b1218840 | 164 | |
2e881a6f A |
165 | if (n == a - 1) { |
166 | debug((char *) "%s| %s: WARNING: Invalid Hex UTF-8 string %s\n", LogTime(), PROGRAM, up); | |
b656d212 | 167 | xfree(ul); |
2e881a6f A |
168 | return NULL; |
169 | } | |
755494da | 170 | ++n; |
2e881a6f A |
171 | ival = up[n]; |
172 | if (ival > 64 && ival < 71) | |
173 | ichar = ichar + ival - 55; | |
174 | else if (ival > 96 && ival < 103) | |
175 | ichar = ichar + ival - 87; | |
176 | else if (ival > 47 && ival < 58) | |
177 | ichar = ichar + ival - 48; | |
178 | else { | |
179 | debug((char *) "%s| %s: WARNING: Invalid Hex value %c\n", LogTime(), PROGRAM, ival); | |
b656d212 | 180 | xfree(ul); |
2e881a6f A |
181 | return NULL; |
182 | } | |
b1218840 | 183 | |
2e881a6f A |
184 | if (iUTF2) { |
185 | if (iUTF2 == 0xC2 && ichar > 0x7F && ichar < 0xC0) { | |
186 | iUTF2 = 0; | |
4ebcf1ce | 187 | ul[nl - 1] = (char)ichar; |
2e881a6f A |
188 | } else if (iUTF2 == 0xC3 && ichar > 0x7F && ichar < 0xC0) { |
189 | iUTF2 = 0; | |
4ebcf1ce | 190 | ul[nl - 1] = (char)(ichar + 64); |
2e881a6f A |
191 | } else if (iUTF2 > 0xC3 && iUTF2 < 0xE0 && ichar > 0x7F && ichar < 0xC0) { |
192 | iUTF2 = 0; | |
4ebcf1ce | 193 | ul[nl] = (char)ichar; |
755494da | 194 | ++nl; |
2e881a6f A |
195 | } else { |
196 | iUTF2 = 0; | |
4ebcf1ce | 197 | ul[nl] = (char)ichar; |
2e881a6f A |
198 | ul[nl + 1] = '\0'; |
199 | debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul); | |
b656d212 | 200 | xfree(ul); |
2e881a6f A |
201 | return NULL; |
202 | } | |
203 | } else if (iUTF3) { | |
204 | if (iUTF3 == 0xE0 && ichar > 0x9F && ichar < 0xC0) { | |
205 | iUTF3 = 1; | |
4ebcf1ce | 206 | ul[nl] = (char)ichar; |
755494da | 207 | ++nl; |
2e881a6f A |
208 | } else if (iUTF3 > 0xE0 && iUTF3 < 0xED && ichar > 0x7F && ichar < 0xC0) { |
209 | iUTF3 = 2; | |
4ebcf1ce | 210 | ul[nl] = (char)ichar; |
755494da | 211 | ++nl; |
2e881a6f A |
212 | } else if (iUTF3 == 0xED && ichar > 0x7F && ichar < 0xA0) { |
213 | iUTF3 = 3; | |
4ebcf1ce | 214 | ul[nl] = (char)ichar; |
755494da | 215 | ++nl; |
2e881a6f A |
216 | } else if (iUTF3 > 0xED && iUTF3 < 0xF0 && ichar > 0x7F && ichar < 0xC0) { |
217 | iUTF3 = 4; | |
4ebcf1ce | 218 | ul[nl] = (char)ichar; |
755494da | 219 | ++nl; |
2e881a6f A |
220 | } else if (iUTF3 > 0 && iUTF3 < 5 && ichar > 0x7F && ichar < 0xC0) { |
221 | iUTF3 = 0; | |
4ebcf1ce | 222 | ul[nl] = (char)ichar; |
755494da | 223 | ++nl; |
2e881a6f A |
224 | } else { |
225 | iUTF3 = 0; | |
4ebcf1ce | 226 | ul[nl] = (char)ichar; |
2e881a6f A |
227 | ul[nl + 1] = '\0'; |
228 | debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul); | |
b656d212 | 229 | xfree(ul); |
2e881a6f A |
230 | return NULL; |
231 | } | |
232 | } else if (iUTF4) { | |
233 | if (iUTF4 == 0xF0 && ichar > 0x8F && ichar < 0xC0) { | |
234 | iUTF4 = 1; | |
4ebcf1ce | 235 | ul[nl] = (char)ichar; |
755494da | 236 | ++nl; |
2e881a6f A |
237 | } else if (iUTF4 > 0xF0 && iUTF3 < 0xF4 && ichar > 0x7F && ichar < 0xC0) { |
238 | iUTF4 = 2; | |
4ebcf1ce | 239 | ul[nl] = (char)ichar; |
755494da | 240 | ++nl; |
2e881a6f A |
241 | } else if (iUTF4 == 0xF4 && ichar > 0x7F && ichar < 0x90) { |
242 | iUTF4 = 3; | |
4ebcf1ce | 243 | ul[nl] = (char)ichar; |
755494da | 244 | ++nl; |
2e881a6f A |
245 | } else if (iUTF4 > 0 && iUTF4 < 5 && ichar > 0x7F && ichar < 0xC0) { |
246 | if (iUTF4 == 4) | |
247 | iUTF4 = 0; | |
248 | else | |
249 | iUTF4 = 4; | |
4ebcf1ce | 250 | ul[nl] = (char)ichar; |
755494da | 251 | ++nl; |
2e881a6f A |
252 | } else { |
253 | iUTF4 = 0; | |
4ebcf1ce | 254 | ul[nl] = (char)ichar; |
2e881a6f A |
255 | ul[nl + 1] = '\0'; |
256 | debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul); | |
b656d212 | 257 | xfree(ul); |
2e881a6f A |
258 | return NULL; |
259 | } | |
260 | } else if (ichar < 0x80) { | |
261 | /* UTF1 */ | |
4ebcf1ce | 262 | ul[nl] = (char)ichar; |
755494da | 263 | ++nl; |
2e881a6f A |
264 | } else if (ichar > 0xC1 && ichar < 0xE0) { |
265 | /* UTF2 (Latin) */ | |
266 | iUTF2 = ichar; | |
4ebcf1ce | 267 | ul[nl] = (char)ichar; |
755494da | 268 | ++nl; |
2e881a6f A |
269 | } else if (ichar > 0xDF && ichar < 0xF0) { |
270 | /* UTF3 */ | |
271 | iUTF3 = ichar; | |
4ebcf1ce | 272 | ul[nl] = (char)ichar; |
755494da | 273 | ++nl; |
2e881a6f A |
274 | } else if (ichar > 0xEF && ichar < 0xF5) { |
275 | /* UTF4 */ | |
276 | iUTF4 = ichar; | |
4ebcf1ce | 277 | ul[nl] = (char)ichar; |
755494da | 278 | ++nl; |
2e881a6f | 279 | } else { |
4ebcf1ce | 280 | ul[nl] = (char)ichar; |
2e881a6f A |
281 | ul[nl + 1] = '\0'; |
282 | debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul); | |
b656d212 | 283 | xfree(ul); |
2e881a6f A |
284 | return NULL; |
285 | } | |
755494da | 286 | ++n; |
b1218840 AJ |
287 | } |
288 | ||
289 | ul[nl] = '\0'; | |
290 | if (iUTF2 || iUTF3 || iUTF4) { | |
2e881a6f A |
291 | debug((char *) "%s| %s: INFO: iUTF2: %d iUTF3: %d iUTF4: %d\n", LogTime(), PROGRAM, iUTF2, iUTF3, iUTF4); |
292 | debug((char *) "%s| %s: WARNING: Invalid UTF-8 sequence for Unicode %s\n", LogTime(), PROGRAM, ul); | |
4ad7aabf | 293 | xfree(ul); |
2e881a6f | 294 | return NULL; |
b1218840 AJ |
295 | } |
296 | if (flag && upd) | |
2e881a6f | 297 | ul = strcat(ul, upd); |
b1218840 AJ |
298 | return ul; |
299 | } | |
300 | ||
b1218840 AJ |
301 | int |
302 | create_gd(struct main_args *margs) | |
303 | { | |
304 | char *gp, *dp; | |
b1218840 AJ |
305 | char *p; |
306 | struct gdstruct *gdsp = NULL, *gdspn = NULL; | |
307 | /* | |
308 | * Group list format: | |
309 | * | |
310 | * glist=Pattern1[:Pattern2] | |
311 | * | |
2e881a6f A |
312 | * Pattern=Group Group for all domains(including non Kerberos domains using ldap url options) if no |
313 | * other group definition for domain exists or users without | |
b1218840 AJ |
314 | * domain information. |
315 | * gdstruct.domain=NULL, gdstruct.group=Group | |
2e881a6f | 316 | * |
b1218840 | 317 | * or Pattern=Group@ Group for all Kerberos domains if no other group definition |
2e881a6f | 318 | * exists |
b1218840 AJ |
319 | * gdstruct.domain="", gdstruct.group=Group |
320 | * | |
321 | * or Pattern=Group@Domain Group for a specific Kerberos domain | |
322 | * gdstruct.domain=Domain, gdstruct.group=Group | |
323 | * | |
324 | * | |
325 | */ | |
4ad7aabf AJ |
326 | char *hp1 = hex_utf_char(margs, 0); |
327 | char *hp2 = hex_utf_char(margs, 1); | |
328 | char *up = utf8dup(margs); | |
b656d212 AJ |
329 | |
330 | // NP: will point to the start of a temporary assembly buffer used by 'p' and 'gp' | |
331 | // for catenation of the hp1, hp2, and up buffer contents from above. | |
332 | // necessary for xfree() because both p and gp move over the assembly area | |
4ad7aabf AJ |
333 | char *gpbuf = NULL; |
334 | ||
335 | // release the allocated UTF decoding buffers | |
336 | #define cleanup() { \ | |
337 | xfree(gpbuf); \ | |
338 | xfree(hp1); \ | |
339 | xfree(hp2); \ | |
b656d212 | 340 | xfree(up); \ |
4ad7aabf AJ |
341 | free_gd(gdsp); \ |
342 | } | |
343 | ||
b1218840 AJ |
344 | p = up; |
345 | if (hp1) { | |
2e881a6f A |
346 | if (hp2) { |
347 | if (up) { | |
4ad7aabf | 348 | gpbuf = p = (char *) xmalloc(strlen(up) + strlen(hp1) + strlen(hp2) + 2); |
2e881a6f A |
349 | strcpy(p, up); |
350 | strcat(p, ":"); | |
351 | strcat(p, hp1); | |
352 | strcat(p, ":"); | |
353 | strcat(p, hp2); | |
354 | } else { | |
4ad7aabf | 355 | gpbuf = p = (char *) xmalloc(strlen(hp1) + strlen(hp2) + 1); |
2e881a6f A |
356 | strcpy(p, hp1); |
357 | strcat(p, ":"); | |
358 | strcat(p, hp2); | |
359 | } | |
360 | } else { | |
361 | if (up) { | |
4ad7aabf | 362 | gpbuf = p = (char *) xmalloc(strlen(up) + strlen(hp1) + 1); |
2e881a6f A |
363 | strcpy(p, up); |
364 | strcat(p, ":"); | |
365 | strcat(p, hp1); | |
366 | } else | |
367 | p = hp1; | |
368 | } | |
b1218840 | 369 | } else { |
2e881a6f A |
370 | if (hp2) { |
371 | if (up) { | |
4ad7aabf | 372 | gpbuf = p = (char *) xmalloc(strlen(up) + strlen(hp2) + 1); |
2e881a6f A |
373 | strcpy(p, up); |
374 | strcat(p, ":"); | |
375 | strcat(p, hp2); | |
376 | } else | |
377 | p = hp2; | |
378 | } else | |
379 | p = up; | |
b1218840 AJ |
380 | } |
381 | gp = p; | |
382 | debug((char *) "%s| %s: INFO: Group list %s\n", LogTime(), PROGRAM, p ? p : "NULL"); | |
383 | dp = NULL; | |
384 | ||
385 | if (!p) { | |
2e881a6f | 386 | debug((char *) "%s| %s: ERROR: No groups defined.\n", LogTime(), PROGRAM); |
4ad7aabf | 387 | cleanup(); |
2e881a6f | 388 | return (1); |
b1218840 | 389 | } |
f53969cc SM |
390 | while (*p) { /* loop over group list */ |
391 | if (*p == '\n' || *p == '\r') { /* Ignore CR and LF if exist */ | |
755494da | 392 | ++p; |
2e881a6f A |
393 | continue; |
394 | } | |
f53969cc SM |
395 | if (*p == '@') { /* end of group name - start of domain name */ |
396 | if (p == gp) { /* empty group name not allowed */ | |
2e881a6f | 397 | debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p); |
4ad7aabf | 398 | cleanup(); |
2e881a6f A |
399 | return (1); |
400 | } | |
4f10fd9b MM |
401 | if (dp) { /* end of domain name - twice */ |
402 | debug((char *) "%s| %s: @ is not allowed in group name %s@%s\n",LogTime(), PROGRAM,gp,dp); | |
403 | cleanup(); | |
404 | return(1); | |
405 | } | |
2e881a6f | 406 | *p = '\0'; |
755494da | 407 | ++p; |
2e881a6f | 408 | gdsp = init_gd(); |
4ad7aabf AJ |
409 | gdsp->group = xstrdup(gp); |
410 | gdsp->next = gdspn; | |
f53969cc SM |
411 | dp = p; /* after @ starts new domain name */ |
412 | } else if (*p == ':') { /* end of group name or end of domain name */ | |
413 | if (p == gp) { /* empty group name not allowed */ | |
2e881a6f | 414 | debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p); |
4ad7aabf | 415 | cleanup(); |
2e881a6f A |
416 | return (1); |
417 | } | |
418 | *p = '\0'; | |
755494da | 419 | ++p; |
f53969cc | 420 | if (dp) { /* end of domain name */ |
2e881a6f A |
421 | gdsp->domain = xstrdup(dp); |
422 | dp = NULL; | |
f53969cc | 423 | } else { /* end of group name and no domain name */ |
2e881a6f | 424 | gdsp = init_gd(); |
4ad7aabf AJ |
425 | gdsp->group = xstrdup(gp); |
426 | gdsp->next = gdspn; | |
2e881a6f A |
427 | } |
428 | gdspn = gdsp; | |
f53969cc | 429 | gp = p; /* after : starts new group name */ |
2e881a6f A |
430 | debug((char *) "%s| %s: INFO: Group %s Domain %s\n", LogTime(), PROGRAM, gdsp->group, gdsp->domain ? gdsp->domain : "NULL"); |
431 | } else | |
755494da | 432 | ++p; |
b1218840 | 433 | } |
f53969cc | 434 | if (p == gp) { /* empty group name not allowed */ |
2e881a6f | 435 | debug((char *) "%s| %s: ERROR: No group defined for domain %s\n", LogTime(), PROGRAM, p); |
4ad7aabf | 436 | cleanup(); |
2e881a6f | 437 | return (1); |
b1218840 | 438 | } |
f53969cc | 439 | if (dp) { /* end of domain name */ |
2e881a6f | 440 | gdsp->domain = xstrdup(dp); |
f53969cc | 441 | } else { /* end of group name and no domain name */ |
2e881a6f | 442 | gdsp = init_gd(); |
4ad7aabf | 443 | gdsp->group = xstrdup(gp); |
f53969cc | 444 | if (gdspn) /* Have already an existing structure */ |
2e881a6f | 445 | gdsp->next = gdspn; |
b1218840 AJ |
446 | } |
447 | debug((char *) "%s| %s: INFO: Group %s Domain %s\n", LogTime(), PROGRAM, gdsp->group, gdsp->domain ? gdsp->domain : "NULL"); | |
448 | ||
449 | margs->groups = gdsp; | |
4ad7aabf AJ |
450 | gdsp = NULL; // prevent the cleanup() deallocating it. |
451 | cleanup(); | |
b1218840 AJ |
452 | return (0); |
453 | } | |
454 | #endif | |
f53969cc | 455 |