Moved host_t and host_resolver_t to a new networking subfolder
[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_config.h"
18
19 #include <unistd.h>
20 #include <errno.h>
21
22 #include <debug.h>
23 #include <networking/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 configuration
42 */
43 radius_config_t *config;
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 chunk_t data;
88
89 /* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
90 req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
91 /* add our NAS-Identifier */
92 req->add(req, RAT_NAS_IDENTIFIER,
93 this->config->get_nas_identifier(this->config));
94 /* add State attribute, if server sent one */
95 if (this->state.ptr)
96 {
97 req->add(req, RAT_STATE, this->state);
98 }
99 socket = this->config->get_socket(this->config);
100 DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
101 req->get_code(req), this->config->get_name(this->config));
102
103 res = socket->request(socket, req);
104 if (res)
105 {
106 DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
107 radius_message_code_names, res->get_code(res),
108 this->config->get_name(this->config));
109 data = res->get_encoding(res);
110 DBG3(DBG_CFG, "%B", &data);
111
112 save_state(this, res);
113 if (res->get_code(res) == RMC_ACCESS_ACCEPT)
114 {
115 chunk_clear(&this->msk);
116 this->msk = socket->decrypt_msk(socket, req, res);
117 }
118 this->config->put_socket(this->config, socket, TRUE);
119 return res;
120 }
121 this->config->put_socket(this->config, socket, FALSE);
122 return NULL;
123 }
124
125 METHOD(radius_client_t, get_msk, chunk_t,
126 private_radius_client_t *this)
127 {
128 return this->msk;
129 }
130
131 METHOD(radius_client_t, destroy, void,
132 private_radius_client_t *this)
133 {
134 this->config->destroy(this->config);
135 chunk_clear(&this->msk);
136 free(this->state.ptr);
137 free(this);
138 }
139
140 /**
141 * See header
142 */
143 radius_client_t *radius_client_create(radius_config_t *config)
144 {
145 private_radius_client_t *this;
146
147 INIT(this,
148 .public = {
149 .request = _request,
150 .get_msk = _get_msk,
151 .destroy = _destroy,
152 },
153 .config = config,
154 );
155
156 return &this->public;
157 }