KLone APIs | Modules | Data Structures | File List | Data Fields | Globals

session.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005, 2006 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  * $Id: session.c,v 1.46 2009/10/23 14:08:28 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #include <sys/time.h>
00015 #include <stdlib.h>
00016 #include <time.h>
00017 #include <unistd.h>
00018 #include <fcntl.h>
00019 #ifdef HAVE_LIBOPENSSL
00020 #include <openssl/hmac.h>
00021 #include <openssl/evp.h>
00022 #include <openssl/rand.h>
00023 #include <klone/ccipher.h>
00024 #endif /* HAVE_LIBOPENSSL */
00025 #include <u/libu.h>
00026 #include <klone/session.h>
00027 #include <klone/request.h>
00028 #include <klone/response.h>
00029 #include <klone/vars.h>
00030 #include <klone/utils.h>
00031 #include <klone/ses_prv.h>
00032 #include <klone/codecs.h>
00033 
00034 enum { DEFAULT_SESSION_EXPIRATION = 60*20 }; /* 20 minutes */
00035 static const char SID_NAME[] = "klone_sid";
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     session_opt_t *so = NULL;
00055     u_config_t *c = NULL;
00056     const char *v;
00057 
00058     dbg_err_if (config == NULL);
00059     dbg_err_if (pso == NULL);
00060 
00061     so = u_zalloc(sizeof(session_opt_t));
00062     dbg_err_if(so == 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     if(!u_config_get_subkey(config, "session", &c))
00072     {
00073         /* no 'session' subsection, defaults will be used */
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 HAVE_LIBOPENSSL
00083             } else if(!strcasecmp(v, "client")) {
00084                 so->type = SESSION_TYPE_CLIENT;
00085 #endif
00086             } else
00087                warn_err("config error: bad session type (typo or missing "
00088                         "library)");
00089         }
00090 
00091         /* set max_age */
00092         if((v = u_config_get_subkey_value(c, "max_age")) != NULL)
00093             so->max_age = MAX(atoi(v) * 60, 60); /* min value: 1 min */
00094 
00095         /* set compression flag */
00096         dbg_err_if(u_config_get_subkey_value_b(c, "compress", 0,
00097             &so->compress));
00098 
00099         /* set encryption flag */
00100         dbg_err_if(u_config_get_subkey_value_b(c, "encrypt", 0, &so->encrypt));
00101 
00102         /* set cookie name */
00103         if ((v = u_config_get_subkey_value(c, "sid_name")) != NULL)
00104             dbg_err_if (u_strlcpy(so->name, v, sizeof so->name));
00105 
00106 #ifndef HAVE_LIBZ
00107         if(so->compress)
00108             warn_err("config error: compression is enabled but libz is not "
00109                      "linked");
00110 #endif
00111 
00112 #ifndef HAVE_LIBOPENSSL
00113         if(so->encrypt)
00114             warn_err("config error: encryption is enabled but OpenSSL is not "
00115                      "linked");
00116 #else
00117         /* init cipher EVP algo, the random key and IV */
00118         so->cipher = EVP_aes_256_cbc(); /* use AES-256 in CBC mode */
00119 
00120         EVP_add_cipher(so->cipher);
00121 
00122         /* key and iv for client-side session */
00123         dbg_err_if(!RAND_bytes(so->cipher_key, CIPHER_KEY_SIZE));
00124         dbg_err_if(!RAND_pseudo_bytes(so->cipher_iv, CIPHER_IV_SIZE));
00125 
00126         /* create a random key and iv to crypt the KLONE_CIPHER_KEY variable */
00127         dbg_err_if(!RAND_bytes(so->session_key, CIPHER_KEY_SIZE));
00128         dbg_err_if(!RAND_pseudo_bytes(so->session_iv, CIPHER_IV_SIZE));
00129 
00130 #endif
00131     } /* if "session" exists */
00132 
00133     /* per-type configuration init */
00134     if(so->type == SESSION_TYPE_MEMORY)
00135         warn_err_ifm(session_mem_module_init(c, so), 
00136             "in-memory session engine init error");
00137     else if(so->type == SESSION_TYPE_FILE)
00138         warn_err_ifm(session_file_module_init(c, so), 
00139             "file session engine init error");
00140 #ifdef HAVE_LIBOPENSSL
00141     else if(so->type == SESSION_TYPE_CLIENT)
00142         warn_err_ifm(session_client_module_init(c, so),
00143             "client-side session engine init error");
00144 #endif
00145 
00146     *pso = so;
00147 
00148     return 0;
00149 err:
00150     U_FREE(so);
00151     return ~0;
00152 }
00153 
00154 int session_prv_calc_maxsize(var_t *v, void *p)
00155 {
00156     const char *value = NULL;
00157     size_t *psz = (size_t*)p;
00158 
00159     dbg_err_if (v == NULL);
00160     dbg_err_if (var_get_name(v) == NULL);
00161     dbg_err_if (psz == NULL);
00162 
00163 #ifdef HAVE_LIBOPENSSL
00164     if(*psz == 0)
00165     {   /* first time here */
00166         *psz = CODEC_CIPHER_BLOCK_SIZE;
00167     }
00168 #endif
00169 
00170     /* name= */
00171     *psz += 3 * strlen(var_get_name(v)) + 3;
00172 
00173     /* value */
00174     if((value = var_get_value(v)) != NULL)
00175         *psz += 3 * strlen(value) + 1; /* worse case (i.e. longest string) */
00176 
00177     return 0;
00178 err:
00179     return ~0;
00180 }
00181 
00182 int session_prv_load_from_buf(session_t *ss, char *buf, size_t size)
00183 {
00184     io_t *io = NULL;
00185 
00186     dbg_err_if (ss == NULL);
00187     dbg_err_if (buf == NULL);
00188 
00189     /* build an io_t around the buffer */
00190     dbg_err_if(io_mem_create(buf, size, 0, &io));
00191 
00192     /* load data */
00193     dbg_err_if(session_prv_load_from_io(ss, io));
00194 
00195     io_free(io);
00196 
00197     return 0;
00198 err:
00199     if(io)
00200         io_free(io);
00201     return ~0;
00202 }
00203 
00204 int session_prv_save_to_buf(session_t *ss, char **pbuf, size_t *psz)
00205 {
00206     io_t *io = NULL;
00207     char *buf = NULL;
00208     size_t sz = 0;
00209 
00210     dbg_err_if (ss == NULL);
00211     dbg_err_if (pbuf == NULL);
00212     dbg_err_if (psz == NULL);
00213  
00214     /* calc the maximum session data size (exact calc requires url encoding and
00215        codec transformation knowledge) */
00216     vars_foreach(ss->vars, session_prv_calc_maxsize, (void*)&sz);
00217 
00218     /* alloc a big-enough block to save the session data */
00219     buf = u_malloc(sz);
00220     dbg_err_if(buf == NULL);
00221 
00222     /* create a big-enough in-memory io object */
00223     dbg_err_if(io_mem_create(buf, sz, 0, &io));
00224 
00225     /* save the session to the in-memory io */
00226     dbg_err_if(session_prv_save_to_io(ss, io));
00227 
00228     /* remove all codecs to get the right size of 'buf'. we need to remove 
00229        the codecs because some of them buffer data until last codec->flush() 
00230        is called (and it's not possible to flush codecs without removing them */
00231     dbg_err_if(io_codecs_remove(io));
00232 
00233     /* get the number of bytes written to the io (so to 'buf') */
00234     sz = io_tell(io);
00235 
00236     io_free(io);
00237     io = NULL;
00238 
00239     *pbuf = buf;
00240     *psz = sz;
00241 
00242     return 0;
00243 err:
00244     if(io)
00245         io_free(io);
00246     U_FREE(buf);
00247     return ~0;
00248 }
00249 
00250 static int session_is_good_id(const char *id)
00251 {
00252     const char *p;
00253     size_t len;
00254 
00255     dbg_return_if (id == NULL, 0);
00256 
00257     dbg_ifb((len = strlen(id)) != SESSION_ID_LENGTH)
00258         return 0; /* wrong length */
00259 
00260     for(p = id; len; --len, ++p)
00261     {
00262         /* if is hex */
00263         if(! ((*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f') || 
00264               (*p >= '0' && *p <= '9')) )
00265         return 0; /* not safe */
00266     }
00267 
00268     return 1; /* good */
00269 }
00270 
00271 static int session_set_filename(session_t *ss)
00272 {
00273     kaddr_t *addr = NULL;
00274 
00275     dbg_err_if(strlen(ss->id) == 0);
00276 
00277     dbg_err_if((addr = request_get_addr(ss->rq)) == NULL);
00278     switch(addr->type)
00279     {
00280     case ADDR_IPV4:
00281         dbg_err_if(u_path_snprintf(ss->filename, U_FILENAME_MAX, 
00282             U_PATH_SEPARATOR, "%s/klone_sess_%s_%lu", ss->so->path, ss->id, 
00283             addr->sa.sin.sin_addr));
00284         break;
00285     case ADDR_IPV6:
00286         /* FIXME: add ipv6 address in session filename */
00287         dbg_err_if(u_path_snprintf(ss->filename, U_FILENAME_MAX, 
00288             U_PATH_SEPARATOR, "%s/klone_sess_%s", ss->so->path, ss->id));
00289         break;
00290 #ifdef OS_UNIX
00291     case ADDR_UNIX:
00292         /* FIXME: add unix address in session filename */
00293         dbg_err_if(u_path_snprintf(ss->filename, U_FILENAME_MAX, 
00294             U_PATH_SEPARATOR, "%s/klone_sess_%s", ss->so->path, ss->id));
00295         break;
00296 #endif
00297     }
00298 
00299     return 0;
00300 err:
00301     return 0;
00302 }
00303 
00304 static int session_gen_id(session_t *ss)
00305 {
00306     enum { BUFSZ = 256 };
00307     char buf[BUFSZ];
00308     struct timeval tv;
00309 
00310     dbg_err_if (ss == NULL);
00311 
00312     /* gen a new one */
00313     gettimeofday(&tv, NULL);
00314 
00315     dbg_err_if(u_snprintf(buf, BUFSZ, "%lu%d%lu%d", tv.tv_sec, getpid(), 
00316         tv.tv_usec, rand()));
00317 
00318     /* return the md5 (in hex) buf */
00319     dbg_err_if(u_md5(buf, strlen(buf), ss->id));
00320 
00321     /* remove previous sid if any */ 
00322     dbg_err_if(response_set_cookie(ss->rs, ss->so->name, NULL, 0, NULL, 
00323                 NULL, 0));
00324 
00325     /* set the cookie ID */
00326     dbg_err_if(response_set_cookie(ss->rs, ss->so->name, ss->id, 0, NULL, 
00327                 NULL, 0));
00328 
00329     return 0;
00330 err:
00331     return ~0;
00332 }
00333 
00334 int session_priv_set_id(session_t *ss, const char *sid)
00335 {
00336     /* set or generate a session id */
00337     if(sid && session_is_good_id(sid))
00338     {
00339         dbg_err_if(u_snprintf(ss->id, SESSION_ID_BUFSZ, "%s", sid));
00340         ss->id[SESSION_ID_BUFSZ-1] = 0;
00341     } else
00342         dbg_err_if(session_gen_id(ss));
00343 
00344     /* set the filename accordingly */
00345     dbg_err_if(session_set_filename(ss));
00346 
00347     return 0;
00348 err:
00349     return ~0;
00350 }
00351 
00352 int session_load(session_t *ss)
00353 {
00354     dbg_return_if (ss == NULL, ~0);
00355     dbg_return_if (ss->load == NULL, ~0);
00356 
00357     return ss->load(ss);
00358 }
00359 
00360 int session_save(session_t *ss)
00361 {
00362     size_t vcount;
00363     dbg_err_if (ss == NULL);
00364     dbg_err_if (ss->save == NULL);
00365 
00366     vcount = vars_count(ss->vars);
00367 
00368     if(ss->id[0] == 0 && vcount == 0)
00369         return 0; /* new user, no vars set -> nothing to save */
00370 
00371     if(ss->id[0] != 0 && vcount == 0)
00372         return session_remove(ss); /* old user, all vars removed */
00373 
00374     if(ss->id[0] == 0)
00375     {
00376         /* new user, need to save some vars */
00377 
00378         /* generate a new SID and set session filename accordingly */
00379         dbg_err_if(session_priv_set_id(ss, NULL)); 
00380     }
00381 
00382     return ss->save(ss);
00383 err:
00384     return ~0;
00385 }
00386 
00387 int session_remove(session_t *ss)
00388 {
00389     dbg_return_if (ss == NULL, ~0);
00390     dbg_return_if (ss->remove == NULL, ~0);
00391 
00392     /* remove the cookie */
00393     response_set_cookie(ss->rs, ss->so->name, NULL, 0, NULL, NULL, 0);
00394 
00395     ss->removed = 1;
00396 
00397     return ss->remove(ss);
00398 }
00399 
00400 int session_prv_init(session_t *ss, request_t *rq, response_t *rs)
00401 {
00402     const char *sid;
00403 
00404     dbg_err_if (ss == NULL);
00405     dbg_err_if (rq == NULL);
00406     dbg_err_if (rs == NULL);
00407     
00408     dbg_err_if(vars_create(&ss->vars));
00409 
00410     ss->rq = rq;
00411     ss->rs = rs;
00412 
00413     /* if the client has a SID set and it's a good one then use it */
00414     sid = request_get_cookie(ss->rq, ss->so->name);
00415     if(sid)
00416         dbg_err_if(session_priv_set_id(ss, sid));
00417 
00418     return 0;
00419 err:
00420     return ~0;
00421 }
00422 
00423 int session_prv_load_from_io(session_t *ss, io_t *io)
00424 {
00425     u_string_t *line = NULL;
00426     var_t *v = NULL;
00427     codec_t *unzip = NULL, *decrypt = NULL;
00428     unsigned char key[CODEC_CIPHER_KEY_SIZE];
00429     size_t ksz;
00430 
00431     dbg_return_if (ss == NULL, ~0);
00432     dbg_return_if (io == NULL, ~0);
00433 
00434 #ifdef HAVE_LIBOPENSSL
00435     if(ss->so->encrypt)
00436     {
00437         dbg_err_if(codec_cipher_create(CIPHER_DECRYPT, ss->so->cipher, 
00438             ss->so->cipher_key, ss->so->cipher_iv, &decrypt)); 
00439         dbg_err_if(io_codec_add_tail(io, decrypt));
00440         decrypt = NULL; /* io_t owns it after io_codec_add_tail */
00441     }
00442 #else
00443     u_unused_args(key, ksz);
00444 #endif
00445 
00446 #ifdef HAVE_LIBZ
00447     if(ss->so->compress)
00448     {
00449         dbg_err_if(codec_gzip_create(GZIP_UNCOMPRESS, &unzip));
00450         dbg_err_if(io_codec_add_tail(io, unzip));
00451         unzip = NULL; /* io_t owns it after io_codec_add_tail */
00452     }
00453 #endif
00454 
00455     dbg_err_if(u_string_create(NULL, 0, &line));
00456 
00457     while(u_getline(io, line) == 0)
00458     {
00459         if(u_string_len(line))
00460         {
00461             dbg_err_if(vars_add_urlvar(ss->vars, u_string_c(line), &v));
00462 
00463 #ifdef HAVE_LIBOPENSSL
00464             if(!strcmp(var_get_name(v), "KLONE_CIPHER_KEY"))
00465             {
00466                 /* decrypt key and save it to key */
00467                 memset(key, 0, 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, "KLONE_CIPHER_KEY");
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 #endif
00480         }
00481     }
00482 
00483     /* remove set codecs and flush */
00484     io_codecs_remove(io);
00485 
00486     u_string_free(line);
00487 
00488     return 0;
00489 err:
00490     if(io)
00491         io_codecs_remove(io);
00492     if(decrypt)
00493         codec_free(decrypt);
00494     if(unzip)
00495         codec_free(unzip);
00496     if(line)
00497         u_string_free(line);
00498     return ~0;
00499 }
00500 
00501 int session_free(session_t *ss)
00502 {
00503     if (ss)
00504     { 
00505         if(!ss->removed)
00506             dbg_if(session_save(ss));
00507 
00508         /* driver cleanup */
00509         dbg_if(ss->term(ss));
00510 
00511         if(ss->vars)
00512             vars_free(ss->vars);
00513 
00514         U_FREE(ss);
00515     }
00516 
00517     return 0;
00518 }
00519 
00530 vars_t *session_get_vars(session_t *ss)
00531 {
00532     dbg_return_if (ss == NULL, NULL);
00533 
00534     return ss->vars;
00535 }
00536 
00549 const char *session_get(session_t *ss, const char *name)
00550 {
00551     var_t *v;
00552 
00553     dbg_return_if (ss == NULL, NULL);
00554     dbg_return_if (name == NULL, NULL);
00555     
00556     v = vars_get(ss->vars, name);
00557     return v ? var_get_value(v): NULL;
00558 }
00559 
00570 const char *session_get_id (session_t *ss)
00571 {
00572     dbg_return_if (ss == NULL, NULL);
00573 
00574     return ss->id;
00575 }
00576 
00589 int session_set(session_t *ss, const char *name, const char *value)
00590 {
00591     var_t *v = NULL;
00592 
00593     dbg_err_if (ss == NULL);
00594     dbg_err_if (name == NULL);
00595     dbg_err_if (value == NULL);
00596     dbg_err_if (strlen(name) == 0);
00597 
00598     if((v = vars_get(ss->vars, name)) == NULL)
00599     {
00600         /* add a new session variable */
00601         dbg_err_if(var_create(name, value, &v));
00602 
00603         dbg_err_if(vars_add(ss->vars, v));
00604     } else {
00605         /* update an existing var */
00606         dbg_ifb(var_set_value(v, value))
00607             return ~0;
00608     }
00609 
00610     return 0;
00611 err:
00612     if(v)
00613         var_free(v);
00614     return ~0;
00615 }
00616 
00629 int session_age(session_t *ss)
00630 {
00631     time_t now;
00632 
00633     dbg_return_if (ss == NULL, -1);
00634 
00635     now = time(0);
00636 
00637     /* ss->mtime must has been set into session_X_create funcs */
00638     return (int)(now - ss->mtime); /* in seconds */
00639 }
00640 
00651 int session_clean(session_t *ss)
00652 {
00653     var_t *v = NULL;
00654 
00655     dbg_err_if (ss == NULL);
00656 
00657     while((v = vars_getn(ss->vars, 0)) != NULL)
00658     {
00659         dbg_err_if(vars_del(ss->vars, v));
00660         var_free(v);
00661     }
00662 
00663     return 0;
00664 err:
00665     return ~0;
00666 }
00667 
00681 int session_del(session_t *ss, const char *name)
00682 {
00683     var_t *v = NULL;
00684 
00685     dbg_err_if (ss == NULL);
00686     dbg_err_if (name == NULL);
00687     
00688     dbg_err_if((v = vars_get(ss->vars, name)) == NULL);
00689     dbg_err_if(vars_del(ss->vars, v));
00690     var_free(v);
00691 
00692     return 0;
00693 err:
00694     return ~0;
00695 }
00696 
00697 int session_prv_save_to_io(session_t *ss, io_t *out)
00698 {
00699     save_cb_params_t prm; 
00700     codec_t *zip = NULL, *cencrypt = NULL;
00701 
00702     dbg_err_if (ss == NULL);
00703     dbg_err_if (out == NULL);
00704 
00705 #ifdef HAVE_LIBZ
00706     if(ss->so->compress)
00707     {
00708         dbg_err_if(codec_gzip_create(GZIP_COMPRESS, &zip));
00709         dbg_err_if(io_codec_add_tail(out, zip));
00710         zip = NULL; /* io_t owns it after io_codec_add_tail */
00711     }
00712 #endif
00713 
00714 #ifdef HAVE_LIBOPENSSL
00715     if(ss->so->encrypt)
00716     {
00717         dbg_err_if(codec_cipher_create(CIPHER_ENCRYPT, ss->so->cipher, 
00718             ss->so->cipher_key, ss->so->cipher_iv, &cencrypt));
00719         dbg_err_if(io_codec_add_tail(out, cencrypt));
00720         cencrypt = NULL; /* io_t owns it after io_codec_add_tail */
00721     }
00722 #endif
00723 
00724     /* pass io and session poiters to the callback function */
00725     prm.io = out;
00726     prm.ss = ss;
00727 
00728     vars_foreach(ss->vars, session_prv_save_var, (void*)&prm);
00729 
00730     /* remove all codecs and flush */
00731     io_codecs_remove(out);
00732 
00733     return 0;
00734 err:
00735     if(out)
00736         io_codecs_remove(out);
00737     if(zip)
00738         codec_free(zip);
00739     if(cencrypt)
00740         codec_free(cencrypt);
00741     return ~0;
00742 }
00743 
00744 /* save a var_t (text or binary) to the session io_t */
00745 int session_prv_save_var(var_t *v, void *vp)
00746 {
00747     enum { NAMESZ = 256, VALSZ = 4096 };
00748     char sname[NAMESZ], svalue[VALSZ];
00749     char *uname = sname, *uvalue = svalue;
00750     save_cb_params_t *pprm = (save_cb_params_t*)vp;
00751     /* encrypted key buffer */
00752     unsigned char ekey[CODEC_CIPHER_KEY_SIZE + CODEC_CIPHER_BLOCK_SIZE + 1]; 
00753     size_t eksz, nsz, vsz;
00754     int rc = ~0;
00755 
00756     dbg_err_if (v == NULL);
00757     /* dbg_err_if (vp == NULL); */
00758 
00759     /* buffers must be at least three times the src data to URL-encode  */
00760     nsz = 1 + 3 * strlen(var_get_name(v));  /* name buffer size  */
00761     vsz = 1 + 3 * var_get_value_size(v);    /* value buffer size */
00762 
00763 #ifdef HAVE_LIBOPENSSL
00764     vsz += CODEC_CIPHER_BLOCK_SIZE; /* encryption may enlarge the content up 
00765                                        to CODEC_CIPHER_BLOCK_SIZE -1         */
00766 #else
00767     u_unused_args(ekey, eksz);
00768 #endif
00769 
00770     /* if the buffer on the stack is too small alloc a bigger one */
00771     if(NAMESZ <= nsz)
00772         dbg_err_if((uname = u_zalloc(nsz)) == NULL);
00773 
00774     /* url encode name */
00775     dbg_err_if(u_urlncpy(uname, var_get_name(v), strlen(var_get_name(v)), 
00776         URLCPY_ENCODE) <= 0);
00777 
00778     if(var_get_value(v))
00779     {
00780         /* if the buffer on the stack is too small alloc a bigger one */
00781         if(VALSZ <= vsz)
00782             dbg_err_if((uvalue = u_zalloc(vsz)) == NULL);
00783 
00784 #ifdef HAVE_LIBOPENSSL
00785         if(!strcmp(var_get_name(v), "KLONE_CIPHER_KEY"))
00786         {
00787             /* encrypt key and save it to ekey */
00788             dbg_err_if(u_cipher_encrypt(EVP_aes_256_cbc(), 
00789                 pprm->ss->so->session_key, pprm->ss->so->session_iv, 
00790                 ekey, &eksz, var_get_value(v), var_get_value_size(v)));
00791 
00792             /* save it to the var list */
00793             dbg_err_if(var_set_bin_value(v, ekey, eksz));
00794         }
00795 #endif
00796 
00797         dbg_err_if(u_urlncpy(uvalue, var_get_value(v), var_get_value_size(v), 
00798             URLCPY_ENCODE) <= 0);
00799 
00800         dbg_err_if(io_printf(pprm->io, "%s=%s\n", uname, uvalue) < 0);
00801     } else 
00802         dbg_err_if(io_printf(pprm->io, "%s=\n", uname) < 0);
00803 
00804     rc = 0; /* success */
00805 err:
00806     /* free heap buffers */
00807     if(uname && uname != sname)
00808         U_FREE(uname);
00809 
00810     if(uvalue && uvalue != svalue)
00811         U_FREE(uvalue);
00812 
00813     return rc;
00814 }
00815 
00816 int session_create(session_opt_t *so, request_t *rq, response_t *rs, 
00817     session_t **pss)
00818 {
00819     session_t *ss = NULL;
00820 
00821     dbg_err_if (so == NULL);
00822     dbg_err_if (rq == NULL);
00823     dbg_err_if (rs == NULL);
00824     dbg_err_if (pss == NULL);
00825 
00826     switch(so->type)
00827     {
00828     case SESSION_TYPE_FILE:
00829         dbg_err_if(session_file_create(so, rq, rs, &ss));
00830         break;
00831     case SESSION_TYPE_MEMORY:
00832         dbg_err_if(session_mem_create(so, rq, rs, &ss));
00833         break;
00834 #ifdef HAVE_LIBOPENSSL
00835     case SESSION_TYPE_CLIENT:
00836         dbg_err_if(session_client_create(so, rq, rs, &ss));
00837         break;
00838 #endif
00839     default:
00840         warn_err("bad session type");
00841     }
00842 
00843     /* may fail if the session does not exist */
00844     if(ss->id[0] != 0)
00845     {
00846         session_load(ss);
00847 
00848         dbg_ifb(session_age(ss) > so->max_age)
00849         {
00850             session_clean(ss);  /* remove all session variables */
00851             session_remove(ss); /* remove the session itself    */
00852         }
00853     } 
00854 
00855     *pss = ss;
00856 
00857     return 0;
00858 err:
00859     if(ss)
00860         session_free(ss);
00861     return ~0;
00862 }