libdrizzle Developer Documentation

libdrizzle/pack.c
Go to the documentation of this file.
00001 /*
00002  * Drizzle Client & Protocol Library
00003  *
00004  * Copyright (C) 2008 Eric Day (eday@oddments.org)
00005  * All rights reserved.
00006  *
00007  * Use and distribution licensed under the BSD license.  See
00008  * the COPYING file in this directory for full text.
00009  */
00010 
00016 #include "common.h"
00017 
00018 /*
00019  * Private declarations
00020  */
00021 
00031 static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
00032                                             uint8_t *buffer);
00033 
00036 /*
00037  * Public definitions
00038  */
00039 
00040 uint8_t *drizzle_pack_length(uint64_t number, uint8_t *ptr)
00041 {
00042   if (number < 251)
00043   {
00044     ptr[0]= (uint8_t)number;
00045     ptr++;
00046   }
00047   else if (number < 65536)
00048   {
00049     ptr[0]= 252;
00050     ptr++;
00051     drizzle_set_byte2(ptr, number);
00052     ptr+= 2;
00053   }
00054   else if (number < 16777216)
00055   {
00056     ptr[0]= 253;
00057     ptr++;
00058     drizzle_set_byte3(ptr, number);
00059     ptr+= 3;
00060   }
00061   else
00062   {
00063     ptr[0]= 254;
00064     ptr++;
00065     drizzle_set_byte8(ptr, number);
00066     ptr+= 8;
00067   }
00068 
00069   return ptr;
00070 }
00071 
00072 uint64_t drizzle_unpack_length(drizzle_con_st *con, drizzle_return_t *ret_ptr)
00073 {
00074   uint64_t length;
00075   uint8_t bytes;
00076 
00077   if (con->buffer_ptr[0] < 251)
00078   {
00079     length= (uint64_t)(con->buffer_ptr[0]);
00080     bytes= 1;
00081   }
00082   else if (con->buffer_ptr[0] == 251)
00083   {
00084     con->buffer_ptr++;
00085     con->buffer_size--;
00086     con->packet_size--;
00087 
00088     *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
00089     return 0;
00090   }
00091   else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
00092   {
00093     length= drizzle_get_byte2(con->buffer_ptr + 1);
00094     bytes= 3;
00095   }
00096   else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
00097   {
00098     length= drizzle_get_byte3(con->buffer_ptr + 1);
00099     bytes= 4;
00100   }
00101   else if (con->buffer_size > 8)
00102   {
00103     length= drizzle_get_byte8(con->buffer_ptr + 1);
00104     bytes= 9;
00105   }
00106   else
00107   {
00108     *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
00109     return 0;
00110   }
00111 
00112   con->buffer_ptr+= bytes;
00113   con->buffer_size-= bytes;
00114   con->packet_size-= bytes;
00115 
00116   *ret_ptr= DRIZZLE_RETURN_OK;
00117   return length;
00118 }
00119 
00120 uint8_t *drizzle_pack_string(char *string, uint8_t *ptr)
00121 {
00122   uint64_t size= strlen(string);
00123 
00124   ptr= drizzle_pack_length(size, ptr);
00125   if (size > 0)
00126   {
00127     memcpy(ptr, string, (size_t)size);
00128     ptr+= size;
00129   }
00130 
00131   return ptr;
00132 }
00133 
00134 drizzle_return_t drizzle_unpack_string(drizzle_con_st *con, char *buffer,
00135                                        uint64_t max_length)
00136 {
00137   drizzle_return_t ret= DRIZZLE_RETURN_OK;
00138   uint64_t length;
00139 
00140   length= drizzle_unpack_length(con, &ret);
00141   if (ret != DRIZZLE_RETURN_OK)
00142   {
00143     if (ret == DRIZZLE_RETURN_NULL_SIZE)
00144     {
00145       drizzle_set_error(con->drizzle, "drizzle_unpack_string",
00146                         "unexpected NULL length");
00147     }
00148 
00149     return ret;
00150   }
00151 
00152   if (length < max_length)
00153   {
00154     if (length > 0)
00155       memcpy(buffer, con->buffer_ptr, (size_t)length);
00156 
00157     buffer[length]= 0;
00158   }
00159   else
00160   {
00161     memcpy(buffer, con->buffer_ptr, (size_t)(max_length - 1));
00162     buffer[max_length - 1]= 0;
00163   }
00164   
00165   con->buffer_ptr+= length;
00166   con->buffer_size-= (size_t)length;
00167   con->packet_size-= (size_t)length;
00168 
00169   return DRIZZLE_RETURN_OK;
00170 }
00171 
00172 uint8_t *drizzle_pack_auth(drizzle_con_st *con, uint8_t *ptr,
00173                            drizzle_return_t *ret_ptr)
00174 {
00175   if (con->user[0] != 0)
00176   {
00177     memcpy(ptr, con->user, strlen(con->user));
00178     ptr+= strlen(con->user);
00179   }
00180 
00181   ptr[0]= 0;
00182   ptr++;
00183 
00184   if (con->options & DRIZZLE_CON_RAW_SCRAMBLE && con->scramble != NULL)
00185   {
00186     ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
00187     ptr++;
00188 
00189     memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
00190     ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
00191   }
00192   else if (con->password[0] == 0)
00193   {
00194     ptr[0]= 0;
00195     ptr++;
00196     con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
00197   }
00198   else
00199   {
00200     ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
00201     ptr++;
00202 
00203     if (con->options & DRIZZLE_CON_MYSQL)
00204     {
00205       *ret_ptr= _pack_scramble_hash(con, ptr);
00206       if (*ret_ptr != DRIZZLE_RETURN_OK)
00207         return ptr;
00208     }
00209     else
00210       snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
00211 
00212     ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
00213   }
00214 
00215   if (con->db[0] != 0)
00216   {
00217     memcpy(ptr, con->db, strlen(con->db));
00218     ptr+= strlen(con->db);
00219   }
00220 
00221   ptr[0]= 0;
00222   ptr++;
00223 
00224   *ret_ptr= DRIZZLE_RETURN_OK;
00225   return ptr;
00226 }
00227 
00228 /*
00229  * Private definitions
00230  */
00231 
00232 static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
00233                                             uint8_t *buffer)
00234 {
00235   SHA1_CTX ctx;
00236   uint8_t hash_tmp1[SHA1_DIGEST_LENGTH];
00237   uint8_t hash_tmp2[SHA1_DIGEST_LENGTH];
00238   uint32_t x;
00239 
00240   if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
00241   {
00242     drizzle_set_error(con->drizzle, "_pack_scramble_hash",
00243                       "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
00244                       DRIZZLE_MAX_SCRAMBLE_SIZE);
00245     return DRIZZLE_RETURN_INTERNAL_ERROR;
00246   }
00247 
00248   if (con->scramble == NULL)
00249   {
00250     drizzle_set_error(con->drizzle, "_pack_scramble_hash",
00251                       "no scramble buffer");
00252     return DRIZZLE_RETURN_NO_SCRAMBLE;
00253   }
00254 
00255   /* First hash the password. */
00256   SHA1Init(&ctx);
00257   SHA1Update(&ctx, (uint8_t *)(con->password), strlen(con->password));
00258   SHA1Final(hash_tmp1, &ctx);
00259 
00260   /* Second, hash the password hash. */
00261   SHA1Init(&ctx);
00262   SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
00263   SHA1Final(hash_tmp2, &ctx);
00264 
00265   /* Third, hash the scramble and the double password hash. */
00266   SHA1Init(&ctx);
00267   SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
00268   SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
00269   SHA1Final(buffer, &ctx);
00270 
00271   /* Fourth, xor the last hash against the first password hash. */
00272   for (x= 0; x < SHA1_DIGEST_LENGTH; x++)
00273     buffer[x]= buffer[x] ^ hash_tmp1[x];
00274 
00275   return DRIZZLE_RETURN_OK;
00276 }