summaryrefslogtreecommitdiffstats
path: root/src/sessions.c
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2015-05-05 16:55:33 -0400
committerSimo Sorce <simo@redhat.com>2015-05-05 16:55:33 -0400
commit675e965f6449922ae1354012bb78b7df2e00e33d (patch)
treebc5561297b199b5327e38877242ea53e60c1cb97 /src/sessions.c
parent219c9b85f4a4ae04d6578384ba7ff37e3b3f113d (diff)
downloadmod_auth_gssapi-client_reauth.tar.gz
mod_auth_gssapi-client_reauth.tar.xz
mod_auth_gssapi-client_reauth.zip
Pack session dataclient_reauth
This prevent any parsing ambiguity and also allow to easily expand the data saved by simply adding more fields when packing the data.
Diffstat (limited to 'src/sessions.c')
-rw-r--r--src/sessions.c221
1 files changed, 192 insertions, 29 deletions
diff --git a/src/sessions.c b/src/sessions.c
index e3a8785..b09a181 100644
--- a/src/sessions.c
+++ b/src/sessions.c
@@ -41,6 +41,188 @@ static apr_status_t mag_session_set(request_rec *req, session_rec *sess,
return DECLINED;
}
+
+/* Format, simple 32bit word based scheme:
+ * the first byte is the data identifier,
+ * the next three bytes are the length in big endian for strings,
+ * or the value for small integers and boolean data.
+ *
+ * identifiers:
+ *
+ * 0xFF reserved
+ * 0x00 reserved
+ * 0x01 established (boolean)
+ * 0x10 user name (string)
+ * 0x11 gss name (string)
+ * 0x20 expiration (large integer)
+ * */
+#define EST 0x01
+#define USR 0x10
+#define GSS 0x11
+#define AUT 0x12
+#define EXP 0x20
+
+#define IDMASK 0x00ffffff
+
+static apr_status_t mag_unpack_string(apr_pool_t *pool, struct databuf *plain,
+ uint32_t word, size_t *pos,
+ const char **dest)
+{
+ char *data;
+ uint32_t len;
+
+ len = be32toh(word & IDMASK);
+ if (len > (plain->length - *pos)) return APR_EINVAL;
+
+ data = (char *)&plain->value[*pos];
+ *pos += len;
+
+ *dest = apr_pstrndup(pool, data, len);
+ if (!*dest) return APR_ENOMEM;
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t mag_unpack_session(struct databuf *plain,
+ struct mag_conn *mc)
+{
+ apr_status_t ret = APR_SUCCESS;
+ size_t pos = 0;
+ uint32_t word;
+ uint64_t exp;
+ uint8_t id;
+
+ while (pos < plain->length) {
+ memcpy(&word, &plain->value[pos], 4);
+ pos += 4;
+ id = word >> 24;
+ switch (id) {
+ case EST:
+ mc->established = (be32toh(word & IDMASK) == 1);
+ break;
+ case USR:
+ ret = mag_unpack_string(mc->parent, plain, word,
+ &pos, &mc->user_name);
+ if (ret != APR_SUCCESS) goto done;
+ break;
+ case GSS:
+ ret = mag_unpack_string(mc->parent, plain, word,
+ &pos, &mc->gss_name);
+ if (ret != APR_SUCCESS) goto done;
+ break;
+ case AUT:
+ ret = mag_unpack_string(mc->parent, plain, word,
+ &pos, &mc->auth_type);
+ if (ret != APR_SUCCESS) goto done;
+ break;
+ case EXP:
+ if (((word & IDMASK) != 8) ||
+ ((plain->length - pos) < 8)) {
+ ret = APR_EINVAL;
+ goto done;
+ }
+ memcpy(&exp, &plain->value[pos], 8);
+ mc->expiration = be64toh(exp);
+ pos += 8;
+ break;
+ default:
+ ret = APR_EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ if (ret != APR_SUCCESS) {
+ /* wipe mc to avoid returning partial data */
+ memset(mc, 0, sizeof(struct mag_conn));
+ }
+ return ret;
+}
+
+static apr_status_t mag_pack_string(struct databuf *plain, char id,
+ size_t maxlen, size_t *pos,
+ const char *src)
+{
+ uint32_t len = strlen(src);
+ uint32_t word;
+
+ /* skip if zero length */
+ if (len == 0) return APR_SUCCESS;
+ if (len > IDMASK) return APR_EINVAL;
+ if (maxlen < (*pos + len + 4)) return APR_EINVAL;
+ word = id << 24;
+ word |= (htobe32(len) & IDMASK);
+ memcpy(&plain->value[*pos], &word, 4);
+ *pos += 4;
+ memcpy(&plain->value[*pos], src, len);
+ *pos += len;
+ return APR_SUCCESS;
+}
+
+static apr_status_t mag_pack_session(struct mag_conn *mc,
+ apr_pool_t *pool,
+ struct databuf *plain)
+{
+ apr_status_t ret;
+ size_t maxlen;
+ uint32_t word;
+ uint64_t exp;
+ size_t pos = 0;
+
+ /* 5 fields */
+ maxlen = 5 * sizeof(uint32_t);
+ /* expiration */
+ maxlen += sizeof(uint64_t);
+ /* string values */
+ if (mc->user_name)
+ maxlen += strlen(mc->user_name);
+ if (mc->gss_name)
+ maxlen += strlen(mc->gss_name);
+ if (mc->auth_type)
+ maxlen += strlen(mc->auth_type);
+
+ plain->value = apr_pcalloc(pool, maxlen);
+ if (!plain->value) return APR_ENOMEM;
+
+ /* established */
+ if (maxlen < (pos + 4)) return APR_EINVAL;
+ word = EST << 24;
+ if (mc->established) {
+ word |= (htobe32(1) & IDMASK);
+ }
+ memcpy(&plain->value[pos], &word, 4);
+ pos += 4;
+
+ /* expiration */
+ if (maxlen < (pos + 12)) return APR_EINVAL;
+ word = EXP << 24;
+ word |= (htobe32(8) & IDMASK);
+ memcpy(&plain->value[pos], &word, 4);
+ pos += 4;
+ exp = htobe64((uint64_t)mc->expiration);
+ memcpy(&plain->value[pos], &exp, 8);
+ pos += 8;
+
+ /* string values */
+ if (mc->user_name) {
+ ret = mag_pack_string(plain, USR, maxlen, &pos, mc->user_name);
+ if (ret != APR_SUCCESS) return ret;
+ }
+
+ if (mc->gss_name) {
+ ret = mag_pack_string(plain, GSS, maxlen, &pos, mc->gss_name);
+ if (ret != APR_SUCCESS) return ret;
+ }
+
+ if (mc->auth_type) {
+ ret = mag_pack_string(plain, AUT, maxlen, &pos, mc->auth_type);
+ if (ret != APR_SUCCESS) return ret;
+ }
+
+ plain->length = pos;
+ return APR_SUCCESS;
+}
+
#define MAG_BEARER_KEY "MagBearerToken"
void mag_check_session(request_rec *req,
@@ -53,8 +235,6 @@ void mag_check_session(request_rec *req,
int declen;
struct databuf ctxbuf = { 0 };
struct databuf cipherbuf = { 0 };
- char *next, *last;
- time_t expiration;
rc = mag_session_load(req, &sess);
if (rc != OK || sess == NULL) {
@@ -103,34 +283,17 @@ void mag_check_session(request_rec *req,
return;
}
- /* get time */
- next = apr_strtok((char *)ctxbuf.value, ":", &last);
- expiration = (time_t)apr_atoi64(next);
- if (expiration < time(NULL)) {
- /* credentials fully expired, return nothing */
- return;
+ rc = mag_unpack_session(&ctxbuf, mc);
+ if (rc != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to parse session data!");
}
-
- /* user name is next */
- next = apr_strtok(NULL, ":", &last);
- mc->user_name = apr_pstrdup(mc->parent, next);
- if (!mc->user_name) return;
-
- /* gssapi name (often a principal) is last.
- * (because it may contain the separator as a valid char we
- * just read last as is, without further tokenizing */
- mc->gss_name = apr_pstrdup(mc->parent, last);
- if (!mc->gss_name) return;
-
- /* OK we have a valid token */
- mc->established = true;
}
void mag_attempt_session(request_rec *req,
struct mag_config *cfg, struct mag_conn *mc)
{
session_rec *sess = NULL;
- char *sessval = NULL;
struct databuf plainbuf = { 0 };
struct databuf cipherbuf = { 0 };
struct databuf ctxbuf = { 0 };
@@ -157,12 +320,12 @@ void mag_attempt_session(request_rec *req,
}
}
- sessval = apr_psprintf(req->pool, "%ld:%s:%s",
- (long)mc->expiration, mc->user_name, mc->gss_name);
- if (!sessval) return;
-
- plainbuf.length = strlen(sessval) + 1;
- plainbuf.value = (unsigned char *)sessval;
+ rc = mag_pack_session(mc, req->pool, &plainbuf);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to package session data!");
+ return;
+ }
rc = SEAL_BUFFER(req->pool, cfg->mag_skey, &plainbuf, &cipherbuf);
if (rc != OK) {