summaryrefslogtreecommitdiffstats
path: root/plugin/eurephiadb_session.c
blob: 58e93db439dedae54f62327691d2fe165dfd1dc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* eurephiadb_session.c  --  Functions for handling sessions from eurephia-auth
 *
 *  GPLv2 - Copyright (C) 2008  David Sommerseth <dazo@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; version 2
 *  of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define EUREPHIA_FWINTF
#include <eurephiafw_struct.h>
#include <eurephia_context.h>
#include "eurephia_nullsafe.h"
#include "eurephia_log.h"
#include "eurephiadb_session.h"
#include <eurephiadb_session_common.h>
#include "sha512.h"


// Also defined in the eurephiadb_driver.h, but not as extern.
extern char *(*eDBget_sessionkey_seed) (eurephiaCTX *ctx, sessionType type, const char *sessionseed);
extern char *(*eDBget_sessionkey_macaddr) (eurephiaCTX *ctx, const char *macaddr);

extern int (*eDBcheck_sessionkey_uniqueness) (eurephiaCTX *ctx, const char *seskey);

extern int (*eDBregister_sessionkey) (eurephiaCTX *ctx, const char *seed, const char *seskey);

extern eurephiaVALUES *(*eDBload_sessiondata) (eurephiaCTX *ctx, const char *sesskey);

// Generates a new session structure.  Session key will be created if session seed (input params) are not known.
// If session seed is known, the already generated session key will be used.
eurephiaSESSION *eDBopen_session_seed(eurephiaCTX *ctx, const char *digest,
                                      const char *cname, const char *username,
                                      const char *vpnipaddr, const char *vpnipmask,
                                      const char *remipaddr, const char *remport)
{
        eurephiaSESSION *new_session = NULL;
        char *seeddata = NULL, *seed = NULL, *ptr = NULL;
        SHA512Context sha;
        uint8_t sha_res[SHA512_HASH_SIZE];
        int totlen = 0, i = 0;

        DEBUG(ctx, 12, "Function call: eDBopen_session_seed(ctx, '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
              digest, cname, username, vpnipaddr, vpnipmask, remipaddr, remport);

        new_session = (eurephiaSESSION *) malloc(sizeof(eurephiaSESSION) + 2);
        if( new_session == NULL ) {
                eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session");
                return NULL;
        }
        memset(new_session, 0, sizeof(eurephiaSESSION) + 2);

        // Session type is stSESSION if we do have VPN address and/or netmask
        new_session->type = ((vpnipaddr == NULL) && (vpnipmask == NULL) ? stAUTHENTICATION : stSESSION);

        // Build up a string containing all elements for the session seed
        totlen = strlen_nullsafe(digest) + strlen_nullsafe(cname) + strlen_nullsafe(username)
                + strlen_nullsafe(vpnipaddr) + strlen_nullsafe(vpnipmask) + strlen_nullsafe(remipaddr)
                + strlen_nullsafe(remport) + 20; // +5 == len(pid) + 15 extra buffer if some strings are (null)

        seeddata = (char *) malloc((totlen * 2) + 4);
        if( seeddata == NULL ) {
                eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session key (1)");
                free_nullsafe(new_session);
                return NULL;
        }
        memset(seeddata, 0, (totlen * 2) + 4);
        snprintf((char *)seeddata, totlen,
                 "%s%s%s%s%s%s%s%i", digest, cname, username, vpnipaddr, vpnipmask, remipaddr, remport,getpid());

        // Generate a SHA512 version of session seed
        memset(&sha, 0, sizeof(SHA512Context));
        memset(&sha_res, 0, sizeof(sha_res));
        SHA512Init(&sha);
        SHA512Update(&sha, seeddata, totlen);
        SHA512Final(&sha, sha_res);

        seed = (char *) malloc((SHA512_HASH_SIZE*2)+3);
        if( seed == NULL ) {
                eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for session seed");
                free_nullsafe(seeddata);
                free_nullsafe(new_session);
                return NULL;
        }
        memset(seed, 0, (SHA512_HASH_SIZE*2)+2);
        ptr = seed;

        for( i = 0; i < SHA512_HASH_SIZE; i++ ) {
                sprintf(ptr, "%02x", sha_res[i]);
                ptr += 2;
        }
        memset(&sha, 0, sizeof(SHA512Context));
        memset(&sha_res, 0, sizeof(sha_res));

        DEBUG(ctx, 13, "Using session seed '%s'", seed);

        // Try to retrieve the sessionkey from the database, based on the session seed
        new_session->sessionkey = eDBget_sessionkey_seed(ctx, new_session->type, seed);
        if( new_session->sessionkey == NULL ) {
                // ... if we do not find a sessionkey ... lets generate one
                int rndlen = 0;
                char *rndstr = NULL;
                char *skeydata = NULL;
                int loop = 0, uniqcheck = 0;

                DEBUG(ctx, 13, "Unknown session seed, creating new session key");

                // Loop until we get a unique sessionkey - don't loop more than 10 times
                skeydata = (char *) malloc((totlen*2)+4);
                if( skeydata == NULL ) {
                        eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for new session key data");
                        free_nullsafe(new_session->sessionkey);
                        free_nullsafe(new_session);
                        free_nullsafe(seeddata);
                        free_nullsafe(seed);
                        return NULL;
                }
                do {
                        memset(skeydata, 0, (totlen*2)+4);

		// FIXME:  Validate that we have enough random data for the session key

                        // Append some random data to our session seed
                        rndstr = (char *) malloc((totlen * 2));
                        if( rndstr == NULL ) {
                                eurephia_log(ctx, LOG_PANIC, 0,
                                             "Could not allocate memory for new session key data (2)");
                                free_nullsafe(new_session->sessionkey);
                                free_nullsafe(new_session);
                                free_nullsafe(seeddata);
                                free_nullsafe(seed);
                                return NULL;
                        }
                        memset(rndstr, 0, (totlen * 2));
                        rndlen = ((totlen * 2) - strlen_nullsafe(seed) - 2);

                        if( !eDBsessionGetRandString(ctx, rndstr, rndlen) ) {
                                eurephia_log(ctx, LOG_PANIC, 0,
                                             "Could not generate enough random data for session key");
                                free_nullsafe(new_session->sessionkey);
                                free_nullsafe(new_session);
                                free_nullsafe(seeddata);
                                free_nullsafe(seed);
                                return NULL;
                        }

                        // Generate SHA512 version of the session data
                        SHA512Init(&sha);
                        SHA512Update(&sha, rndstr, rndlen);
                        SHA512Final(&sha, sha_res);

                        free_nullsafe(new_session->sessionkey);
                        new_session->sessionkey = (char *) malloc((SHA512_HASH_SIZE*2)+3);
                        if( new_session->sessionkey == NULL ) {
                                eurephia_log(ctx, LOG_PANIC, 0,
                                             "Could not allocate memory for new session key");
                                free_nullsafe(new_session);
                                free_nullsafe(seeddata);
                                free_nullsafe(seed);
                                return NULL;
                        }
                        memset(new_session->sessionkey, 0, (SHA512_HASH_SIZE*2)+3);

                        ptr = new_session->sessionkey;
                        for( i = 0; i < SHA512_HASH_SIZE; i++ ) {
                                sprintf(ptr, "%02x", sha_res[i]);
                                ptr += 2;
                        }
                        memset(&sha, 0, sizeof(SHA512Context));
                        memset(&sha_res, 0, sizeof(sha_res));
                        free_nullsafe(rndstr);

                        loop++;
                        uniqcheck = eDBcheck_sessionkey_uniqueness(ctx, new_session->sessionkey);
                } while( (uniqcheck == 0) && loop < 11 );
                free_nullsafe(skeydata);

                // If we did not manage to create a unique session key (random data collection must have failed!)
                if( uniqcheck == 0 ) {
                        eurephia_log(ctx, LOG_FATAL, 0,
                                     "Did not manage to create a unique sessionkey after %i attempts", loop-1);
                        free_nullsafe(new_session->sessionkey);
                        free_nullsafe(new_session);
                        free_nullsafe(seeddata);
                        free_nullsafe(seed);
                        return NULL;
                }

                // Save this session key in the database and connect it to this session seed
                if( eDBregister_sessionkey(ctx, seed, new_session->sessionkey) == 0) {
                        eurephia_log(ctx, LOG_FATAL, 0, "Could not register sessionkey");
                        free_nullsafe(new_session->sessionkey);
                        free_nullsafe(new_session);
                        free_nullsafe(seeddata);
                        free_nullsafe(seed);
                        return NULL;
                };
                new_session->sessionstatus = SESSION_NEW;
        } else {
                new_session->sessionstatus = SESSION_EXISTING;
                DEBUG(ctx, 13, "Session seed found, using sessionkey '%s'", new_session->sessionkey);
        }
        free_nullsafe(seed);
        free_nullsafe(seeddata);

        // Load session values from the database
        new_session->sessvals = eDBload_sessiondata(ctx, new_session->sessionkey);

        // Return struct which contains session key and session variables
        return new_session;
}

// Open an existing session based on a MAC address
eurephiaSESSION *eDBopen_session_macaddr(eurephiaCTX *ctx, const char *macaddr) {
        eurephiaSESSION *new_session = NULL;

        DEBUG(ctx, 12, "Function call: eDBopen_session_mac(ctx, '%s')", macaddr);

        new_session = (eurephiaSESSION *) malloc(sizeof(eurephiaSESSION) + 2);
        if( new_session == NULL ) {
                eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session");
                return NULL;
        }
        memset(new_session, 0, sizeof(eurephiaSESSION) + 2);

        new_session->type = stSESSION; // When we have macaddr - this is a stSESSION type of session

        // Get the sessionkey from the database
        new_session->sessionkey = eDBget_sessionkey_macaddr(ctx, macaddr);
        if( new_session->sessionkey == NULL ) {
                eurephia_log(ctx, LOG_CRITICAL, 0, "Could not find an active session for MAC address '%s'",
                             macaddr);
                free_nullsafe(new_session);
                return NULL;
        }
        DEBUG(ctx, 13, "Session seed found, using sessionkey '%s'", new_session->sessionkey);

        // Load session values from the database
        new_session->sessvals = eDBload_sessiondata(ctx, new_session->sessionkey);

        // Return struct which contains the current session
        return new_session;
}