Drizzled Public API Documentation

pack.cc
Go to the documentation of this file.
00001 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00002  *
00003  * Drizzle Client & Protocol Library
00004  *
00005  * Copyright (C) 2008 Eric Day (eday@oddments.org)
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are
00010  * met:
00011  *
00012  *     * Redistributions of source code must retain the above copyright
00013  * notice, this list of conditions and the following disclaimer.
00014  *
00015  *     * Redistributions in binary form must reproduce the above
00016  * copyright notice, this list of conditions and the following disclaimer
00017  * in the documentation and/or other materials provided with the
00018  * distribution.
00019  *
00020  *     * The names of its contributors may not be used to endorse or
00021  * promote products derived from this software without specific prior
00022  * written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00027  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  */
00037 
00043 #include <libdrizzle/common.h>
00044 
00045 /*
00046  * Private declarations
00047  */
00048 
00058 static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
00059                                             uint8_t *buffer);
00060 
00063 /*
00064  * Public definitions
00065  */
00066 
00067 uint8_t *drizzle_pack_length(uint64_t number, uint8_t *ptr)
00068 {
00069   if (number < 251)
00070   {
00071     ptr[0]= (uint8_t)number;
00072     ptr++;
00073   }
00074   else if (number < 65536)
00075   {
00076     ptr[0]= 252;
00077     ptr++;
00078     drizzle_set_byte2(ptr, number);
00079     ptr+= 2;
00080   }
00081   else if (number < 16777216)
00082   {
00083     ptr[0]= 253;
00084     ptr++;
00085     drizzle_set_byte3(ptr, number);
00086     ptr+= 3;
00087   }
00088   else
00089   {
00090     ptr[0]= 254;
00091     ptr++;
00092     drizzle_set_byte8(ptr, number);
00093     ptr+= 8;
00094   }
00095 
00096   return ptr;
00097 }
00098 
00099 uint64_t drizzle_unpack_length(drizzle_con_st *con, drizzle_return_t *ret_ptr)
00100 {
00101   uint64_t length;
00102   uint8_t bytes;
00103 
00104   drizzle_return_t unused_ret;
00105   if (ret_ptr == NULL)
00106   {
00107     ret_ptr= &unused_ret;
00108   }
00109 
00110   if (con == NULL)
00111   {
00112     *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
00113     return 0;
00114   }
00115 
00116   if (con->buffer_ptr[0] < 251)
00117   {
00118     length= (uint64_t)(con->buffer_ptr[0]);
00119     bytes= 1;
00120   }
00121   else if (con->buffer_ptr[0] == 251)
00122   {
00123     con->buffer_ptr++;
00124     con->buffer_size--;
00125     con->packet_size--;
00126 
00127     *ret_ptr= DRIZZLE_RETURN_NULL_SIZE;
00128     return 0;
00129   }
00130   else if (con->buffer_ptr[0] == 252 && con->buffer_size > 2)
00131   {
00132     length= drizzle_get_byte2(con->buffer_ptr + 1);
00133     bytes= 3;
00134   }
00135   else if (con->buffer_ptr[0] == 253 && con->buffer_size > 3)
00136   {
00137     length= drizzle_get_byte3(con->buffer_ptr + 1);
00138     bytes= 4;
00139   }
00140   else if (con->buffer_size > 8)
00141   {
00142     length= drizzle_get_byte8(con->buffer_ptr + 1);
00143     bytes= 9;
00144   }
00145   else
00146   {
00147     *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
00148     return 0;
00149   }
00150 
00151   con->buffer_ptr+= bytes;
00152   con->buffer_size-= bytes;
00153   con->packet_size-= bytes;
00154 
00155   *ret_ptr= DRIZZLE_RETURN_OK;
00156   return length;
00157 }
00158 
00159 uint8_t *drizzle_pack_string(char *string, uint8_t *ptr)
00160 {
00161   if (string == NULL)
00162   {
00163     return NULL;
00164   }
00165 
00166   uint64_t size= strlen(string);
00167 
00168   ptr= drizzle_pack_length(size, ptr);
00169   if (size > 0)
00170   {
00171     memcpy(ptr, string, (size_t)size);
00172     ptr+= size;
00173   }
00174 
00175   return ptr;
00176 }
00177 
00178 drizzle_return_t drizzle_unpack_string(drizzle_con_st *con, char *buffer,
00179                                        uint64_t max_length)
00180 {
00181   drizzle_return_t ret= DRIZZLE_RETURN_OK;
00182 
00183   if (con == NULL)
00184   {
00185     return DRIZZLE_RETURN_INVALID_ARGUMENT;
00186   }
00187 
00188   uint64_t length= drizzle_unpack_length(con, &ret);
00189   if (ret != DRIZZLE_RETURN_OK)
00190   {
00191     if (ret == DRIZZLE_RETURN_NULL_SIZE)
00192     {
00193       drizzle_set_error(con->drizzle, "drizzle_unpack_string",
00194                         "unexpected NULL length");
00195     }
00196 
00197     return ret;
00198   }
00199 
00200   if (length < max_length)
00201   {
00202     if (length > 0)
00203       memcpy(buffer, con->buffer_ptr, (size_t)length);
00204 
00205     buffer[length]= 0;
00206   }
00207   else
00208   {
00209     memcpy(buffer, con->buffer_ptr, (size_t)(max_length - 1));
00210     buffer[max_length - 1]= 0;
00211   }
00212   
00213   con->buffer_ptr+= length;
00214   con->buffer_size-= (size_t)length;
00215   con->packet_size-= (size_t)length;
00216 
00217   return DRIZZLE_RETURN_OK;
00218 }
00219 
00220 uint8_t *drizzle_pack_auth(drizzle_con_st *con, uint8_t *ptr,
00221                            drizzle_return_t *ret_ptr)
00222 {
00223   drizzle_return_t unused_ret;
00224   if (ret_ptr == NULL)
00225   {
00226     ret_ptr= &unused_ret;
00227   }
00228 
00229   if (con == NULL)
00230   {
00231     *ret_ptr= DRIZZLE_RETURN_INVALID_ARGUMENT;
00232     return NULL;
00233   }
00234 
00235   if (con->user[0] != 0)
00236   {
00237     memcpy(ptr, con->user, strlen(con->user));
00238     ptr+= strlen(con->user);
00239   }
00240 
00241   ptr[0]= 0;
00242   ptr++;
00243 
00244   if (con->options & DRIZZLE_CON_RAW_SCRAMBLE && con->scramble != NULL)
00245   {
00246     ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
00247     ptr++;
00248 
00249     memcpy(ptr, con->scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
00250     ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
00251   }
00252   else if (con->password[0] == 0)
00253   {
00254     ptr[0]= 0;
00255     ptr++;
00256     con->packet_size-= DRIZZLE_MAX_SCRAMBLE_SIZE;
00257   }
00258   else
00259   {
00260     ptr[0]= DRIZZLE_MAX_SCRAMBLE_SIZE;
00261     ptr++;
00262 
00263     if (con->options & DRIZZLE_CON_MYSQL && con->options & DRIZZLE_CON_AUTH_PLUGIN)
00264     {
00265       snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
00266       ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
00267     }
00268     else if (con->options & DRIZZLE_CON_MYSQL)
00269     {
00270       *ret_ptr= _pack_scramble_hash(con, ptr);
00271       if (*ret_ptr != DRIZZLE_RETURN_OK)
00272         return ptr;
00273     }
00274     else // We assume Drizzle
00275     {
00276       snprintf((char *)ptr, DRIZZLE_MAX_SCRAMBLE_SIZE, "%s", con->password);
00277       ptr[DRIZZLE_MAX_SCRAMBLE_SIZE-1]= 0;
00278     }
00279 
00280     ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
00281   }
00282 
00283   if (con->db[0] != 0)
00284   {
00285     memcpy(ptr, con->db, strlen(con->db));
00286     ptr+= strlen(con->db);
00287   }
00288 
00289   ptr[0]= 0;
00290   ptr++;
00291 
00292   *ret_ptr= DRIZZLE_RETURN_OK;
00293   return ptr;
00294 }
00295 
00296 /*
00297  * Private definitions
00298  */
00299 
00300 static drizzle_return_t _pack_scramble_hash(drizzle_con_st *con,
00301                                             uint8_t *buffer)
00302 {
00303   SHA1_CTX ctx;
00304   uint8_t hash_tmp1[SHA1_DIGEST_LENGTH];
00305   uint8_t hash_tmp2[SHA1_DIGEST_LENGTH];
00306 
00307   if (SHA1_DIGEST_LENGTH != DRIZZLE_MAX_SCRAMBLE_SIZE)
00308   {
00309     drizzle_set_error(con->drizzle, "_pack_scramble_hash",
00310                       "SHA1 hash size mismatch:%u:%u", SHA1_DIGEST_LENGTH,
00311                       DRIZZLE_MAX_SCRAMBLE_SIZE);
00312     return DRIZZLE_RETURN_INTERNAL_ERROR;
00313   }
00314 
00315   if (con->scramble == NULL)
00316   {
00317     drizzle_set_error(con->drizzle, "_pack_scramble_hash",
00318                       "no scramble buffer");
00319     return DRIZZLE_RETURN_NO_SCRAMBLE;
00320   }
00321 
00322   /* First hash the password. */
00323   SHA1Init(&ctx);
00324   SHA1Update(&ctx, (uint8_t *)(con->password), strlen(con->password));
00325   SHA1Final(hash_tmp1, &ctx);
00326 
00327   /* Second, hash the password hash. */
00328   SHA1Init(&ctx);
00329   SHA1Update(&ctx, hash_tmp1, SHA1_DIGEST_LENGTH);
00330   SHA1Final(hash_tmp2, &ctx);
00331 
00332   /* Third, hash the scramble and the double password hash. */
00333   SHA1Init(&ctx);
00334   SHA1Update(&ctx, con->scramble, SHA1_DIGEST_LENGTH);
00335   SHA1Update(&ctx, hash_tmp2, SHA1_DIGEST_LENGTH);
00336   SHA1Final(buffer, &ctx);
00337 
00338   /* Fourth, xor the last hash against the first password hash. */
00339   uint32_t x;
00340   for (uint32_t x= 0; x < SHA1_DIGEST_LENGTH; x++)
00341   {
00342     buffer[x]= buffer[x] ^ hash_tmp1[x];
00343   }
00344 
00345   return DRIZZLE_RETURN_OK;
00346 }