session.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright (c) 2018 Markus Hennecke <markus-hennecke@markus-hennecke.de>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <sys/types.h>
  17. #include <fcntl.h>
  18. #include <limits.h>
  19. #include <db.h>
  20. #include <err.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <time.h>
  25. #include "session.h"
  26. static const char b64[] =
  27. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  28. "abcdefghijklmnopqrstuvwxyz"
  29. "0123456789+/";
  30. static size_t
  31. base64len(size_t _len)
  32. {
  33. return((_len + 2) / 3 * 4) + 1;
  34. }
  35. static size_t
  36. base64buf(char *_enc, const char *_str, size_t _len)
  37. {
  38. size_t i;
  39. char *p;
  40. p = _enc;
  41. for (i = 0; i < _len - 2; i += 3) {
  42. *p++ = b64[(_str[i] >> 2) & 0x3F];
  43. *p++ = b64[((_str[i] & 0x3) << 4) |
  44. ((int)(_str[i + 1] & 0xF0) >> 4)];
  45. *p++ = b64[((_str[i + 1] & 0xF) << 2) |
  46. ((int)(_str[i + 2] & 0xC0) >> 6)];
  47. *p++ = b64[_str[i + 2] & 0x3F];
  48. }
  49. if (i < _len) {
  50. *p++ = b64[(_str[i] >> 2) & 0x3F];
  51. if (i == (_len - 1)) {
  52. *p++ = b64[((_str[i] & 0x3) << 4)];
  53. *p++ = '=';
  54. } else {
  55. *p++ = b64[((_str[i] & 0x3) << 4) |
  56. ((int)(_str[i + 1] & 0xF0) >> 4)];
  57. *p++ = b64[((_str[i + 1] & 0xF) << 2)];
  58. }
  59. *p++ = '=';
  60. }
  61. *p++ = '\0';
  62. return(p - _enc);
  63. }
  64. struct session_data *
  65. session_data_new(void)
  66. {
  67. struct session_data *sd = calloc(1, sizeof(struct session_data));
  68. if (sd == NULL)
  69. err(1, NULL);
  70. sd->timeout = time(NULL) + 60 * 30;
  71. return sd;
  72. }
  73. bool
  74. session_data_timeout(struct session_data *_s)
  75. {
  76. time_t now = time(NULL);
  77. return (now > _s->timeout);
  78. }
  79. struct session *
  80. session_new(void)
  81. {
  82. char id[15];
  83. struct session *s = calloc(1, sizeof(struct session));
  84. if (s == NULL)
  85. err(1, NULL);
  86. s->data.timeout = time(NULL) + 60 * 30;
  87. arc4random_buf(id, sizeof(id));
  88. s->sid = malloc(base64len(sizeof(id)));
  89. base64buf(s->sid, id, sizeof(id));
  90. return s;
  91. }
  92. void
  93. session_free(struct session *_s)
  94. {
  95. if (_s) {
  96. free(_s->sid);
  97. free(_s);
  98. }
  99. }
  100. bool
  101. session_save(struct session *_s, struct session_store *_store,
  102. bool _new)
  103. {
  104. DBT key = { _s->sid, strlen(_s->sid) };
  105. DBT data = { &_s->data, sizeof(struct session_data) };
  106. int rc = _store->db->put(_store->db, &key, &data,
  107. (_new) ? R_NOOVERWRITE : 0);
  108. if (rc == -1)
  109. err(1, NULL);
  110. else if (_new && (rc == 1)) {
  111. errx(1, "Duplicate session key");
  112. }
  113. return true;
  114. }
  115. struct session *
  116. session_load(char *_sid, struct session_store *_store)
  117. {
  118. DBT key = { _sid, strlen(_sid) };
  119. struct session *s = calloc(1, sizeof(struct session));
  120. if (s == NULL)
  121. err(1, NULL);
  122. DBT data;
  123. int rc = _store->db->get(_store->db, &key, &data, 0);
  124. if (rc == -1)
  125. err(1, NULL);
  126. else if (rc == 1) {
  127. session_free(s);
  128. s = NULL;
  129. } else {
  130. memcpy(&s->data, data.data, sizeof(struct session_data));
  131. s->sid = strdup(_sid);
  132. }
  133. return s;
  134. }
  135. struct session_store *
  136. session_store_new(const char *_filename)
  137. {
  138. struct session_store *store = malloc(sizeof(struct session_store));
  139. if (store == NULL)
  140. err(1, NULL);
  141. store->db = dbopen(_filename, O_CREAT | O_RDWR | O_SHLOCK, 0600,
  142. DB_HASH, NULL);
  143. if (store->db == NULL)
  144. err(1, "%s", _filename);
  145. store->filename = strdup(_filename);
  146. return store;
  147. }
  148. void
  149. session_store_free(struct session_store *_store)
  150. {
  151. if (_store && _store->db) {
  152. _store->db->close(_store->db);
  153. free(_store->filename);
  154. }
  155. free(_store);
  156. }
  157. void
  158. session_store_cleanup(struct session_store *_s)
  159. {
  160. int rc;
  161. DBT key, data;
  162. while ((rc = _s->db->seq(_s->db, &key, &data, R_NEXT)) == 0) {
  163. if (session_data_timeout(data.data)) {
  164. if (-1 == _s->db->del(_s->db, &key, R_CURSOR)) {
  165. warn(NULL);
  166. }
  167. }
  168. #if 0
  169. else {
  170. struct session_data *d
  171. = (struct session_data *)data.data;
  172. warnx("Session %.*s expires in %d seconds",
  173. (int )key.size,
  174. key.data, (
  175. int )(d->timeout - time(NULL)));
  176. }
  177. #endif
  178. }
  179. if (rc == -1)
  180. warn(NULL);
  181. }