1086505869397c36af6c4ce51fb1007a3d5dc922
[mod_auth_gssapi.git] / src / sessions.c
1 /* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */
2
3 #include "mod_auth_gssapi.h"
4
5 static APR_OPTIONAL_FN_TYPE(ap_session_load) *mag_sess_load_fn = NULL;
6 static APR_OPTIONAL_FN_TYPE(ap_session_get) *mag_sess_get_fn = NULL;
7 static APR_OPTIONAL_FN_TYPE(ap_session_set) *mag_sess_set_fn = NULL;
8
9 void mag_post_config_session(void)
10 {
11     mag_sess_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load);
12     mag_sess_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get);
13     mag_sess_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set);
14 }
15
16 static apr_status_t mag_session_load(request_rec *req, session_rec **sess)
17 {
18     if (mag_sess_load_fn) {
19         return mag_sess_load_fn(req, sess);
20     }
21     return DECLINED;
22 }
23
24 static apr_status_t mag_session_get(request_rec *req, session_rec *sess,
25                                     const char *key, const char **value)
26 {
27     if (mag_sess_get_fn) {
28         return mag_sess_get_fn(req, sess, key, value);
29     }
30     return DECLINED;
31 }
32
33 static apr_status_t mag_session_set(request_rec *req, session_rec *sess,
34                                     const char *key, const char *value)
35 {
36     if (mag_sess_set_fn) {
37         return mag_sess_set_fn(req, sess, key, value);
38     }
39     return DECLINED;
40 }
41
42 #define MAG_BEARER_KEY "MagBearerToken"
43
44 void mag_check_session(request_rec *req,
45                        struct mag_config *cfg, struct mag_conn **conn)
46 {
47     struct mag_conn *mc;
48     apr_status_t rc;
49     session_rec *sess = NULL;
50     const char *sessval = NULL;
51     int declen;
52     struct databuf ctxbuf = { 0 };
53     struct databuf cipherbuf = { 0 };
54     char *next, *last;
55     time_t expiration;
56
57     rc = mag_session_load(req, &sess);
58     if (rc != OK || sess == NULL) {
59         ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req,
60                       "Sessions not available, no cookies!");
61         return;
62     }
63
64     mc = *conn;
65     if (!mc) {
66         mc = apr_pcalloc(req->pool, sizeof(struct mag_conn));
67         if (!mc) return;
68
69         mc->parent = req->pool;
70         *conn = mc;
71     }
72
73     rc = mag_session_get(req, sess, MAG_BEARER_KEY, &sessval);
74     if (rc != OK) {
75         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
76                       "Failed to get session data!");
77         return;
78     }
79     if (!sessval) {
80         /* no session established, just return */
81         return;
82     }
83
84     if (!cfg->mag_skey) {
85         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
86                       "Session key not available, no cookies!");
87         /* we do not have a key, just return */
88         return;
89     }
90
91     /* decode it */
92     declen = apr_base64_decode_len(sessval);
93     cipherbuf.value = apr_palloc(req->pool, declen);
94     if (!cipherbuf.value) return;
95     cipherbuf.length = (int)apr_base64_decode((char *)cipherbuf.value, sessval);
96
97     rc = UNSEAL_BUFFER(req->pool, cfg->mag_skey, &cipherbuf, &ctxbuf);
98     if (rc != OK) {
99         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
100                       "Failed to unseal session data!");
101         return;
102     }
103
104     /* get time */
105     next = apr_strtok((char *)ctxbuf.value, ":", &last);
106     expiration = (time_t)apr_atoi64(next);
107     if (expiration < time(NULL)) {
108         /* credentials fully expired, return nothing */
109         return;
110     }
111
112     /* user name is next */
113     next = apr_strtok(NULL, ":", &last);
114     mc->user_name = apr_pstrdup(mc->parent, next);
115     if (!mc->user_name) return;
116
117     /* gssapi name (often a principal) is last.
118      * (because it may contain the separator as a valid char we
119      * just read last as is, without further tokenizing */
120     mc->gss_name = apr_pstrdup(mc->parent, last);
121     if (!mc->gss_name) return;
122
123     /* OK we have a valid token */
124     mc->established = true;
125 }
126
127 void mag_attempt_session(request_rec *req,
128                          struct mag_config *cfg, struct mag_conn *mc)
129 {
130     session_rec *sess = NULL;
131     char *sessval = NULL;
132     struct databuf plainbuf = { 0 };
133     struct databuf cipherbuf = { 0 };
134     struct databuf ctxbuf = { 0 };
135     apr_status_t rc;
136
137     /* we save the session only if the authentication is established */
138
139     if (!mc->established) return;
140     rc = mag_session_load(req, &sess);
141     if (rc != OK || sess == NULL) {
142         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
143                       "Sessions not available, can't send cookies!");
144         return;
145     }
146
147     if (!cfg->mag_skey) {
148         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
149                       "Session key not available, generating new one.");
150         rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, NULL);
151         if (rc != OK) {
152             ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
153                           "Failed to create sealing key!");
154             return;
155         }
156     }
157
158     sessval = apr_psprintf(req->pool, "%ld:%s:%s",
159                            (long)mc->expiration, mc->user_name, mc->gss_name);
160     if (!sessval) return;
161
162     plainbuf.length = strlen(sessval) + 1;
163     plainbuf.value = (unsigned char *)sessval;
164
165     rc = SEAL_BUFFER(req->pool, cfg->mag_skey, &plainbuf, &cipherbuf);
166     if (rc != OK) {
167         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
168                       "Failed to seal session data!");
169         return;
170     }
171
172     ctxbuf.length = apr_base64_encode_len(cipherbuf.length);
173     ctxbuf.value = apr_pcalloc(req->pool, ctxbuf.length);
174     if (!ctxbuf.value) return;
175
176     ctxbuf.length = apr_base64_encode((char *)ctxbuf.value,
177                                       (char *)cipherbuf.value,
178                                       cipherbuf.length);
179
180     rc = mag_session_set(req, sess, MAG_BEARER_KEY, (char *)ctxbuf.value);
181     if (rc != OK) {
182         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
183                       "Failed to set session data!");
184         return;
185     }
186 }
187