|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static gint |
|
|
static gint |
|
|
rspamd_mailto_parse (struct http_parser_url *u, const gchar *str) |
|
|
|
|
|
|
|
|
rspamd_mailto_parse (struct http_parser_url *u, const gchar *str, |
|
|
|
|
|
gchar const **end) |
|
|
{ |
|
|
{ |
|
|
const gchar *p = str, *c = str; |
|
|
const gchar *p = str, *c = str; |
|
|
gchar t; |
|
|
gchar t; |
|
|
|
|
|
gint ret = 1; |
|
|
enum { |
|
|
enum { |
|
|
parse_mailto, |
|
|
parse_mailto, |
|
|
parse_slash, |
|
|
parse_slash, |
|
|
|
|
|
|
|
|
st = parse_slash_slash; |
|
|
st = parse_slash_slash; |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
st = parse_destination; |
|
|
st = parse_destination; |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case parse_destination: |
|
|
case parse_destination: |
|
|
|
|
|
|
|
|
case parse_user: |
|
|
case parse_user: |
|
|
if (t == '@') { |
|
|
if (t == '@') { |
|
|
if (p - c == 0) { |
|
|
if (p - c == 0) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
|
|
|
|
|
|
st = parse_at; |
|
|
st = parse_at; |
|
|
} |
|
|
} |
|
|
else if (!is_atom (t)) { |
|
|
else if (!is_atom (t)) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
st = parse_suffix_question; |
|
|
st = parse_suffix_question; |
|
|
} |
|
|
} |
|
|
else if (!is_domain (t) && t != '.' && t != '_') { |
|
|
else if (!is_domain (t) && t != '.' && t != '_') { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
case parse_query: |
|
|
case parse_query: |
|
|
if (!is_atom (t)) { |
|
|
if (!is_atom (t)) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (st == parse_domain) { |
|
|
if (st == parse_domain) { |
|
|
if (p - c == 0) { |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u->field_set |= 1 << UF_HOST; |
|
|
|
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
|
|
|
u->field_data[UF_HOST].off = c - str; |
|
|
|
|
|
|
|
|
if (p - c != 0) { |
|
|
|
|
|
u->field_set |= 1 << UF_HOST; |
|
|
|
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
|
|
|
u->field_data[UF_HOST].off = c - str; |
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
ret = 0; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
else if (st == parse_query) { |
|
|
else if (st == parse_query) { |
|
|
if (p - c > 0) { |
|
|
if (p - c > 0) { |
|
|
|
|
|
|
|
|
u->field_data[UF_QUERY].off = c - str; |
|
|
u->field_data[UF_QUERY].off = c - str; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
ret = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
|
if (end != NULL) { |
|
|
|
|
|
*end = p; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
|
return ret; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static gint |
|
|
static gint |
|
|
rspamd_web_parse (struct http_parser_url *u, const gchar *str) |
|
|
|
|
|
|
|
|
rspamd_web_parse (struct http_parser_url *u, const gchar *str, gchar const **end) |
|
|
{ |
|
|
{ |
|
|
const gchar *p = str, *c = str; |
|
|
const gchar *p = str, *c = str; |
|
|
gchar t; |
|
|
gchar t; |
|
|
|
|
|
|
|
|
st = parse_slash_slash; |
|
|
st = parse_slash_slash; |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case parse_user: |
|
|
case parse_user: |
|
|
if (t == ':') { |
|
|
if (t == ':') { |
|
|
if (p - c == 0) { |
|
|
if (p - c == 0) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
|
|
|
|
|
|
else if (t == '@') { |
|
|
else if (t == '@') { |
|
|
/* No password */ |
|
|
/* No password */ |
|
|
if (p - c == 0) { |
|
|
if (p - c == 0) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_set |= 1 << UF_USERINFO; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
u->field_data[UF_USERINFO].len = p - c; |
|
|
|
|
|
|
|
|
st = parse_at; |
|
|
st = parse_at; |
|
|
} |
|
|
} |
|
|
else if (!is_atom (t)) { |
|
|
else if (!is_atom (t)) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
st = parse_at; |
|
|
st = parse_at; |
|
|
} |
|
|
} |
|
|
else if (!is_atom (t)) { |
|
|
else if (!is_atom (t)) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case parse_domain: |
|
|
case parse_domain: |
|
|
if (t == '/' || t == ':') { |
|
|
if (t == '/' || t == ':') { |
|
|
if (p - c == 0) { |
|
|
if (p - c == 0) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->field_set |= 1 << UF_HOST; |
|
|
u->field_set |= 1 << UF_HOST; |
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (uc == (gunichar)-1) { |
|
|
if (uc == (gunichar)-1) { |
|
|
/* Bad utf8 */ |
|
|
/* Bad utf8 */ |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!g_unichar_isalnum (uc)) { |
|
|
if (!g_unichar_isalnum (uc)) { |
|
|
/* Bad symbol */ |
|
|
/* Bad symbol */ |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
p = g_utf8_next_char (p); |
|
|
p = g_utf8_next_char (p); |
|
|
|
|
|
|
|
|
if (t == '/') { |
|
|
if (t == '/') { |
|
|
pt = strtoul (c, NULL, 10); |
|
|
pt = strtoul (c, NULL, 10); |
|
|
if (pt == 0 || pt > 65535) { |
|
|
if (pt == 0 || pt > 65535) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->port = pt; |
|
|
u->port = pt; |
|
|
st = parse_suffix_slash; |
|
|
st = parse_suffix_slash; |
|
|
} |
|
|
} |
|
|
else if (!g_ascii_isdigit (t)) { |
|
|
else if (!g_ascii_isdigit (t)) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
p ++; |
|
|
p ++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
switch (st) { |
|
|
switch (st) { |
|
|
case parse_domain: |
|
|
case parse_domain: |
|
|
if (p - c == 0) { |
|
|
if (p - c == 0) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->field_set |= 1 << UF_HOST; |
|
|
u->field_set |= 1 << UF_HOST; |
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
u->field_data[UF_HOST].len = p - c; |
|
|
|
|
|
|
|
|
case parse_port: |
|
|
case parse_port: |
|
|
pt = strtoul (c, NULL, 10); |
|
|
pt = strtoul (c, NULL, 10); |
|
|
if (pt == 0 || pt > 65535) { |
|
|
if (pt == 0 || pt > 65535) { |
|
|
return 1; |
|
|
|
|
|
|
|
|
goto out; |
|
|
} |
|
|
} |
|
|
u->port = pt; |
|
|
u->port = pt; |
|
|
ret = 0; |
|
|
ret = 0; |
|
|
|
|
|
|
|
|
ret = 1; |
|
|
ret = 1; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
out: |
|
|
|
|
|
if (end != NULL) { |
|
|
|
|
|
*end = p; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return ret; |
|
|
return ret; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (len > sizeof ("mailto:") - 1) { |
|
|
if (len > sizeof ("mailto:") - 1) { |
|
|
/* For mailto: urls we also need to add slashes to make it a valid URL */ |
|
|
/* For mailto: urls we also need to add slashes to make it a valid URL */ |
|
|
if (g_ascii_strncasecmp (p, "mailto:", sizeof ("mailto:") - 1) == 0) { |
|
|
if (g_ascii_strncasecmp (p, "mailto:", sizeof ("mailto:") - 1) == 0) { |
|
|
ret = rspamd_mailto_parse (&u, p); |
|
|
|
|
|
|
|
|
ret = rspamd_mailto_parse (&u, p, NULL); |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
ret = rspamd_web_parse (&u, p); |
|
|
|
|
|
|
|
|
ret = rspamd_web_parse (&u, p, NULL); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
ret = rspamd_web_parse (&u, p); |
|
|
|
|
|
|
|
|
ret = rspamd_web_parse (&u, p, NULL); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (ret != 0) { |
|
|
if (ret != 0) { |