Moved generic RADIUS protocol support to a dedicated libradius
[strongswan.git] / src / libradius / radius_client.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "radius_client.h"
17 #include "radius_server.h"
18
19 #include <unistd.h>
20 #include <errno.h>
21
22 #include <debug.h>
23 #include <utils/host.h>
24 #include <utils/linked_list.h>
25 #include <threading/condvar.h>
26 #include <threading/mutex.h>
27
28 typedef struct private_radius_client_t private_radius_client_t;
29
30 /**
31 * Private data of an radius_client_t object.
32 */
33 struct private_radius_client_t {
34
35 /**
36 * Public radius_client_t interface.
37 */
38 radius_client_t public;
39
40 /**
41 * Selected RADIUS server
42 */
43 radius_server_t *server;
44
45 /**
46 * RADIUS servers State attribute
47 */
48 chunk_t state;
49
50 /**
51 * EAP MSK, from MPPE keys
52 */
53 chunk_t msk;
54 };
55
56 /**
57 * Save the state attribute to include in further request
58 */
59 static void save_state(private_radius_client_t *this, radius_message_t *msg)
60 {
61 enumerator_t *enumerator;
62 int type;
63 chunk_t data;
64
65 enumerator = msg->create_enumerator(msg);
66 while (enumerator->enumerate(enumerator, &type, &data))
67 {
68 if (type == RAT_STATE)
69 {
70 free(this->state.ptr);
71 this->state = chunk_clone(data);
72 enumerator->destroy(enumerator);
73 return;
74 }
75 }
76 enumerator->destroy(enumerator);
77 /* no state attribute found, remove state */
78 chunk_free(&this->state);
79 }
80
81 METHOD(radius_client_t, request, radius_message_t*,
82 private_radius_client_t *this, radius_message_t *req)
83 {
84 char virtual[] = {0x00,0x00,0x00,0x05};
85 radius_socket_t *socket;
86 radius_message_t *res;
87
88 /* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
89 req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
90 /* add our NAS-Identifier */
91 req->add(req, RAT_NAS_IDENTIFIER,
92 this->server->get_nas_identifier(this->server));
93 /* add State attribute, if server sent one */
94 if (this->state.ptr)
95 {
96 req->add(req, RAT_STATE, this->state);
97 }
98 socket = this->server->get_socket(this->server);
99 DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
100 req->get_code(req), this->server->get_name(this->server));
101 res = socket->request(socket, req);
102 if (res)
103 {
104 DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
105 radius_message_code_names, res->get_code(res),
106 this->server->get_name(this->server));
107 save_state(this, res);
108 if (res->get_code(res) == RMC_ACCESS_ACCEPT)
109 {
110 chunk_clear(&this->msk);
111 this->msk = socket->decrypt_msk(socket, req, res);
112 }
113 this->server->put_socket(this->server, socket, TRUE);
114 return res;
115 }
116 this->server->put_socket(this->server, socket, FALSE);
117 return NULL;
118 }
119
120 METHOD(radius_client_t, get_msk, chunk_t,
121 private_radius_client_t *this)
122 {
123 return this->msk;
124 }
125
126 METHOD(radius_client_t, destroy, void,
127 private_radius_client_t *this)
128 {
129 this->server->destroy(this->server);
130 chunk_clear(&this->msk);
131 free(this->state.ptr);
132 free(this);
133 }
134
135 /**
136 * See header
137 */
138 radius_client_t *radius_client_create(radius_server_t *server)
139 {
140 private_radius_client_t *this;
141
142 INIT(this,
143 .public = {
144 .request = _request,
145 .get_msk = _get_msk,
146 .destroy = _destroy,
147 },
148 .server = server,
149 );
150
151 return &this->public;
152 }