1 /*
2 * Copyright (C) 2013 Nikos Mavrogiannopoulos
3 *
4 * This file is part of ocserv.
5 *
6 * ocserv is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * ocserv is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21
22 #include <gnutls/gnutls.h>
23 #include <gnutls/crypto.h>
24 #include <gnutls/x509.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35
36 #include <vpn.h>
37 #include <worker.h>
38 #include "common.h"
39 #include "ipc.pb-c.h"
40 #include <tlslib.h>
41
42
recv_resume_fetch_reply(worker_st * ws,int sd,gnutls_datum_t * sdata)43 static int recv_resume_fetch_reply(worker_st *ws, int sd, gnutls_datum_t *sdata)
44 {
45 int ret;
46 SessionResumeReplyMsg *resp;
47 PROTOBUF_ALLOCATOR(pa, ws);
48
49 ret = recv_msg(ws, sd, RESUME_FETCH_REP, (void*)&resp,
50 (unpack_func)session_resume_reply_msg__unpack, DEFAULT_SOCKET_TIMEOUT);
51 if (ret < 0) {
52 oclog(ws, LOG_ERR, "error receiving resumption reply (fetch)");
53 return ret;
54 }
55
56 if (resp->reply != SESSION_RESUME_REPLY_MSG__RESUME__REP__OK) {
57 ret = -1;
58 goto cleanup;
59 }
60
61 sdata->data = gnutls_malloc(resp->session_data.len);
62 if (sdata->data == NULL) {
63 ret = -1;
64 goto cleanup;
65 }
66
67 sdata->size = resp->session_data.len;
68 memcpy(sdata->data, resp->session_data.data, sdata->size);
69
70 ret = 0;
71 cleanup:
72 session_resume_reply_msg__free_unpacked(resp, &pa);
73
74 return ret;
75 }
76
77 /* sends an authentication request to main thread and waits for
78 * a reply.
79 * Returns 0 on success.
80 */
resume_db_fetch(void * dbf,gnutls_datum_t key)81 static gnutls_datum_t resume_db_fetch(void *dbf, gnutls_datum_t key)
82 {
83 worker_st *ws = dbf;
84 gnutls_datum_t r = { NULL, 0 };
85 int ret, sd;
86 SessionResumeFetchMsg msg = SESSION_RESUME_FETCH_MSG__INIT;
87
88 if (key.size > GNUTLS_MAX_SESSION_ID) {
89 oclog(ws, LOG_DEBUG, "session ID size exceeds the maximum %u", key.size);
90 return r;
91 }
92
93 sd = connect_to_secmod(ws);
94 if (sd == -1) {
95 oclog(ws, LOG_DEBUG, "cannot connect to secmod");
96 return r;
97 }
98
99 msg.session_id.len = key.size;
100 msg.session_id.data = key.data;
101 msg.cli_addr.len = ws->remote_addr_len;
102 msg.cli_addr.data = (void*)&ws->remote_addr;
103 msg.vhost = ws->vhost->name;
104
105 ret = send_msg_to_secmod(ws, sd, RESUME_FETCH_REQ, &msg,
106 (pack_size_func)session_resume_fetch_msg__get_packed_size,
107 (pack_func)session_resume_fetch_msg__pack);
108 if (ret < 0) {
109 goto cleanup;
110 }
111
112 recv_resume_fetch_reply(ws, sd, &r);
113
114 cleanup:
115 close(sd);
116 return r;
117 }
118
119
120 static int
resume_db_store(void * dbf,gnutls_datum_t key,gnutls_datum_t data)121 resume_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
122 {
123 worker_st *ws = dbf;
124 SessionResumeStoreReqMsg msg = SESSION_RESUME_STORE_REQ_MSG__INIT;
125 int ret, sd;
126
127 if (data.size > MAX_SESSION_DATA_SIZE) {
128 oclog(ws, LOG_DEBUG, "session data size exceeds the maximum %u", data.size);
129 return GNUTLS_E_DB_ERROR;
130 }
131
132 if (key.size > GNUTLS_MAX_SESSION_ID) {
133 oclog(ws, LOG_DEBUG, "session ID size exceeds the maximum %u", key.size);
134 return GNUTLS_E_DB_ERROR;
135 }
136
137 msg.session_id.len = key.size;
138 msg.session_data.len = data.size;
139
140 msg.session_id.data = key.data;
141 msg.session_data.data = data.data;
142
143 msg.cli_addr.len = ws->remote_addr_len;
144 msg.cli_addr.data = (void*)&ws->remote_addr;
145
146 msg.vhost = ws->vhost->name;
147
148 sd = connect_to_secmod(ws);
149 if (sd == -1) {
150 oclog(ws, LOG_DEBUG, "cannot connect to secmod");
151 return GNUTLS_E_DB_ERROR;
152 }
153
154 ret = send_msg_to_secmod(ws, sd, RESUME_STORE_REQ, &msg,
155 (pack_size_func)session_resume_store_req_msg__get_packed_size,
156 (pack_func)session_resume_store_req_msg__pack);
157
158 close(sd);
159
160 if (ret < 0) {
161 return GNUTLS_E_DB_ERROR;
162 }
163
164 return 0;
165 }
166
167 /* sends an authentication request to main thread and waits for
168 * a reply.
169 * Returns 0 on success.
170 */
resume_db_delete(void * dbf,gnutls_datum_t key)171 static int resume_db_delete(void *dbf, gnutls_datum_t key)
172 {
173 worker_st *ws = dbf;
174 int ret, sd;
175 SessionResumeFetchMsg msg = SESSION_RESUME_FETCH_MSG__INIT;
176
177 if (key.size > GNUTLS_MAX_SESSION_ID) {
178 oclog(ws, LOG_DEBUG, "Session ID size exceeds the maximum %u", key.size);
179 return GNUTLS_E_DB_ERROR;
180 }
181
182 msg.session_id.len = key.size;
183 msg.session_id.data = key.data;
184
185 sd = connect_to_secmod(ws);
186 if (sd == -1) {
187 oclog(ws, LOG_DEBUG, "cannot connect to secmod");
188 return GNUTLS_E_DB_ERROR;
189 }
190
191 ret = send_msg_to_secmod(ws, sd, RESUME_DELETE_REQ, &msg,
192 (pack_size_func)session_resume_fetch_msg__get_packed_size,
193 (pack_func)session_resume_fetch_msg__pack);
194
195 close(sd);
196 if (ret < 0)
197 return GNUTLS_E_DB_ERROR;
198
199 return 0;
200 }
201
set_resume_db_funcs(gnutls_session_t session)202 void set_resume_db_funcs(gnutls_session_t session)
203 {
204 gnutls_db_set_retrieve_function (session, resume_db_fetch);
205 gnutls_db_set_remove_function (session, resume_db_delete);
206 gnutls_db_set_store_function (session, resume_db_store);
207 }
208