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