~ubuntu-branches/ubuntu/trusty/vsftpd/trusty-proposed

1.2.1 by Daniel Jacobowitz
Import upstream version 2.0.3
1
/*
2
 * Part of Very Secure FTPd
3
 * Licence: GPL v2
4
 * Author: Chris Evans
5
 * ipaddrparse.c
6
 *
7
 * A routine to parse ip addresses. I'm paranoid and don't want to use
8
 * inet_pton.
9
 */
10
11
#include "ipaddrparse.h"
12
#include "sysutil.h"
13
#include "str.h"
14
15
static int ipv6_parse_main(struct mystr* p_out_str,
16
                           const struct mystr* p_in_str);
17
static int ipv6_parse_hex(struct mystr* p_out_str,
18
                          const struct mystr* p_in_str);
19
static int ipv4_parse_dotquad(struct mystr* p_out_str,
20
                              const struct mystr* p_in_str);
21
22
const unsigned char*
23
vsf_sysutil_parse_ipv6(const struct mystr* p_str)
24
{
25
  static struct mystr s_ret;
26
  static struct mystr s_rhs_ret;
27
  static struct mystr s_lhs_str;
28
  static struct mystr s_rhs_str;
29
  unsigned int lhs_len;
30
  unsigned int rhs_len;
31
  str_empty(&s_ret);
32
  str_empty(&s_rhs_ret);
33
  str_copy(&s_lhs_str, p_str);
34
  str_split_text(&s_lhs_str, &s_rhs_str, "::");
35
  if (!ipv6_parse_main(&s_ret, &s_lhs_str))
36
  {
37
    return 0;
38
  }
39
  if (!ipv6_parse_main(&s_rhs_ret, &s_rhs_str))
40
  {
41
    return 0;
42
  }
43
  lhs_len = str_getlen(&s_ret);
44
  rhs_len = str_getlen(&s_rhs_ret);
45
  if (lhs_len + rhs_len > 16)
46
  {
47
    return 0;
48
  }
49
  if (rhs_len > 0)
50
  {
51
    unsigned int add_nulls = 16 - (lhs_len + rhs_len);
52
    while (add_nulls--)
53
    {
54
      str_append_char(&s_ret, '\0');
55
    }
56
    str_append_str(&s_ret, &s_rhs_ret);
57
  }
1.3.1 by Matej Vela
Import upstream version 2.0.5
58
  return (const unsigned char*) str_getbuf(&s_ret);
1.2.1 by Daniel Jacobowitz
Import upstream version 2.0.3
59
}
60
61
const unsigned char*
62
vsf_sysutil_parse_ipv4(const struct mystr* p_str)
63
{
64
  static unsigned char items[4];
65
  return vsf_sysutil_parse_uchar_string_sep(p_str, '.', items, sizeof(items));
66
}
67
68
const unsigned char*
69
vsf_sysutil_parse_uchar_string_sep(
70
  const struct mystr* p_str, char sep, unsigned char* p_items,
71
  unsigned int items)
72
{
73
  static struct mystr s_tmp_str;
74
  unsigned int i;
75
  str_copy(&s_tmp_str, p_str);
76
  for (i=0; i<items; i++)
77
  {
78
    static struct mystr s_rhs_sep_str;
79
    int this_number;
80
    /* This puts a single separator delimited field in tmp_str */
81
    str_split_char(&s_tmp_str, &s_rhs_sep_str, sep);
82
    /* Sanity - check for too many or two few dots! */
83
    if ( (i < (items-1) && str_isempty(&s_rhs_sep_str)) ||
84
         (i == (items-1) && !str_isempty(&s_rhs_sep_str)))
85
    {
86
      return 0;
87
    }
88
    this_number = str_atoi(&s_tmp_str);
89
    if (this_number < 0 || this_number > 255)
90
    {
91
      return 0;
92
    }
93
    /* If this truncates from int to uchar, we don't care */
94
    p_items[i] = (unsigned char) this_number;
95
    /* The right hand side of the comma now becomes the new string to
96
     * breakdown
97
     */
98
    str_copy(&s_tmp_str, &s_rhs_sep_str);
99
  }
100
  return p_items;
101
}
102
103
static int
104
ipv6_parse_main(struct mystr* p_out_str, const struct mystr* p_in_str)
105
{
106
  static struct mystr s_lhs_str;
107
  static struct mystr s_rhs_str;
108
  struct str_locate_result loc_ret;
109
  str_copy(&s_lhs_str, p_in_str);
110
  while (!str_isempty(&s_lhs_str))
111
  {
112
    str_split_char(&s_lhs_str, &s_rhs_str, ':');
113
    if (str_isempty(&s_lhs_str))
114
    {
115
      return 0;
116
    }
117
    loc_ret = str_locate_char(&s_lhs_str, '.');
118
    if (loc_ret.found)
119
    {
120
      if (!ipv4_parse_dotquad(p_out_str, &s_lhs_str))
121
      {
122
        return 0;
123
      }
124
    }
125
    else if (!ipv6_parse_hex(p_out_str, &s_lhs_str))
126
    {
127
      return 0;
128
    }
129
    str_copy(&s_lhs_str, &s_rhs_str);
130
  }
131
  return 1;
132
}
133
134
static int
135
ipv6_parse_hex(struct mystr* p_out_str, const struct mystr* p_in_str)
136
{
137
  unsigned int len = str_getlen(p_in_str);
138
  unsigned int i;
139
  unsigned int val = 0;
140
  for (i=0; i<len; ++i)
141
  {
142
    int ch = vsf_sysutil_toupper(str_get_char_at(p_in_str, i));
143
    if (ch >= '0' && ch <= '9')
144
    {
145
      ch -= '0';
146
    }
147
    else if (ch >= 'A' && ch <= 'F')
148
    {
149
      ch -= 'A';
150
      ch += 10;
151
    }
152
    else
153
    {
154
      return 0;
155
    }
156
    val <<= 4;
157
    val |= ch;
158
    if (val > 0xFFFF)
159
    {
160
      return 0;
161
    }
162
  }
163
  str_append_char(p_out_str, (val >> 8));
164
  str_append_char(p_out_str, (val & 0xFF));
165
  return 1;
166
}
167
168
static int
169
ipv4_parse_dotquad(struct mystr* p_out_str, const struct mystr* p_in_str)
170
{
171
  unsigned int len = str_getlen(p_in_str);
172
  unsigned int i;
173
  unsigned int val = 0;
174
  unsigned int final_val = 0;
175
  int seen_char = 0;
176
  int dots = 0;
177
  for (i=0; i<len; ++i)
178
  {
179
    int ch = str_get_char_at(p_in_str, i);
180
    if (ch == '.')
181
    {
182
      if (!seen_char || dots == 3)
183
      {
184
        return 0;
185
      }
186
      seen_char = 0;
187
      dots++;
188
      final_val <<= 8;
189
      final_val |= val;
190
      val = 0;
191
    }
192
    else if (ch >= '0' && ch <= '9')
193
    {
194
      ch -= '0';
195
      val *= 10;
196
      val += ch;
197
      if (val > 255)
198
      {
199
        return 0;
200
      }
201
      seen_char = 1;
202
    }
203
    else
204
    {
205
      return 0;
206
    }
207
  }
208
  if (dots != 3 || !seen_char)
209
  {
210
    return 0;
211
  }
212
  final_val <<= 8;
213
  final_val |= val;
214
  str_append_char(p_out_str, (final_val >> 24));
215
  str_append_char(p_out_str, ((final_val >> 16) & 0xFF));
216
  str_append_char(p_out_str, ((final_val >> 8) & 0xFF));
217
  str_append_char(p_out_str, (final_val & 0xFF));
218
  return 1;
219
}
220