1 /*
2  * File: dpiutil.c
3  *
4  * Copyright 2004-2007 Jorge Arellano Cid <jcid@dillo.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  */
12 
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <sys/socket.h>
20 
21 #include "dpiutil.h"
22 
23 /*
24  * Debugging macros
25  */
26 #define _MSG(...)
27 #define MSG(...)  printf("[dpiutil.c]: " __VA_ARGS__)
28 
29 
30 /* Escaping/De-escaping ---------------------------------------------------*/
31 
32 /*
33  * Escape URI characters in 'esc_set' as %XX sequences.
34  * Return value: New escaped string.
35  */
Escape_uri_str(const char * str,const char * p_esc_set)36 char *Escape_uri_str(const char *str, const char *p_esc_set)
37 {
38    static const char *esc_set, *hex = "0123456789ABCDEF";
39    char *p;
40    Dstr *dstr;
41    int i;
42 
43    esc_set = (p_esc_set) ? p_esc_set : "%#:' ";
44    dstr = dStr_sized_new(64);
45    for (i = 0; str[i]; ++i) {
46       if (str[i] <= 0x1F || str[i] == 0x7F || strchr(esc_set, str[i])) {
47          dStr_append_c(dstr, '%');
48          dStr_append_c(dstr, hex[(str[i] >> 4) & 15]);
49          dStr_append_c(dstr, hex[str[i] & 15]);
50       } else {
51          dStr_append_c(dstr, str[i]);
52       }
53    }
54    p = dstr->str;
55    dStr_free(dstr, FALSE);
56 
57    return p;
58 }
59 
60 /*
61  * Unescape %XX sequences in a string.
62  * Return value: a new unescaped string
63  */
Unescape_uri_str(const char * s)64 char *Unescape_uri_str(const char *s)
65 {
66    char *p, *buf = dStrdup(s);
67 
68    if (strchr(s, '%')) {
69       for (p = buf; (*p = *s); ++s, ++p) {
70          if (*p == '%' && isxdigit(s[1]) && isxdigit(s[2])) {
71             *p = (isdigit(s[1]) ? (s[1] - '0')
72                                 : D_ASCII_TOUPPER(s[1]) - 'A' + 10) * 16;
73             *p += isdigit(s[2]) ? (s[2] - '0')
74                                 : D_ASCII_TOUPPER(s[2]) - 'A' + 10;
75             s += 2;
76          }
77       }
78    }
79 
80    return buf;
81 }
82 
83 
84 static const char *unsafe_chars = "&<>\"'";
85 static const char *unsafe_rep[] =
86   { "&amp;", "&lt;", "&gt;", "&quot;", "&#39;" };
87 static const int unsafe_rep_len[] =  { 5, 4, 4, 6, 5 };
88 
89 /*
90  * Escape unsafe characters as html entities.
91  * Return value: New escaped string.
92  */
Escape_html_str(const char * str)93 char *Escape_html_str(const char *str)
94 {
95    int i;
96    char *p;
97    Dstr *dstr = dStr_sized_new(64);
98 
99    for (i = 0; str[i]; ++i) {
100       if ((p = strchr(unsafe_chars, str[i])))
101          dStr_append(dstr, unsafe_rep[p - unsafe_chars]);
102       else
103          dStr_append_c(dstr, str[i]);
104    }
105    p = dstr->str;
106    dStr_free(dstr, FALSE);
107 
108    return p;
109 }
110 
111 /*
112  * Unescape a few HTML entities (inverse of Escape_html_str)
113  * Return value: New unescaped string.
114  */
Unescape_html_str(const char * str)115 char *Unescape_html_str(const char *str)
116 {
117    int i, j, k;
118    char *u_str = dStrdup(str);
119 
120    if (!strchr(str, '&'))
121       return u_str;
122 
123    for (i = 0, j = 0; str[i]; ++i) {
124       if (str[i] == '&') {
125          for (k = 0; k < 5; ++k) {
126             if (!dStrnAsciiCasecmp(str + i, unsafe_rep[k], unsafe_rep_len[k])) {
127                i += unsafe_rep_len[k] - 1;
128                break;
129             }
130          }
131          u_str[j++] = (k < 5) ? unsafe_chars[k] : str[i];
132       } else {
133          u_str[j++] = str[i];
134       }
135    }
136    u_str[j] = 0;
137 
138    return u_str;
139 }
140 
141 /*
142  * Filter '\n', '\r', "%0D" and "%0A" from the authority part of an FTP url.
143  * This helps to avoid a SMTP relaying hack. This filtering could be done
144  * only when port == 25, but if the mail server is listening on another
145  * port it wouldn't work.
146  * Note: AFAIS this should be done by wget.
147  */
Filter_smtp_hack(char * url)148 char *Filter_smtp_hack(char *url)
149 {
150    int i;
151    char c;
152 
153    if (strlen(url) > 6) { /* ftp:// */
154       for (i = 6; (c = url[i]) && c != '/'; ++i) {
155          if (c == '\n' || c == '\r') {
156             memmove(url + i, url + i + 1, strlen(url + i));
157             --i;
158          } else if (c == '%' && url[i+1] == '0' &&
159                     (D_ASCII_TOLOWER(url[i+2]) == 'a' ||
160                      D_ASCII_TOLOWER(url[i+2]) == 'd')) {
161             memmove(url + i, url + i + 3, strlen(url + i + 2));
162             --i;
163          }
164       }
165    }
166    return url;
167 }
168 
169