~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/pack.c

Added libdrizzle to the tree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Drizzle Client & Protocol Library
 
3
 *
 
4
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
 
5
 * All rights reserved.
 
6
 *
 
7
 * Use and distribution licensed under the BSD license.  See
 
8
 * the COPYING file in this directory for full text.
 
9
 */
 
10
 
 
11
/**
 
12
 * @file
 
13
 * @brief Packing definitions
 
14
 */
 
15
 
 
16
#include "common.h"
 
17
 
 
18
/*
 
19
 * Private declarations
 
20
 */
 
21
 
 
22
/**
 
23
 * @addtogroup drizzle_pack_private Private Packing Functions
 
24
 * @ingroup drizzle_pack
 
25
 * @{
 
26
 */
 
27
 
 
28
/**
 
29
 * Compute hash from password and scramble.
 
30
 */
 
31
static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
 
32
                                            uint8_t *buffer);
 
33
 
 
34
/** @} */
 
35
 
 
36
/*
 
37
 * Public definitions
 
38
 */
 
39
 
 
40
uint8_t *drizzle_pack_length(uint64_t number, uint8_t *ptr)
 
41
{
 
42
  if (number < 251)
 
43
  {
 
44
    ptr[0]= (uint8_t)number;
 
45
    ptr++;
 
46
  }
 
47
  else if (number < 65536)
 
48
  {
 
49
    ptr[0]= 252;
 
50
    ptr++;
 
51
    drizzle_set_byte2(ptr, number);
 
52
    ptr+= 2;
 
53
  }
 
54
  else if (number < 16777216)
 
55
  {
 
56
    ptr[0]= 253;
 
57
    ptr++;
 
58
    drizzle_set_byte3(ptr, number);
 
59
    ptr+= 3;
 
60
  }
 
61
  else
 
62
  {
 
63
    ptr[0]= 254;
 
64
    ptr++;
 
65
    drizzle_set_byte8(ptr, number);
 
66
    ptr+= 8;
 
67
  }
 
68
 
 
69
  return ptr;
 
70
}
 
71
 
 
72
uint64_t drizzle_unpack_length(drizzle_con_st *con, drizzle_return_t *ret_ptr)
 
73
{
 
74
  uint64_t length;
 
75
  uint8_t bytes;
 
76
 
 
77
  if (con->buffer_ptr[0] < 251)
 
78
  {
 
79
    length= (uint64_t)(con->buffer_ptr[0]);
 
80
    bytes= 1;
 
81
  }
 
82
  else if (con->buffer_ptr[0] == 251)
 
83
  {
 
84
    con->buffer_ptr++;
 
85
    con->buffer_size--;
 
86
    con->packet_size--;
 
87
 
 
88
    *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
 
89
    return 0;
 
90
  }
 
91
  else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
 
92
  {
 
93
    length= drizzle_get_byte2(con->buffer_ptr + 1);
 
94
    bytes= 3;
 
95
  }
 
96
  else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
 
97
  {
 
98
    length= drizzle_get_byte3(con->buffer_ptr + 1);
 
99
    bytes= 4;
 
100
  }
 
101
  else if (con->buffer_size > 8)
 
102
  {
 
103
    length= drizzle_get_byte8(con->buffer_ptr + 1);
 
104
    bytes= 9;
 
105
  }
 
106
  else
 
107
  {
 
108
    *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
 
109
    return 0;
 
110
  }
 
111
 
 
112
  con->buffer_ptr+= bytes;
 
113
  con->buffer_size-= bytes;
 
114
  con->packet_size-= bytes;
 
115
 
 
116
  *ret_ptr= DRIZZLE_RETURN_OK;
 
117
  return length;
 
118
}
 
119
 
 
120
uint8_t *drizzle_pack_string(char *string, uint8_t *ptr)
 
121
{
 
122
  uint64_t size= strlen(string);
 
123
 
 
124
  ptr= drizzle_pack_length(size, ptr);
 
125
  if (size > 0)
 
126
  {
 
127
    memcpy(ptr, string, (size_t)size);
 
128
    ptr+= size;
 
129
  }
 
130
 
 
131
  return ptr;
 
132
}
 
133
 
 
134
drizzle_return_t drizzle_unpack_string(drizzle_con_st *con, char *buffer,
 
135
                                       uint64_t max_length)
 
136
{
 
137
  drizzle_return_t ret= DRIZZLE_RETURN_OK;
 
138
  uint64_t length;
 
139
 
 
140
  length= drizzle_unpack_length(con, &ret);
 
141
  if (ret != DRIZZLE_RETURN_OK)
 
142
  {
 
143
    if (ret == DRIZZLE_RETURN_NULL_SIZE)
 
144
    {
 
145
      drizzle_set_error(con->drizzle, "drizzle_unpack_string",
 
146
                        "unexpected NULL length");
 
147
    }
 
148
 
 
149
    return ret;
 
150
  }
 
151
 
 
152
  if (length < max_length)
 
153
  {
 
154
    if (length > 0)
 
155
      memcpy(buffer, con->buffer_ptr, (size_t)length);
 
156
 
 
157
    buffer[length]= 0;
 
158
  }
 
159
  else
 
160
  {
 
161
    memcpy(buffer, con->buffer_ptr, (size_t)(max_length - 1));
 
162
    buffer[max_length - 1]= 0;
 
163
  }
 
164
  
 
165
  con->buffer_ptr+= length;
 
166
  con->buffer_size-= (size_t)length;
 
167
  con->packet_size-= (size_t)length;
 
168
 
 
169
  return DRIZZLE_RETURN_OK;
 
170
}
 
171
 
 
172
uint8_t *drizzle_pack_auth(drizzle_con_st *con, uint8_t *ptr,
 
173
                           drizzle_return_t *ret_ptr)
 
174
{
 
175
  if (con->user[0] != 0)
 
176
  {
 
177
    memcpy(ptr, con->user, strlen(con->user));
 
178
    ptr+= strlen(con->user);
 
179
  }
 
180
 
 
181
  ptr[0]= 0;
 
182
  ptr++;
 
183
 
 
184
  if (con->options & DRIZZLE_CON_RAW_SCRAMBLE && con->scramble != NULL)
 
185
  {
 
186
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
187
    ptr++;
 
188
 
 
189
    memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
 
190
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
191
  }
 
192
  else if (con->password[0] == 0)
 
193
  {
 
194
    ptr[0]= 0;
 
195
    ptr++;
 
196
    con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
197
  }
 
198
  else
 
199
  {
 
200
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
201
    ptr++;
 
202
 
 
203
    if (con->options & DRIZZLE_CON_MYSQL)
 
204
    {
 
205
      *ret_ptr= _pack_scramble_hash(con, ptr);
 
206
      if (*ret_ptr != DRIZZLE_RETURN_OK)
 
207
        return ptr;
 
208
    }
 
209
    else
 
210
      snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
 
211
 
 
212
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
213
  }
 
214
 
 
215
  if (con->db[0] != 0)
 
216
  {
 
217
    memcpy(ptr, con->db, strlen(con->db));
 
218
    ptr+= strlen(con->db);
 
219
  }
 
220
 
 
221
  ptr[0]= 0;
 
222
  ptr++;
 
223
 
 
224
  *ret_ptr= DRIZZLE_RETURN_OK;
 
225
  return ptr;
 
226
}
 
227
 
 
228
/*
 
229
 * Private definitions
 
230
 */
 
231
 
 
232
static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
 
233
                                            uint8_t *buffer)
 
234
{
 
235
  SHA1_CTX ctx;
 
236
  uint8_t hash_tmp1[SHA1_DIGEST_LENGTH];
 
237
  uint8_t hash_tmp2[SHA1_DIGEST_LENGTH];
 
238
  uint32_t x;
 
239
 
 
240
  if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
 
241
  {
 
242
    drizzle_set_error(con->drizzle, "_pack_scramble_hash",
 
243
                      "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
 
244
                      DRIZZLE_MAX_SCRAMBLE_SIZE);
 
245
    return DRIZZLE_RETURN_INTERNAL_ERROR;
 
246
  }
 
247
 
 
248
  if (con->scramble == NULL)
 
249
  {
 
250
    drizzle_set_error(con->drizzle, "_pack_scramble_hash",
 
251
                      "no scramble buffer");
 
252
    return DRIZZLE_RETURN_NO_SCRAMBLE;
 
253
  }
 
254
 
 
255
  /* First hash the password. */
 
256
  SHA1Init(&ctx);
 
257
  SHA1Update(&ctx, (uint8_t *)(con->password), strlen(con->password));
 
258
  SHA1Final(hash_tmp1, &ctx);
 
259
 
 
260
  /* Second, hash the password hash. */
 
261
  SHA1Init(&ctx);
 
262
  SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
 
263
  SHA1Final(hash_tmp2, &ctx);
 
264
 
 
265
  /* Third, hash the scramble and the double password hash. */
 
266
  SHA1Init(&ctx);
 
267
  SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
 
268
  SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
 
269
  SHA1Final(buffer, &ctx);
 
270
 
 
271
  /* Fourth, xor the last hash against the first password hash. */
 
272
  for (x= 0; x < SHA1_DIGEST_LENGTH; x++)
 
273
    buffer[x]= buffer[x] ^ hash_tmp1[x];
 
274
 
 
275
  return DRIZZLE_RETURN_OK;
 
276
}