parse.c 5.95 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* parse.c
 *
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen's avatar
J.H.M. Dassen committed
23
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
24
25
26
 */

#include "parse.h"
27
28
29

#include "format.h"
#include "list.h"
30
#include "werror.h"
Niels Möller's avatar
Niels Möller committed
31
#include "xalloc.h"
Niels Möller's avatar
Niels Möller committed
32

33
34
#include "parse_macros.h"

35
#include <assert.h>
36
37
#include <string.h>

Niels Möller's avatar
Niels Möller committed
38
39
40
void
simple_buffer_init(struct simple_buffer *buffer,
		   UINT32 capacity, const UINT8 *data)
Niels Möller's avatar
Niels Möller committed
41
42
43
44
45
46
{
  buffer->capacity = capacity;
  buffer->pos = 0;
  buffer->data = data;
}

Niels Möller's avatar
Niels Möller committed
47
48
int
parse_uint32(struct simple_buffer *buffer, UINT32 *result)
Niels Möller's avatar
Niels Möller committed
49
{
Niels Möller's avatar
Niels Möller committed
50
  if (LEFT < 4)
Niels Möller's avatar
Niels Möller committed
51
52
    return 0;

Niels Möller's avatar
Niels Möller committed
53
  *result = READ_UINT32(HERE);
Niels Möller's avatar
Niels Möller committed
54
55
56
57
  ADVANCE(4);
  return 1;
}

Niels Möller's avatar
Niels Möller committed
58
59
60
int
parse_string(struct simple_buffer *buffer,
	     UINT32 *length, const UINT8 **start)
Niels Möller's avatar
Niels Möller committed
61
62
63
64
65
66
{
  UINT32 l;

  if (!parse_uint32(buffer, &l))
    return 0;

Niels Möller's avatar
Niels Möller committed
67
  if (LEFT < l)
Niels Möller's avatar
Niels Möller committed
68
69
70
71
72
    return 0;

  *length = l;
  *start = HERE;
  ADVANCE(l);
Niels Möller's avatar
Niels Möller committed
73
  return 1;
Niels Möller's avatar
Niels Möller committed
74
75
}

Niels Möller's avatar
Niels Möller committed
76
77
78
int
parse_octets(struct simple_buffer *buffer,
	     UINT32 length, UINT8 *start)
79
80
81
82
83
84
85
86
{
  if (LEFT < length)
    return 0;
  memcpy(start, HERE, length);
  ADVANCE(length);
  return 1;
}

Niels Möller's avatar
Niels Möller committed
87
88
struct lsh_string *
parse_string_copy(struct simple_buffer *buffer)
89
90
{
  UINT32 length;
Niels Möller's avatar
Niels Möller committed
91
  const UINT8 *start;
92
  
93
  if (!parse_string(buffer, &length, &start))
94
95
96
97
98
    return NULL;

  return ssh_format("%ls", length, start);
}

Niels Möller's avatar
Niels Möller committed
99
/* Initializes subbuffer to parse a string from buffer */
Niels Möller's avatar
Niels Möller committed
100
101
102
int
parse_sub_buffer(struct simple_buffer *buffer,
		 struct simple_buffer *subbuffer)
Niels Möller's avatar
Niels Möller committed
103
104
{
  UINT32 length;
Niels Möller's avatar
Niels Möller committed
105
  const UINT8 *data;
Niels Möller's avatar
Niels Möller committed
106
107
108
109
110
111
112
113

  if (!parse_string(buffer, &length, &data))
    return 0;

  simple_buffer_init(subbuffer, length, data);
  return 1;
}

Niels Möller's avatar
Niels Möller committed
114
115
int
parse_uint8(struct simple_buffer *buffer, unsigned *result)
Niels Möller's avatar
Niels Möller committed
116
117
118
119
120
121
122
123
124
{
  if (!LEFT)
    return 0;

  *result = HERE[0];
  ADVANCE(1);
  return 1;
}

Niels Möller's avatar
Niels Möller committed
125
126
int
parse_utf8(struct simple_buffer *buffer, UINT32 *result)
Niels Möller's avatar
Niels Möller committed
127
128
129
130
131
132
133
134
135
136
137
138
139
{
  UINT32 first;
  int length;
  int i;
  
  if (!LEFT)
    return -1;

  first = HERE[0];

  if (first < 0x80)
    {
      *result = first;
Niels Möller's avatar
Niels Möller committed
140
      ADVANCE(1);
Niels Möller's avatar
Niels Möller committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
      return 1;
    }

  switch(first & 0xF0)
    {
    default:
      return 0;
    case 0xC0:
    case 0xD0:
      length = 2;
      *result = first & 0x1F;
      break;
    case 0xE0:
      length = 3;
      *result = first & 0x0F;
      break;
    case 0xF0:
      switch(first & 0x0E)
	{
	case 0: case 2: case 4: case 6:
	  length = 4;
	  *result = first & 0x07;
	  break;
164
	case 8: case 0xA:
Niels Möller's avatar
Niels Möller committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
	  length = 5;
	  *result = first & 0x03;
	  break;
	case 0xC:
	  length = 6;
	  *result = first & 0x01;
	  break;
	default:
	  fatal("Internal error!\n");
	}
      break;
    }
  for(i = 1; i<length; i++)
    {
      UINT32 c = HERE[i];
      if ( (c & 0xC0) != 0x80)
	return 0;
      *result = (*result << 6) | (c & 0x3f);
    }
  ADVANCE(length);
  return 1;
}  
      
Niels Möller's avatar
Niels Möller committed
188
189
int
parse_boolean(struct simple_buffer *buffer, int *result)
Niels Möller's avatar
Niels Möller committed
190
191
192
193
194
195
196
197
{
  if (!LEFT)
    return 0;
  *result = HERE[0];
  ADVANCE(1);
  return 1;
}

Niels Möller's avatar
Niels Möller committed
198
int
199
parse_bignum(struct simple_buffer *buffer, mpz_t result, UINT32 limit)
Niels Möller's avatar
Niels Möller committed
200
201
{
  UINT32 length;
Niels Möller's avatar
Niels Möller committed
202
  const UINT8 *digits;
Niels Möller's avatar
Niels Möller committed
203

Niels Möller's avatar
Niels Möller committed
204
  if (!parse_string(buffer, &length, &digits))
Niels Möller's avatar
Niels Möller committed
205
206
    return 0;

207
208
209
210
  /* NOTE: If the reciever expects an integer less than 256^limit,
   * there may still be limit + 1 digits, as a leading zero is
   * sometimes required to resolve signedness. */
  if (limit && (length > (limit + 1)))
211
212
    return 0;
  
213
  bignum_parse_s(result, length, digits);
Niels Möller's avatar
Niels Möller committed
214
215

  return 1;
Niels Möller's avatar
Niels Möller committed
216
217
}

Niels Möller's avatar
Niels Möller committed
218
int
219
parse_atom(struct simple_buffer *buffer, int *result)
Niels Möller's avatar
Niels Möller committed
220
221
{
  UINT32 length;
Niels Möller's avatar
Niels Möller committed
222
  const UINT8 *start;
Niels Möller's avatar
Niels Möller committed
223
224
225
226
227

  if ( (!parse_string(buffer, &length, &start))
       || length > 64)
    return 0;

228
  *result = lookup_atom(length, start);
Niels Möller's avatar
Niels Möller committed
229
230
231
232

  return 1;
}

Niels Möller's avatar
Niels Möller committed
233
234
235
/* NOTE: This functions record the fact that it has read to the end of
 * the buffer by setting the position to *beyond* the end of the
 * buffer. */
236
237
static int
parse_next_atom(struct simple_buffer *buffer, int *result)
Niels Möller's avatar
Niels Möller committed
238
239
240
{
  UINT32 i;

241
  assert (buffer->pos <=buffer->capacity);
Niels Möller's avatar
Niels Möller committed
242

Niels Möller's avatar
Niels Möller committed
243
  for(i = 0; i < LEFT; i++)
Niels Möller's avatar
Niels Möller committed
244
245
246
247
248
249
250
    {
      if (HERE[i] == ',')
	break;
      if (i == 64)
	/* Atoms can be no larger than 64 characters */
	return 0;
    }
251
252
253
254
255

  /* No empty atoms. */
  if (!i)
    return 0;

256
  *result = lookup_atom(i, HERE);
Niels Möller's avatar
Niels Möller committed
257
258
259
  ADVANCE(i+1);  /* If the atom was terminated at the end of the
		  * buffer, rather than by a comma, this points beyond
		  * the end of the buffer */
Niels Möller's avatar
Niels Möller committed
260
261
262
  return 1;
}

Niels Möller's avatar
Niels Möller committed
263
264
struct int_list *
parse_atoms(struct simple_buffer *buffer, unsigned limit)
Niels Möller's avatar
Niels Möller committed
265
{
266
267
  unsigned count;
  unsigned i;
268
  struct int_list *res;
269
270

  assert(limit);
271
272
273

  if (!LEFT)
    return make_int_list(0, -1);
Niels Möller's avatar
Niels Möller committed
274
275
276
277
  
  /* Count commas (no commas means one atom) */
  for (i = buffer->pos, count = 1; i < buffer->capacity; i++)
    if (buffer->data[i] == ',')
278
279
280
281
282
      {
	if (count >= limit)
	  return NULL;
	count++;
      }
Niels Möller's avatar
Niels Möller committed
283

284
  res = alloc_int_list(count);
Niels Möller's avatar
Niels Möller committed
285
286
287

  for (i = 0; i < count; i++)
    {
288
      if (!parse_next_atom(buffer, LIST(res)+i))
Niels Möller's avatar
Niels Möller committed
289
	{
290
	  KILL(res);
Niels Möller's avatar
Niels Möller committed
291
292
293
	  return NULL;
	}
    }
294

Niels Möller's avatar
Niels Möller committed
295
296
297
  return res;
}

Niels Möller's avatar
Niels Möller committed
298
299
struct int_list *
parse_atom_list(struct simple_buffer *buffer, unsigned limit)
300
301
302
303
304
305
306
307
308
{
  struct simple_buffer sub_buffer;

  if (!parse_sub_buffer(buffer, &sub_buffer))
    return NULL;

  return parse_atoms(&sub_buffer, limit);
}

309
310
311
312
313
314
315
316
317
318
319
320
struct lsh_string *
parse_rest(struct simple_buffer *buffer)
{
  UINT32 length = LEFT;
  struct lsh_string *s = ssh_format("%ls", length, HERE);

  ADVANCE(length);
  assert(!LEFT);

  return s;
}

Niels Möller's avatar
Niels Möller committed
321
/* Returns success (i.e. 1) iff there is no data left */
Niels Möller's avatar
Niels Möller committed
322
323
int
parse_eod(struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
324
325
326
{
  return !LEFT;
}