parse.c 5.33 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
23
 *
 *
 * $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
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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
41
42
43
44
45
46
47
void simple_buffer_init(struct simple_buffer *buffer,
			UINT32 capacity, UINT8 *data)
{
  buffer->capacity = capacity;
  buffer->pos = 0;
  buffer->data = data;
}

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

Niels Möller's avatar
Niels Möller committed
51
  *result = READ_UINT32(HERE);
Niels Möller's avatar
Niels Möller committed
52
53
54
55
56
57
58
59
60
61
62
63
  ADVANCE(4);
  return 1;
}

int parse_string(struct simple_buffer *buffer,
		 UINT32 *length, UINT8 **start)
{
  UINT32 l;

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

Niels Möller's avatar
Niels Möller committed
64
  if (LEFT < l)
Niels Möller's avatar
Niels Möller committed
65
66
67
68
69
    return 0;

  *length = l;
  *start = HERE;
  ADVANCE(l);
Niels Möller's avatar
Niels Möller committed
70
  return 1;
Niels Möller's avatar
Niels Möller committed
71
72
}

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
int parse_octets(struct simple_buffer *buffer,
		 UINT32 length, UINT8 *start)
{
  if (LEFT < length)
    return 0;
  memcpy(start, HERE, length);
  ADVANCE(length);
  return 1;
}

struct lsh_string *parse_string_copy(struct simple_buffer *buffer)
{
  UINT32 length;
  UINT8 *start;
  
88
  if (!parse_string(buffer, &length, &start))
89
90
91
92
93
    return NULL;

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

Niels Möller's avatar
Niels Möller committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Initializes subbuffer to parse a string from buffer */
int parse_sub_buffer(struct simple_buffer *buffer,
		     struct simple_buffer *subbuffer)
{
  UINT32 length;
  UINT8 *data;

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

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

108
int parse_uint8(struct simple_buffer *buffer, unsigned *result)
Niels Möller's avatar
Niels Möller committed
109
110
111
112
113
114
115
116
117
{
  if (!LEFT)
    return 0;

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

Niels Möller's avatar
Niels Möller committed
118
119
120
121
122
123
124
125
126
127
128
129
130
131
int parse_utf8(struct simple_buffer *buffer, UINT32 *result)
{
  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
132
      ADVANCE(1);
Niels Möller's avatar
Niels Möller committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
      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;
156
	case 8: case 0xA:
Niels Möller's avatar
Niels Möller committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
	  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
180
181
182
183
184
185
186
187
188
int parse_boolean(struct simple_buffer *buffer, int *result)
{
  if (!LEFT)
    return 0;
  *result = HERE[0];
  ADVANCE(1);
  return 1;
}

189
int parse_bignum(struct simple_buffer *buffer, mpz_t result)
Niels Möller's avatar
Niels Möller committed
190
191
192
193
{
  UINT32 length;
  UINT8 *digits;

Niels Möller's avatar
Niels Möller committed
194
  if (!parse_string(buffer, &length, &digits))
Niels Möller's avatar
Niels Möller committed
195
196
    return 0;

197
  bignum_parse_s(result, length, digits);
Niels Möller's avatar
Niels Möller committed
198
199

  return 1;
Niels Möller's avatar
Niels Möller committed
200
201
}

Niels Möller's avatar
Niels Möller committed
202
203
204
205
206
207
208
209
210
int parse_atom(struct simple_buffer *buffer, int *result)
{
  UINT32 length;
  UINT8 *start;

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

211
  *result = lookup_atom(length, start);
Niels Möller's avatar
Niels Möller committed
212
213
214
215

  return 1;
}

Niels Möller's avatar
Niels Möller committed
216
217
218
219
220
221
222
223
224
225
226
227
228
/* Returns 1 on success, 0 on failure, and -1 at end of buffer.
 * Unknown atoms sets result to zero. */

/* 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. */
int parse_next_atom(struct simple_buffer *buffer, int *result)
{
  UINT32 i;

  if (buffer->pos > buffer->capacity)
    return -1;

Niels Möller's avatar
Niels Möller committed
229
  for(i = 0; i < LEFT; i++)
Niels Möller's avatar
Niels Möller committed
230
231
232
233
234
235
236
237
    {
      if (HERE[i] == ',')
	break;
      if (i == 64)
	/* Atoms can be no larger than 64 characters */
	return 0;
    }
  
238
  *result = lookup_atom(i, HERE);
Niels Möller's avatar
Niels Möller committed
239
240
241
  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
242
243
244
  return 1;
}

245
struct int_list *parse_atom_list(struct simple_buffer *buffer, unsigned limit)
Niels Möller's avatar
Niels Möller committed
246
{
247
248
  unsigned count;
  unsigned i;
249
  struct int_list *res;
250
251

  assert(limit);
Niels Möller's avatar
Niels Möller committed
252
253
254
255
  
  /* Count commas (no commas means one atom) */
  for (i = buffer->pos, count = 1; i < buffer->capacity; i++)
    if (buffer->data[i] == ',')
256
257
258
259
260
      {
	if (count >= limit)
	  return NULL;
	count++;
      }
Niels Möller's avatar
Niels Möller committed
261

262
  res = alloc_int_list(count);
Niels Möller's avatar
Niels Möller committed
263
264
265

  for (i = 0; i < count; i++)
    {
266
      switch(parse_next_atom(buffer, LIST(res)+i))
Niels Möller's avatar
Niels Möller committed
267
268
269
270
	{
	case 1:
	  continue;
	case 0:
271
	  KILL(res);
Niels Möller's avatar
Niels Möller committed
272
273
274
275
276
	  return NULL;
	default:
	  fatal("Internal error\n");
	}
    }
277

Niels Möller's avatar
Niels Möller committed
278
279
280
  return res;
}

Niels Möller's avatar
Niels Möller committed
281
/* Returns success (i.e. 1) iff there is no data left */
Niels Möller's avatar
Niels Möller committed
282
int parse_eod(struct simple_buffer *buffer)
Niels Möller's avatar
Niels Möller committed
283
284
285
{
  return !LEFT;
}