session.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  */
00008 
00009 #include "klone_conf.h"
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <sys/time.h>
00013 #include <stdlib.h>
00014 #include <time.h>
00015 #include <ctype.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #ifdef SSL_ON
00019 #include <openssl/evp.h>
00020 #include <openssl/hmac.h>
00021 #include <openssl/rand.h>
00022 #include <klone/ccipher.h>
00023 #endif 
00024 #include <u/libu.h>
00025 #include <klone/session.h>
00026 #include <klone/request.h>
00027 #include <klone/response.h>
00028 #include <klone/vars.h>
00029 #include <klone/utils.h>
00030 #include <klone/ses_prv.h>
00031 #include <klone/codecs.h>
00032 
00033 enum { DEFAULT_SESSION_EXPIRATION = 60*20 }; /* 20 minutes */
00034 static const char SID_NAME[] = "klone_sid";
00035 
00036 
00037 struct save_cb_params_s
00038 {
00039     session_t *ss;
00040     io_t *io;
00041 };
00042 
00043 typedef struct save_cb_params_s save_cb_params_t;
00044 
00045 int session_module_term(session_opt_t *so)
00046 {
00047     U_FREE(so);
00048 
00049     return 0;
00050 }
00051 
00052 int session_module_init(u_config_t *config, session_opt_t **pso)
00053 {
00054     int iv;
00055     session_opt_t *so = NULL;
00056     u_config_t *c = NULL;
00057     const char *v;
00058 
00059     dbg_err_if (config == NULL);
00060     dbg_err_if (pso == NULL);
00061 
00062     dbg_err_sif ((so = u_zalloc(sizeof(session_opt_t))) == NULL);
00063 
00064     /* defaults values */
00065     so->type = SESSION_TYPE_FILE;
00066     so->max_age = DEFAULT_SESSION_EXPIRATION;
00067     so->compress = 0;
00068     so->encrypt = 0;
00069     (void) u_strlcpy(so->name, SID_NAME, sizeof so->name);
00070 
00071     /* In case no 'session' subsection is found, defaults will be used. */
00072 
00073     if(!u_config_get_subkey(config, "session", &c))
00074     {
00075         /* set session type */
00076         if((v = u_config_get_subkey_value(c, "type")) != NULL)
00077         {
00078             if(!strcasecmp(v, "memory"))
00079                 so->type = SESSION_TYPE_MEMORY;
00080             else if(!strcasecmp(v, "file"))
00081                 so->type = SESSION_TYPE_FILE;
00082 #ifdef SSL_ON
00083             else if(!strcasecmp(v, "client"))
00084                 so->type = SESSION_TYPE_CLIENT;
00085 #endif
00086             else
00087                warn_err("config error: bad session type \'%s\'", v);
00088         }
00089 
00090         /* set max_age */
00091         if((v = u_config_get_subkey_value(c, "max_age")) != NULL)
00092         {
00093             dbg_err_ifm (u_atoi(v, &iv), "config error: bad max_age \'%s\'", v);
00094             so->max_age = U_MAX(iv * 60, 60); /* silently uplift to 1 min */
00095         }
00096 
00097         /* set compression flag */
00098         dbg_err_if(u_config_get_subkey_value_b(c, "compress", 0,
00099             &so->compress));
00100 
00101         /* set encryption flag */
00102         dbg_err_if(u_config_get_subkey_value_b(c, "encrypt", 0, &so->encrypt));
00103 
00104         /* set cookie name */
00105         if ((v = u_config_get_subkey_value(c, "sid_name")) != NULL)
00106             dbg_err_if (u_strlcpy(so->name, v, sizeof so->name));
00107 
00108 #ifndef HAVE_LIBZ
00109         if(so->compress)
00110             warn_err("config error: compression is enabled but libz is not "
00111                      "linked");
00112 #endif
00113 
00114 #ifndef SSL_ON
00115         if(so->encrypt)
00116             warn_err("config error: encryption is enabled but no SSL "
00117                      "lib is linked");
00118 #else
00119 
00120 #ifdef SSL_OPENSSL
00121         /* init cipher EVP algo, the random key and IV */
00122         so->cipher = EVP_aes_256_cbc(); /* use AES-256 in CBC mode */
00123 
00124         EVP_add_cipher(so->cipher);
00125 
00126         /* key and iv for client-side session */
00127         dbg_err_if(!RAND_bytes(so->cipher_key, CIPHER_KEY_LEN));
00128         dbg_err_if(!RAND_pseudo_bytes(so->cipher_iv, CIPHER_IV_LEN));
00129 
00130         /* create a random key and iv to crypt the SESSION_KEY_VAR variable */
00131         dbg_err_if(!RAND_bytes(so->session_key, CIPHER_KEY_LEN));
00132         dbg_err_if(!RAND_pseudo_bytes(so->session_iv, CIPHER_IV_LEN));
00133 #endif
00134 
00135 #ifdef SSL_CYASSL
00136         /* init cipher EVP algo, the random key and IV */
00137         so->cipher = EVP_aes_256_cbc(); /* use AES-256 in CBC mode */
00138 
00139         /* key and iv for client-side session */
00140         dbg_err_if(!RAND_bytes(so->cipher_key, CIPHER_KEY_LEN));
00141         dbg_err_if(!RAND_bytes(so->cipher_iv, CIPHER_IV_LEN));
00142 
00143         /* create a random key and iv to crypt the SESSION_KEY_VAR variable */
00144         dbg_err_if(!RAND_bytes(so->session_key, CIPHER_KEY_LEN));
00145         dbg_err_if(!RAND_bytes(so->session_iv, CIPHER_IV_LEN));
00146 #endif
00147 
00148 #endif
00149     } /* if "session" exists */
00150 
00151     /* per-type configuration init */
00152     if(so->type == SESSION_TYPE_MEMORY)
00153         warn_err_ifm(session_mem_module_init(c, so), 
00154             "in-memory session engine init error");
00155     else if(so->type == SESSION_TYPE_FILE)
00156         warn_err_ifm(session_file_module_init(c, so), 
00157             "file session engine init error");
00158 #ifdef SSL_ON
00159     else if(so->type == SESSION_TYPE_CLIENT)
00160         warn_err_ifm(session_client_module_init(c, so),
00161             "client-side session engine init error");
00162 #endif
00163 
00164     *pso = so;
00165 
00166     return 0;
00167 err:
00168     u_free(so);
00169     return ~0;
00170 }
00171 
00172 int session_prv_calc_maxsize(var_t *v, void *p)
00173 {
00174     const char *value = NULL;
00175     size_t *psz = (size_t*)p;
00176 
00177     dbg_err_if (v == NULL);
00178     dbg_err_if (var_get_name(v) == NULL);
00179     dbg_err_if (psz == NULL);
00180 
00181 #ifdef SSL_ON
00182     if(*psz == 0)
00183     {   /* a block plus the padding block */
00184         *psz = CODEC_CIPHER_BLOCK_LEN * 2;
00185     }
00186 #endif
00187 
00188     /* name= */
00189     *psz += 3 * strlen(var_get_name(v)) + 3;
00190 
00191     /* value */
00192     if((value = var_get_value(v)) != NULL)
00193         *psz += 3 * strlen(value) + 1; /* worse case (i.e. longest string) */
00194 
00195     return 0;
00196 err:
00197     return ~0;
00198 }
00199 
00200 int session_prv_load_from_buf(session_t *ss, char *buf, size_t size)
00201 {
00202     io_t *io = NULL;
00203 
00204     dbg_err_if (ss == NULL);
00205     dbg_err_if (buf == NULL);
00206 
00207     /* build an io_t around the buffer */
00208     dbg_err_if(io_mem_create(buf, size, 0, &io));
00209 
00210     /* load data */
00211     dbg_err_if(session_prv_load_from_io(ss, io));
00212 
00213     io_free(io);
00214 
00215     return 0;
00216 err:
00217     if(io)
00218         io_free(io);
00219     return ~0;
00220 }
00221 
00222 int session_prv_save_to_buf(session_t *ss, char **pbuf, size_t *psz)
00223 {
00224     io_t *io = NULL;
00225     char *buf = NULL;
00226     size_t sz = 0;
00227 
00228     dbg_err_if (ss == NULL);
00229     dbg_err_if (pbuf == NULL);
00230     dbg_err_if (psz == NULL);
00231  
00232     /* calc the maximum session data size (exact calc requires url encoding and
00233        codec transformation knowledge) */
00234     vars_foreach(ss->vars, session_prv_calc_maxsize, (void*)&sz);
00235 
00236     /* alloc a big-enough block to save the session data */
00237     buf = u_malloc(sz);
00238     dbg_err_if(buf == NULL);
00239 
00240     /* create a big-enough in-memory io object */
00241     dbg_err_if(io_mem_create(buf, sz, 0, &io));
00242 
00243     /* save the session to the in-memory io */
00244     dbg_err_if(session_prv_save_to_io(ss, io));
00245 
00246     /* remove all codecs to get the right size of 'buf'. we need to remove 
00247        the codecs because some of them buffer data until last codec->flush() 
00248        is called (and it's not possible to flush codecs without removing them */
00249     dbg_err_if(io_codecs_remove(io));
00250 
00251     /* get the number of bytes written to the io (so to 'buf') */
00252     sz = io_tell(io);
00253 
00254     io_free(io);
00255     io = NULL;
00256 
00257     *pbuf = buf;
00258     *psz = sz;
00259 
00260     return 0;
00261 err:
00262     if(io)
00263         io_free(io);
00264     U_FREE(buf);
00265     return ~0;
00266 }
00267 
00268 /* Supplied 'id' must be SESSION_ID_LENGTH long and made of hex digits only. */
00269 static int session_is_good_id(const char *id)
00270 {
00271     const char *p;
00272 
00273     dbg_return_if (id == NULL, 0);
00274     dbg_return_if (strlen(id) != SESSION_ID_LENGTH, 0);
00275 
00276     for (p = id; *p != '\0'; ++p)
00277     {
00278         if (!isxdigit(*p))
00279             return 0;
00280     }
00281 
00282     return 1; /* good */
00283 }
00284 
00285 static int session_set_filename(session_t *ss)
00286 {
00287     const char *a = NULL;
00288 
00289     dbg_return_if (ss->id[0] == '\0', ~0);
00290 
00291     dbg_err_if((a = request_get_addr(ss->rq)) == NULL);
00292 
00293     dbg_err_if(u_path_snprintf(ss->filename, U_FILENAME_MAX, 
00294             U_PATH_SEPARATOR, "%s/klone_sess_%s_%s", ss->so->path, ss->id, a));
00295 
00296     return 0;
00297 err:
00298     return ~0;
00299 }
00300 
00301 static int session_gen_id(session_t *ss)
00302 {
00303     char buf[256 + 1];  /* handle worst case, i.e. (64bit * 4) + '\0' */
00304     struct timeval tv;
00305 
00306     dbg_err_if (ss == NULL);
00307 
00308     /* Initialize sid to empty string. */
00309     ss->id[0] = '\0';
00310 
00311     /* SID is MD5(mix(now, process_pid, random)) */
00312     dbg_err_sif (gettimeofday(&tv, NULL) == -1);
00313 
00314     dbg_err_if (u_snprintf(buf, sizeof buf, "%lu%u%lu%d", 
00315                 (unsigned long) tv.tv_sec, (unsigned int) getpid(), 
00316                 (unsigned long) tv.tv_usec, rand()));
00317 
00318     dbg_err_if (u_md5(buf, strlen(buf), ss->id));
00319 
00320     /* Remove previous SID, if any. */ 
00321     dbg_err_if (response_set_cookie(ss->rs, ss->so->name, NULL, 
00322                 0, NULL, NULL, 0));
00323 
00324     /* Set the cookie ID. */
00325     dbg_err_if (response_set_cookie(ss->rs, ss->so->name, ss->id, 
00326                 0, NULL, NULL, 0));
00327 
00328     return 0;
00329 err:
00330     return ~0;
00331 }
00332 
00333 int session_prv_set_id(session_t *ss, const char *sid)
00334 {
00335     dbg_return_if (ss == NULL, ~0);
00336 
00337     /* set or generate a session id */
00338     if (sid && session_is_good_id(sid))
00339         dbg_err_if (u_snprintf(ss->id, sizeof ss->id, "%s", sid));
00340     else
00341         dbg_err_if (session_gen_id(ss));
00342 
00343     /* set the filename accordingly */
00344     dbg_err_if (session_set_filename(ss));
00345 
00346     return 0;
00347 err:
00348     return ~0;
00349 }
00350 
00351 int session_priv_set_id(session_t *ss, const char *sid)
00352 {
00353     return session_prv_set_id(ss, sid); /* backward compatibility */
00354 }
00355 
00356 int session_load(session_t *ss)
00357 {
00358     dbg_return_if (ss == NULL, ~0);
00359     dbg_return_if (ss->load == NULL, ~0);
00360 
00361     return ss->load(ss);
00362 }
00363 
00364 int session_save(session_t *ss)
00365 {
00366     dbg_return_if (ss == NULL, ~0);
00367     dbg_return_if (ss->save == NULL, ~0);
00368 
00369     /* No vars set: if cookie empty it's a no-op, otherwise remove stored
00370      * cookies. */
00371     if (vars_count(ss->vars) == 0)
00372         return (ss->id[0] == '\0') ? 0 : session_remove(ss);
00373 
00374     /* new user, need to save some vars */
00375     if (ss->id[0] == '\0')
00376     {
00377         /* generate a new SID and set session filename accordingly */
00378         dbg_err_if (session_prv_set_id(ss, NULL)); 
00379     }
00380 
00381     return ss->save(ss);
00382 err:
00383     return ~0;
00384 }
00385 
00386 int session_remove(session_t *ss)
00387 {
00388     dbg_return_if (ss == NULL, ~0);
00389     dbg_return_if (ss->remove == NULL, ~0);
00390 
00391     /* remove the cookie */
00392     response_set_cookie(ss->rs, ss->so->name, NULL, 0, NULL, NULL, 0);
00393 
00394     ss->removed = 1;
00395 
00396     return ss->remove(ss);
00397 }
00398 
00399 int session_prv_init(session_t *ss, request_t *rq, response_t *rs)
00400 {
00401     const char *sid;
00402 
00403     dbg_err_if (ss == NULL);
00404     dbg_err_if (rq == NULL);
00405     dbg_err_if (rs == NULL);
00406     
00407     dbg_err_if(vars_create(&ss->vars));
00408 
00409     ss->rq = rq;
00410     ss->rs = rs;
00411 
00412     /* if the client has a SID set and it's a good one then use it */
00413     sid = request_get_cookie(ss->rq, ss->so->name);
00414     if(sid)
00415         dbg_err_if(session_prv_set_id(ss, sid));
00416 
00417     return 0;
00418 err:
00419     return ~0;
00420 }
00421 
00422 int session_prv_load_from_io(session_t *ss, io_t *io)
00423 {
00424     u_string_t *line = NULL;
00425     var_t *v = NULL;
00426     codec_t *unzip = NULL, *decrypt = NULL;
00427     unsigned char key[CODEC_CIPHER_KEY_BUFSZ];
00428     size_t ksz;
00429 
00430     dbg_return_if (ss == NULL, ~0);
00431     dbg_return_if (io == NULL, ~0);
00432 
00433 #ifdef SSL_ON
00434     if(ss->so->encrypt)
00435     {
00436         dbg_err_if(codec_cipher_create(CIPHER_DECRYPT, ss->so->cipher, 
00437             ss->so->cipher_key, ss->so->cipher_iv, &decrypt)); 
00438         dbg_err_if(io_codec_add_tail(io, decrypt));
00439         decrypt = NULL; /* io_t owns it after io_codec_add_tail */
00440     }
00441 #else
00442     u_unused_args(key, ksz);
00443 #endif
00444 
00445 #ifdef HAVE_LIBZ
00446     if(ss->so->compress)
00447     {
00448         dbg_err_if(codec_gzip_create(GZIP_UNCOMPRESS, &unzip));
00449         dbg_err_if(io_codec_add_tail(io, unzip));
00450         unzip = NULL; /* io_t owns it after io_codec_add_tail */
00451     }
00452 #endif
00453 
00454     dbg_err_if(u_string_create(NULL, 0, &line));
00455 
00456     while(u_getline(io, line) == 0)
00457     {
00458         if(u_string_len(line))
00459         {
00460             dbg_err_if(vars_add_urlvar(ss->vars, u_string_c(line), &v));
00461 
00462 #ifdef SSL_ON
00463             if(!strcmp(var_get_name(v), SESSION_KEY_VAR))
00464             {
00465                 /* decrypt key and save it to key */
00466                 memset(key, 0, sizeof(key));
00467                                 ksz = sizeof(key);
00468                 dbg_ifb(u_cipher_decrypt(EVP_aes_256_cbc(), ss->so->session_key,
00469                     ss->so->session_iv, key, &ksz, 
00470                     var_get_value(v), var_get_value_size(v)))
00471                 {
00472                     v = vars_get(ss->vars, SESSION_KEY_VAR);
00473                     vars_del(ss->vars, v);
00474                 } else {
00475                     /* save it to the var list */
00476                     dbg_err_if(var_set_bin_value(v, key, ksz));
00477                 }
00478 
00479             }
00480 #endif
00481         }
00482     }
00483 
00484     /* remove set codecs and flush */
00485     io_codecs_remove(io);
00486 
00487     u_string_free(line);
00488 
00489     return 0;
00490 err:
00491     if(io)
00492         io_codecs_remove(io);
00493     if(decrypt)
00494         codec_free(decrypt);
00495     if(unzip)
00496         codec_free(unzip);
00497     if(line)
00498         u_string_free(line);
00499     return ~0;
00500 }
00501 
00502 int session_free(session_t *ss)
00503 {
00504     if (ss)
00505     { 
00506         if(!ss->removed)
00507             dbg_if(session_save(ss));
00508 
00509         /* driver cleanup */
00510         dbg_if(ss->term(ss));
00511 
00512         if(ss->vars)
00513             vars_free(ss->vars);
00514 
00515         U_FREE(ss);
00516     }
00517 
00518     return 0;
00519 }
00520 
00531 vars_t *session_get_vars(session_t *ss)
00532 {
00533     dbg_return_if (ss == NULL, NULL);
00534 
00535     return ss->vars;
00536 }
00537 
00550 const char *session_get(session_t *ss, const char *name)
00551 {
00552     var_t *v;
00553 
00554     dbg_return_if (ss == NULL, NULL);
00555     dbg_return_if (name == NULL, NULL);
00556     
00557     v = vars_get(ss->vars, name);
00558     return v ? var_get_value(v): NULL;
00559 }
00560 
00571 const char *session_get_id (session_t *ss)
00572 {
00573     dbg_return_if (ss == NULL, NULL);
00574 
00575     return ss->id;
00576 }
00577 
00590 int session_set(session_t *ss, const char *name, const char *value)
00591 {
00592     var_t *v = NULL;
00593 
00594     dbg_err_if (ss == NULL);
00595     dbg_err_if (name == NULL);
00596     dbg_err_if (value == NULL);
00597     dbg_err_if (strlen(name) == 0);
00598 
00599     if((v = vars_get(ss->vars, name)) == NULL)
00600     {
00601         /* add a new session variable */
00602         dbg_err_if(var_create(name, value, &v));
00603 
00604         dbg_err_if(vars_add(ss->vars, v));
00605     } else {
00606         /* update an existing var */
00607         dbg_ifb(var_set_value(v, value))
00608             return ~0;
00609     }
00610 
00611     return 0;
00612 err:
00613     if(v)
00614         var_free(v);
00615     return ~0;
00616 }
00617 
00630 int session_age(session_t *ss)
00631 {
00632     time_t now;
00633 
00634     dbg_return_if (ss == NULL, -1);
00635 
00636     now = time(0);
00637 
00638     /* ss->mtime must has been set into session_X_create funcs */
00639     return (int)(now - ss->mtime); /* in seconds */
00640 }
00641 
00652 int session_clean(session_t *ss)
00653 {
00654     var_t *v = NULL;
00655 
00656     dbg_err_if (ss == NULL);
00657 
00658     while((v = vars_getn(ss->vars, 0)) != NULL)
00659     {
00660         dbg_err_if(vars_del(ss->vars, v));
00661         var_free(v);
00662     }
00663 
00664     return 0;
00665 err:
00666     return ~0;
00667 }
00668 
00682 int session_del(session_t *ss, const char *name)
00683 {
00684     var_t *v = NULL;
00685 
00686     dbg_err_if (ss == NULL);
00687     dbg_err_if (name == NULL);
00688     
00689     dbg_err_if((v = vars_get(ss->vars, name)) == NULL);
00690     dbg_err_if(vars_del(ss->vars, v));
00691     var_free(v);
00692 
00693     return 0;
00694 err:
00695     return ~0;
00696 }
00697 
00698 #ifdef SSL_ON
00699 
00718 int session_set_cipher_key(session_t *ss, const char *data, size_t sz)
00719 {
00720     var_t *v = NULL;
00721 
00722     dbg_err_if(ss == NULL);
00723     dbg_err_if(ss->vars == NULL);
00724     dbg_err_if(data == NULL);
00725     dbg_err_if(sz == 0);
00726 
00727     /* remove the old key if it has been set */
00728     if((v = vars_get(ss->vars, SESSION_KEY_VAR)) != NULL)
00729     {
00730         dbg_err_if(vars_del(ss->vars, v));
00731         v = NULL;
00732     }
00733 
00734     /* may contain \0 values; treat it as opaque binary data */
00735     dbg_err_if(var_bin_create(SESSION_KEY_VAR, data, sz, &v));
00736 
00737     dbg_err_if(vars_add(ss->vars, v));
00738     v = NULL;
00739 
00740     return 0;
00741 err:
00742     if(v)
00743         var_free(v);
00744     return ~0;
00745 }
00746 
00765 int session_get_cipher_key(session_t *ss, char *buf, size_t *psz)
00766 {
00767     var_t *v = NULL;
00768     size_t vsize;
00769 
00770     dbg_err_if(ss == NULL);
00771     dbg_err_if(ss->vars == NULL);
00772     dbg_err_if(buf == NULL);
00773     dbg_err_if(psz == 0);
00774     dbg_err_if(*psz == 0);
00775 
00776     nop_err_if((v = vars_get(ss->vars, SESSION_KEY_VAR)) == NULL);
00777 
00778     vsize = var_get_value_size(v);
00779 
00780     dbg_err_if(vsize >= *psz);
00781 
00782     memcpy(buf, var_get_value(v), vsize);
00783 
00784     *psz = vsize;
00785 
00786     return 0;
00787 err:
00788     if(v)
00789         var_free(v);
00790     return ~0;
00791 }
00792 
00793 #endif
00794 
00795 int session_prv_save_to_io(session_t *ss, io_t *out)
00796 {
00797     save_cb_params_t prm; 
00798     codec_t *zip = NULL, *cencrypt = NULL;
00799 
00800     dbg_err_if (ss == NULL);
00801     dbg_err_if (out == NULL);
00802 
00803 #ifdef HAVE_LIBZ
00804     if(ss->so->compress)
00805     {
00806         dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00807         dbg_err_if(io_codec_add_tail(out, zip));
00808         zip = NULL; /* io_t owns it after io_codec_add_tail */
00809     }
00810 #endif
00811 
00812 #ifdef SSL_ON
00813     if(ss->so->encrypt)
00814     {
00815         dbg_err_if(codec_cipher_create(CIPHER_ENCRYPT, ss->so->cipher, 
00816             ss->so->cipher_key, ss->so->cipher_iv, &cencrypt));
00817         dbg_err_if(io_codec_add_tail(out, cencrypt));
00818         cencrypt = NULL; /* io_t owns it after io_codec_add_tail */
00819     }
00820 #endif
00821 
00822     /* pass io and session pointers to the callback function */
00823     prm.io = out;
00824     prm.ss = ss;
00825 
00826     vars_foreach(ss->vars, session_prv_save_var, (void*)&prm);
00827 
00828     /* remove all codecs and flush */
00829     io_codecs_remove(out);
00830 
00831     return 0;
00832 err:
00833     if(out)
00834         io_codecs_remove(out);
00835     if(zip)
00836         codec_free(zip);
00837     if(cencrypt)
00838         codec_free(cencrypt);
00839     return ~0;
00840 }
00841 
00842 /* save a var_t (text or binary) to the session io_t */
00843 int session_prv_save_var(var_t *v, void *vp)
00844 {
00845     enum { NAMESZ = 256, VALSZ = 4096 };
00846     char sname[NAMESZ], svalue[VALSZ];
00847     char *uname = sname, *uvalue = svalue;
00848     save_cb_params_t *pprm = (save_cb_params_t*)vp;
00849     /* encrypted key buffer */
00850     unsigned char ekey[CODEC_CIPHER_KEY_BUFSZ]; /* key + padding block */
00851     unsigned char pkey[CODEC_CIPHER_KEY_BUFSZ];
00852     size_t nsz, vsz, eksz, pksz;
00853     int rc = ~0;
00854 
00855     dbg_err_if (v == NULL);
00856     /* dbg_err_if (vp == NULL); */
00857 
00858     memset(sname, 0, NAMESZ);
00859     memset(svalue, 0, VALSZ);
00860 
00861     /* buffers must be at least three times the src data to URL-encode  */
00862     nsz = 1 + 3 * strlen(var_get_name(v));  /* name buffer size  */
00863     vsz = 1 + 3 * var_get_value_size(v);    /* value buffer size */
00864 
00865 #ifdef SSL_ON
00866     vsz += CODEC_CIPHER_BLOCK_LEN; /* encryption may enlarge the content up 
00867                                        to CODEC_CIPHER_BLOCK_LEN -1         */
00868 #else
00869     u_unused_args(ekey, eksz);
00870 #endif
00871 
00872     /* if the buffer on the stack is too small alloc a bigger one */
00873     if(NAMESZ <= nsz)
00874         dbg_err_if((uname = u_zalloc(nsz)) == NULL);
00875 
00876     /* url encode name */
00877     dbg_err_if(u_urlncpy(uname, var_get_name(v), strlen(var_get_name(v)), 
00878         URLCPY_ENCODE) <= 0);
00879 
00880     if(var_get_value(v))
00881     {
00882         /* if the buffer on the stack is too small alloc a bigger one */
00883         if(VALSZ <= vsz)
00884             dbg_err_if((uvalue = u_zalloc(vsz)) == NULL);
00885 
00886 #ifdef SSL_ON
00887         if(!strcmp(var_get_name(v), SESSION_KEY_VAR))
00888         {
00889                         memset(pkey, 0, sizeof(pkey)); /* plain text key */
00890                         memset(ekey, 0, sizeof(ekey)); /* encrypted text key */
00891 
00892                         /* copy the actual key to a zero-ed buffer of size key (i.e. if the
00893                          * key is shorted then the buffer the trailing bytes will be 0s */
00894                         pksz = var_get_value_size(v);
00895 
00896             err_err_ifm(pksz != CODEC_CIPHER_KEY_LEN,
00897                     "bad encryption key; it must be %u bytes long",
00898                     CODEC_CIPHER_KEY_LEN);
00899 
00900                         memcpy(pkey, var_get_value(v), pksz);
00901 
00902                         eksz = sizeof(ekey);;
00903 
00904             /* encrypt the key and save it to ekey */
00905             dbg_err_if(u_cipher_encrypt(EVP_aes_256_cbc(), 
00906                 pprm->ss->so->session_key, pprm->ss->so->session_iv, 
00907                 ekey, &eksz, pkey, pksz));
00908 
00909             /* save it to the var list */
00910             dbg_err_if(var_set_bin_value(v, ekey, eksz));
00911         }
00912 #endif
00913 
00914         dbg_err_if(u_urlncpy(uvalue, var_get_value(v), var_get_value_size(v), 
00915             URLCPY_ENCODE) <= 0);
00916 
00917         dbg_err_if(io_printf(pprm->io, "%s=%s\n", uname, uvalue) < 0);
00918     } else 
00919         dbg_err_if(io_printf(pprm->io, "%s=\n", uname) < 0);
00920 
00921     rc = 0; /* success */
00922 err:
00923     /* free heap buffers */
00924     if(uname && uname != sname)
00925         u_free(uname);
00926 
00927     if(uvalue && uvalue != svalue)
00928         u_free(uvalue);
00929 
00930     return rc;
00931 }
00932 
00933 int session_create(session_opt_t *so, request_t *rq, response_t *rs, 
00934     session_t **pss)
00935 {
00936     session_t *ss = NULL;
00937 
00938     dbg_err_if (so == NULL);
00939     dbg_err_if (rq == NULL);
00940     dbg_err_if (rs == NULL);
00941     dbg_err_if (pss == NULL);
00942 
00943     switch(so->type)
00944     {
00945     case SESSION_TYPE_FILE:
00946         dbg_err_if(session_file_create(so, rq, rs, &ss));
00947         break;
00948     case SESSION_TYPE_MEMORY:
00949         dbg_err_if(session_mem_create(so, rq, rs, &ss));
00950         break;
00951 #ifdef SSL_ON
00952     case SESSION_TYPE_CLIENT:
00953         dbg_err_if(session_client_create(so, rq, rs, &ss));
00954         break;
00955 #endif
00956     default:
00957         warn_err("bad session type");
00958     }
00959 
00960     /* may fail if the session does not exist */
00961     if(ss->id[0] != '\0')
00962     {
00963         (void) session_load(ss);
00964 
00965         if (session_age(ss) > so->max_age)
00966         {
00967             u_dbg("session %s expired", ss->id);
00968             (void) session_clean(ss);  /* remove all session variables */
00969             (void) session_remove(ss); /* remove the session itself    */
00970         }
00971     } 
00972 
00973     *pss = ss;
00974 
00975     return 0;
00976 err:
00977     if(ss)
00978         session_free(ss);
00979     return ~0;
00980 }
00981 

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved