~drizzle-trunk/libdrizzle/jenkins-Libdrizzle-78

« back to all changes in this revision

Viewing changes to libdrizzle/pack.c

  • Committer: Andrew Hutchings
  • Date: 2012-09-03 18:38:34 UTC
  • Revision ID: git-v1:e936672f2f2e4af2b54de08ebf06d53ca1dc6872
The "it compiles!" version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
2
 *
 
3
 * Drizzle Client & Protocol Library
 
4
 *
 
5
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions are
 
10
 * met:
 
11
 *
 
12
 *     * Redistributions of source code must retain the above copyright
 
13
 * notice, this list of conditions and the following disclaimer.
 
14
 *
 
15
 *     * Redistributions in binary form must reproduce the above
 
16
 * copyright notice, this list of conditions and the following disclaimer
 
17
 * in the documentation and/or other materials provided with the
 
18
 * distribution.
 
19
 *
 
20
 *     * The names of its contributors may not be used to endorse or
 
21
 * promote products derived from this software without specific prior
 
22
 * written permission.
 
23
 *
 
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
25
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
26
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
27
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
28
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
29
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
30
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
31
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
32
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
33
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
34
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
35
 *
 
36
 */
 
37
 
 
38
/**
 
39
 * @file
 
40
 * @brief Packing definitions
 
41
 */
 
42
 
 
43
#include <libdrizzle/common.h>
 
44
 
 
45
/*
 
46
 * Private declarations
 
47
 */
 
48
 
 
49
/**
 
50
 * @addtogroup drizzle_pack_private Private Packing Functions
 
51
 * @ingroup drizzle_pack
 
52
 * @{
 
53
 */
 
54
 
 
55
/**
 
56
 * Compute hash from password and scramble.
 
57
 */
 
58
static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
 
59
                                            uint8_t *buffer);
 
60
 
 
61
/** @} */
 
62
 
 
63
/*
 
64
 * Public definitions
 
65
 */
 
66
 
 
67
uint8_t *drizzle_pack_length(uint64_t number, uint8_t *ptr)
 
68
{
 
69
  if (number < 251)
 
70
  {
 
71
    ptr[0]= (uint8_t)number;
 
72
    ptr++;
 
73
  }
 
74
  else if (number < 65536)
 
75
  {
 
76
    ptr[0]= 252;
 
77
    ptr++;
 
78
    drizzle_set_byte2(ptr, number);
 
79
    ptr+= 2;
 
80
  }
 
81
  else if (number < 16777216)
 
82
  {
 
83
    ptr[0]= 253;
 
84
    ptr++;
 
85
    drizzle_set_byte3(ptr, number);
 
86
    ptr+= 3;
 
87
  }
 
88
  else
 
89
  {
 
90
    ptr[0]= 254;
 
91
    ptr++;
 
92
    drizzle_set_byte8(ptr, number);
 
93
    ptr+= 8;
 
94
  }
 
95
 
 
96
  return ptr;
 
97
}
 
98
 
 
99
uint64_t drizzle_unpack_length(drizzle_con_st *con, drizzle_return_t *ret_ptr)
 
100
{
 
101
  uint64_t length;
 
102
  uint8_t bytes;
 
103
 
 
104
  drizzle_return_t unused_ret;
 
105
  if (ret_ptr == NULL)
 
106
  {
 
107
    ret_ptr= &unused_ret;
 
108
  }
 
109
 
 
110
  if (con == NULL)
 
111
  {
 
112
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
 
113
    return 0;
 
114
  }
 
115
 
 
116
  if (con->buffer_ptr[0] < 251)
 
117
  {
 
118
    length= (uint64_t)(con->buffer_ptr[0]);
 
119
    bytes= 1;
 
120
  }
 
121
  else if (con->buffer_ptr[0] == 251)
 
122
  {
 
123
    con->buffer_ptr++;
 
124
    con->buffer_size--;
 
125
    con->packet_size--;
 
126
 
 
127
    *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
 
128
    return 0;
 
129
  }
 
130
  else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
 
131
  {
 
132
    length= drizzle_get_byte2(con->buffer_ptr + 1);
 
133
    bytes= 3;
 
134
  }
 
135
  else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
 
136
  {
 
137
    length= drizzle_get_byte3(con->buffer_ptr + 1);
 
138
    bytes= 4;
 
139
  }
 
140
  else if (con->buffer_size > 8)
 
141
  {
 
142
    length= drizzle_get_byte8(con->buffer_ptr + 1);
 
143
    bytes= 9;
 
144
  }
 
145
  else
 
146
  {
 
147
    *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
 
148
    return 0;
 
149
  }
 
150
 
 
151
  con->buffer_ptr+= bytes;
 
152
  con->buffer_size-= bytes;
 
153
  con->packet_size-= bytes;
 
154
 
 
155
  *ret_ptr= DRIZZLE_RETURN_OK;
 
156
  return length;
 
157
}
 
158
 
 
159
uint8_t *drizzle_pack_string(char *string, uint8_t *ptr)
 
160
{
 
161
  if (string == NULL)
 
162
  {
 
163
    return NULL;
 
164
  }
 
165
 
 
166
  uint64_t size= strlen(string);
 
167
 
 
168
  ptr= drizzle_pack_length(size, ptr);
 
169
  if (size > 0)
 
170
  {
 
171
    memcpy(ptr, string, (size_t)size);
 
172
    ptr+= size;
 
173
  }
 
174
 
 
175
  return ptr;
 
176
}
 
177
 
 
178
drizzle_return_t drizzle_unpack_string(drizzle_con_st *con, char *buffer,
 
179
                                       uint64_t max_length)
 
180
{
 
181
  drizzle_return_t ret= DRIZZLE_RETURN_OK;
 
182
 
 
183
  if (con == NULL)
 
184
  {
 
185
    return DRIZZLE_RETURN_INVALID_ARGUMENT;
 
186
  }
 
187
 
 
188
  uint64_t length= drizzle_unpack_length(con, &ret);
 
189
  if (ret != DRIZZLE_RETURN_OK)
 
190
  {
 
191
    if (ret == DRIZZLE_RETURN_NULL_SIZE)
 
192
    {
 
193
      drizzle_set_error(con->drizzle, "drizzle_unpack_string",
 
194
                        "unexpected NULL length");
 
195
    }
 
196
 
 
197
    return ret;
 
198
  }
 
199
 
 
200
  if (length < max_length)
 
201
  {
 
202
    if (length > 0)
 
203
      memcpy(buffer, con->buffer_ptr, (size_t)length);
 
204
 
 
205
    buffer[length]= 0;
 
206
  }
 
207
  else
 
208
  {
 
209
    memcpy(buffer, con->buffer_ptr, (size_t)(max_length - 1));
 
210
    buffer[max_length - 1]= 0;
 
211
  }
 
212
  
 
213
  con->buffer_ptr+= length;
 
214
  con->buffer_size-= (size_t)length;
 
215
  con->packet_size-= (size_t)length;
 
216
 
 
217
  return DRIZZLE_RETURN_OK;
 
218
}
 
219
 
 
220
uint8_t *drizzle_pack_auth(drizzle_con_st *con, uint8_t *ptr,
 
221
                           drizzle_return_t *ret_ptr)
 
222
{
 
223
  drizzle_return_t unused_ret;
 
224
  if (ret_ptr == NULL)
 
225
  {
 
226
    ret_ptr= &unused_ret;
 
227
  }
 
228
 
 
229
  if (con == NULL)
 
230
  {
 
231
    *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
 
232
    return NULL;
 
233
  }
 
234
 
 
235
  if (con->user[0] != 0)
 
236
  {
 
237
    memcpy(ptr, con->user, strlen(con->user));
 
238
    ptr+= strlen(con->user);
 
239
  }
 
240
 
 
241
  ptr[0]= 0;
 
242
  ptr++;
 
243
 
 
244
  if (con->options & DRIZZLE_CON_RAW_SCRAMBLE && con->scramble != NULL)
 
245
  {
 
246
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
247
    ptr++;
 
248
 
 
249
    memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
 
250
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
251
  }
 
252
  else if (con->password[0] == 0)
 
253
  {
 
254
    ptr[0]= 0;
 
255
    ptr++;
 
256
    con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
257
  }
 
258
  else
 
259
  {
 
260
    ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
261
    ptr++;
 
262
 
 
263
    if (con->options & DRIZZLE_CON_MYSQL && con->options & DRIZZLE_CON_AUTH_PLUGIN)
 
264
    {
 
265
      snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
 
266
      ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
 
267
    }
 
268
    else if (con->options & DRIZZLE_CON_MYSQL)
 
269
    {
 
270
      *ret_ptr= _pack_scramble_hash(con, ptr);
 
271
      if (*ret_ptr != DRIZZLE_RETURN_OK)
 
272
        return ptr;
 
273
    }
 
274
    else // We assume Drizzle
 
275
    {
 
276
      snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
 
277
      ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
 
278
    }
 
279
 
 
280
    ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
 
281
  }
 
282
 
 
283
  if (con->db[0] != 0)
 
284
  {
 
285
    memcpy(ptr, con->db, strlen(con->db));
 
286
    ptr+= strlen(con->db);
 
287
  }
 
288
 
 
289
  ptr[0]= 0;
 
290
  ptr++;
 
291
 
 
292
  *ret_ptr= DRIZZLE_RETURN_OK;
 
293
  return ptr;
 
294
}
 
295
 
 
296
/*
 
297
 * Private definitions
 
298
 */
 
299
 
 
300
static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
 
301
                                            uint8_t *buffer)
 
302
{
 
303
  SHA1_CTX ctx;
 
304
  uint8_t hash_tmp1[SHA1_DIGEST_LENGTH];
 
305
  uint8_t hash_tmp2[SHA1_DIGEST_LENGTH];
 
306
 
 
307
  if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
 
308
  {
 
309
    drizzle_set_error(con->drizzle, "_pack_scramble_hash",
 
310
                      "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
 
311
                      DRIZZLE_MAX_SCRAMBLE_SIZE);
 
312
    return DRIZZLE_RETURN_INTERNAL_ERROR;
 
313
  }
 
314
 
 
315
  if (con->scramble == NULL)
 
316
  {
 
317
    drizzle_set_error(con->drizzle, "_pack_scramble_hash",
 
318
                      "no scramble buffer");
 
319
    return DRIZZLE_RETURN_NO_SCRAMBLE;
 
320
  }
 
321
 
 
322
  /* First hash the password. */
 
323
  SHA1Init(&ctx);
 
324
  SHA1Update(&ctx, (uint8_t *)(con->password), strlen(con->password));
 
325
  SHA1Final(hash_tmp1, &ctx);
 
326
 
 
327
  /* Second, hash the password hash. */
 
328
  SHA1Init(&ctx);
 
329
  SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
 
330
  SHA1Final(hash_tmp2, &ctx);
 
331
 
 
332
  /* Third, hash the scramble and the double password hash. */
 
333
  SHA1Init(&ctx);
 
334
  SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
 
335
  SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
 
336
  SHA1Final(buffer, &ctx);
 
337
 
 
338
  /* Fourth, xor the last hash against the first password hash. */
 
339
  uint32_t x;
 
340
  for (x= 0; x < SHA1_DIGEST_LENGTH; x++)
 
341
  {
 
342
    buffer[x]= buffer[x] ^ hash_tmp1[x];
 
343
  }
 
344
 
 
345
  return DRIZZLE_RETURN_OK;
 
346
}