"Fossies" - the Fresh Open Source Software Archive

Member "mod_auth_gssapi-1.6.3/src/sessions.c" (14 May 2020, 10540 Bytes) of package /linux/www/apache_httpd_modules/mod_auth_gssapi-1.6.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sessions.c" see the Fossies "Dox" file reference documentation.

    1 /* Copyright (C) 2014, 2016 mod_auth_gssapi contributors - See COPYING for (C) terms */
    2 
    3 #include "mod_auth_gssapi.h"
    4 #include "asn1c/GSSSessionData.h"
    5 
    6 APLOG_USE_MODULE(auth_gssapi);
    7 
    8 static APR_OPTIONAL_FN_TYPE(ap_session_load) *mag_sess_load_fn = NULL;
    9 static APR_OPTIONAL_FN_TYPE(ap_session_get) *mag_sess_get_fn = NULL;
   10 static APR_OPTIONAL_FN_TYPE(ap_session_set) *mag_sess_set_fn = NULL;
   11 
   12 void mag_post_config_session(void)
   13 {
   14     mag_sess_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load);
   15     mag_sess_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get);
   16     mag_sess_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set);
   17 }
   18 
   19 static apr_status_t mag_session_load(request_rec *req, session_rec **sess)
   20 {
   21     if (mag_sess_load_fn) {
   22         return mag_sess_load_fn(req, sess);
   23     }
   24     return DECLINED;
   25 }
   26 
   27 static apr_status_t mag_session_get(request_rec *req, session_rec *sess,
   28                                     const char *key, const char **value)
   29 {
   30     if (mag_sess_get_fn) {
   31         return mag_sess_get_fn(req, sess, key, value);
   32     }
   33     return DECLINED;
   34 }
   35 
   36 static apr_status_t mag_session_set(request_rec *req, session_rec *sess,
   37                                     const char *key, const char *value)
   38 {
   39     if (mag_sess_set_fn) {
   40         return mag_sess_set_fn(req, sess, key, value);
   41     }
   42     return DECLINED;
   43 }
   44 
   45 static bool encode_GSSSessionData(apr_pool_t *mempool,
   46                                   GSSSessionData_t *gsessdata,
   47                                   unsigned char **buf, int *len)
   48 {
   49     asn_enc_rval_t rval;
   50     unsigned char *buffer = NULL;
   51     size_t buflen;
   52     bool ret = false;
   53 
   54     /* dry run to compute the size */
   55     rval = der_encode(&asn_DEF_GSSSessionData, gsessdata, NULL, NULL);
   56     if (rval.encoded == -1) goto done;
   57 
   58     buflen = rval.encoded;
   59     buffer = apr_pcalloc(mempool, buflen);
   60 
   61     /* now for real */
   62     rval = der_encode_to_buffer(&asn_DEF_GSSSessionData,
   63                                 gsessdata, buffer, buflen);
   64     if (rval.encoded == -1) goto done;
   65 
   66     *buf = buffer;
   67     *len = buflen;
   68     ret = true;
   69 
   70 done:
   71     return ret;
   72 }
   73 
   74 static GSSSessionData_t *decode_GSSSessionData(void *buf, size_t len)
   75 {
   76     GSSSessionData_t *gsessdata = NULL;
   77     asn_dec_rval_t rval;
   78 
   79     rval = ber_decode(NULL, &asn_DEF_GSSSessionData,
   80                       (void **)&gsessdata, buf, len);
   81     if (rval.code == RC_OK) {
   82         return gsessdata;
   83     }
   84     return NULL;
   85 }
   86 
   87 #define MAG_BEARER_KEY "MagBearerToken"
   88 
   89 void mag_check_session(struct mag_req_cfg *cfg, struct mag_conn **conn)
   90 {
   91     request_rec *req = cfg->req;
   92     struct mag_conn *mc;
   93     apr_status_t rc;
   94     session_rec *sess = NULL;
   95     const char *sessval = NULL;
   96     int declen;
   97     struct databuf ctxbuf = { 0 };
   98     struct databuf cipherbuf = { 0 };
   99     GSSSessionData_t *gsessdata;
  100     time_t expiration;
  101 
  102     rc = mag_session_load(req, &sess);
  103     if (rc != OK || sess == NULL) {
  104         ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req,
  105                       "Sessions not available, no cookies!");
  106         return;
  107     }
  108 
  109     mc = *conn;
  110     if (!mc) {
  111         *conn = mc = mag_new_conn_ctx(req->pool);
  112         mc->is_preserved = true;
  113     }
  114 
  115     rc = mag_session_get(req, sess, MAG_BEARER_KEY, &sessval);
  116     if (rc != OK) {
  117         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  118                       "Failed to get session data!");
  119         return;
  120     }
  121     if (!sessval) {
  122         /* no session established, just return */
  123         return;
  124     }
  125 
  126     if (!cfg->mag_skey) {
  127         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
  128                       "Session key not available, no cookies!");
  129         /* we do not have a key, just return */
  130         return;
  131     }
  132 
  133     /* decode it */
  134     declen = apr_base64_decode_len(sessval);
  135     cipherbuf.value = apr_palloc(req->pool, declen);
  136     if (!cipherbuf.value) return;
  137     cipherbuf.length = (int)apr_base64_decode((char *)cipherbuf.value, sessval);
  138 
  139     rc = UNSEAL_BUFFER(req->pool, cfg->mag_skey, &cipherbuf, &ctxbuf);
  140     if (rc != OK) {
  141         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  142                       "Failed to unseal session data!");
  143         return;
  144     }
  145 
  146     gsessdata = decode_GSSSessionData(ctxbuf.value, ctxbuf.length);
  147     if (!gsessdata) {
  148         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  149                       "Failed to unpack session data!");
  150         return;
  151     }
  152 
  153     /* booleans */
  154     if (gsessdata->established != 0) mc->established = true;
  155     if (gsessdata->delegated != 0) mc->delegated = true;
  156 
  157     /* get time */
  158     expiration = gsessdata->expiration;
  159     if (expiration < time(NULL)) {
  160         /* credentials fully expired, return nothing */
  161         mc->established = false;
  162         goto done;
  163     }
  164 
  165     /* user name */
  166     mc->user_name = apr_pstrndup(mc->pool,
  167                                  (char *)gsessdata->username.buf,
  168                                  gsessdata->username.size);
  169     if (!mc->user_name) goto done;
  170 
  171     /* gssapi name */
  172     mc->gss_name = apr_pstrndup(mc->pool,
  173                                 (char *)gsessdata->gssname.buf,
  174                                 gsessdata->gssname.size);
  175     if (!mc->gss_name) goto done;
  176 
  177     mc->basic_hash.length = gsessdata->basichash.size;
  178     mc->basic_hash.value = apr_palloc(mc->pool, mc->basic_hash.length);
  179     memcpy(mc->basic_hash.value,
  180            gsessdata->basichash.buf, gsessdata->basichash.size);
  181 
  182     /* ccname */
  183     mc->ccname = apr_pstrndup(mc->pool,
  184                               (char *)gsessdata->ccname.buf,
  185                               gsessdata->ccname.size);
  186     if (!mc->ccname) goto done;
  187 
  188     /* OK we have a valid token */
  189     mc->established = true;
  190 
  191 done:
  192     ASN_STRUCT_FREE(asn_DEF_GSSSessionData, gsessdata);
  193 }
  194 
  195 void mag_attempt_session(struct mag_req_cfg *cfg, struct mag_conn *mc)
  196 {
  197     request_rec *req = cfg->req;
  198     session_rec *sess = NULL;
  199     struct databuf plainbuf = { 0 };
  200     struct databuf cipherbuf = { 0 };
  201     struct databuf ctxbuf = { 0 };
  202     GSSSessionData_t gsessdata = { 0 };
  203     apr_status_t rc;
  204     bool ret;
  205 
  206     /* we save the session only if the authentication is established */
  207 
  208     if (!mc->established) return;
  209     rc = mag_session_load(req, &sess);
  210     if (rc != OK || sess == NULL) {
  211         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
  212                       "Sessions not available, can't send cookies!");
  213         return;
  214     }
  215 
  216     if (!cfg->mag_skey) {
  217         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
  218                       "Session key not available, aborting.");
  219         return;
  220     }
  221 
  222     gsessdata.established = mc->established?1:0;
  223     gsessdata.delegated = mc->delegated?1:0;
  224 
  225     if (sess->expiry != 0) {
  226         mc->expiration = mc->expiration < apr_time_sec(sess->expiry) ?
  227                          mc->expiration : apr_time_sec(sess->expiry);
  228     }
  229     gsessdata.expiration = mc->expiration;
  230 
  231     if (OCTET_STRING_fromString(&gsessdata.username, mc->user_name) != 0)
  232         goto done;
  233     if (OCTET_STRING_fromString(&gsessdata.gssname, mc->gss_name) != 0)
  234         goto done;
  235     if (OCTET_STRING_fromBuf(&gsessdata.basichash,
  236                              (const char *)mc->basic_hash.value,
  237                              mc->basic_hash.length) != 0)
  238         goto done;
  239 
  240     /* NULL ccname here just means default ccache */
  241     if (mc->ccname &&
  242         OCTET_STRING_fromString(&gsessdata.ccname, mc->ccname) != 0) {
  243         goto done;
  244     }
  245 
  246     ret = encode_GSSSessionData(req->pool, &gsessdata,
  247                                 &plainbuf.value, &plainbuf.length);
  248     if (ret == false) {
  249         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  250                       "Failed to pack session data!");
  251         goto done;
  252     }
  253 
  254     rc = SEAL_BUFFER(req->pool, cfg->mag_skey, &plainbuf, &cipherbuf);
  255     if (rc != OK) {
  256         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  257                       "Failed to seal session data!");
  258         goto done;
  259     }
  260 
  261     ctxbuf.length = apr_base64_encode_len(cipherbuf.length);
  262     ctxbuf.value = apr_pcalloc(req->pool, ctxbuf.length);
  263     if (!ctxbuf.value) goto done;
  264 
  265     ctxbuf.length = apr_base64_encode((char *)ctxbuf.value,
  266                                       (char *)cipherbuf.value,
  267                                       cipherbuf.length);
  268 
  269     rc = mag_session_set(req, sess, MAG_BEARER_KEY, (char *)ctxbuf.value);
  270     if (rc != OK) {
  271         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
  272                       "Failed to set session data!");
  273     }
  274 
  275 done:
  276     ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GSSSessionData, &gsessdata);
  277 }
  278 
  279 static int mag_basic_hmac(struct seal_key *key, unsigned char *mac,
  280                           gss_buffer_desc user, gss_buffer_desc pwd)
  281 {
  282     struct databuf hmacbuf = { mac, 0 };
  283     int data_size = user.length + pwd.length + 1;
  284     unsigned char data[data_size];
  285     struct databuf databuf = { data, data_size };
  286 
  287     memcpy(data, user.value, user.length);
  288     data[user.length] = '\0';
  289     memcpy(&data[user.length + 1], pwd.value, pwd.length);
  290 
  291     return HMAC_BUFFER(key, &databuf, &hmacbuf);
  292 }
  293 
  294 static int mag_get_mac_size(struct mag_req_cfg *cfg)
  295 {
  296     if (!cfg->mag_skey) {
  297         ap_log_perror(APLOG_MARK, APLOG_INFO, 0, cfg->cfg->pool,
  298                       "Session key not available, aborting!");
  299         return 0;
  300     }
  301 
  302     return get_mac_size(cfg->mag_skey);
  303 }
  304 
  305 bool mag_basic_check(struct mag_req_cfg *cfg, struct mag_conn *mc,
  306                      gss_buffer_desc user, gss_buffer_desc pwd)
  307 {
  308     int mac_size = mag_get_mac_size(cfg);
  309     unsigned char mac[mac_size];
  310     int ret, i, j;
  311     bool res = false;
  312 
  313     if (mac_size == 0) return false;
  314     if (mc->basic_hash.value == NULL) return false;
  315 
  316     ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd);
  317     if (ret != 0) goto done;
  318 
  319     for (i = 0, j = 0; i < mac_size; i++) {
  320         if (mc->basic_hash.value[i] != mac[i]) j++;
  321     }
  322     if (j == 0) res = true;
  323 
  324 done:
  325     if (res == false) {
  326         mc->basic_hash.value = NULL;
  327         mc->basic_hash.length = 0;
  328     }
  329     return res;
  330 }
  331 
  332 void mag_basic_cache(struct mag_req_cfg *cfg, struct mag_conn *mc,
  333                      gss_buffer_desc user, gss_buffer_desc pwd)
  334 {
  335     int mac_size = mag_get_mac_size(cfg);
  336     unsigned char mac[mac_size];
  337     int ret;
  338 
  339     ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd);
  340     if (ret != 0) return;
  341 
  342     mc->basic_hash.length = mac_size;
  343     mc->basic_hash.value = apr_palloc(mc->pool, mac_size);
  344     memcpy(mc->basic_hash.value, mac, mac_size);
  345 }