Send NAS-Port, NAS-IP and Calling/Called-Station-ID in Access-Request
[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 <utils/debug.h>
23 #include <networking/host.h>
24 #include <collections/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 radius_socket_t *socket;
85 radius_message_t *res;
86 chunk_t data;
87
88 /* add our NAS-Identifier */
89 req->add(req, RAT_NAS_IDENTIFIER,
90 this->config->get_nas_identifier(this->config));
91 /* add State attribute, if server sent one */
92 if (this->state.ptr)
93 {
94 req->add(req, RAT_STATE, this->state);
95 }
96 socket = this->config->get_socket(this->config);
97 DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
98 req->get_code(req), this->config->get_name(this->config));
99
100 res = socket->request(socket, req);
101 if (res)
102 {
103 DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
104 radius_message_code_names, res->get_code(res),
105 this->config->get_name(this->config));
106 data = res->get_encoding(res);
107 DBG3(DBG_CFG, "%B", &data);
108
109 save_state(this, res);
110 if (res->get_code(res) == RMC_ACCESS_ACCEPT)
111 {
112 chunk_clear(&this->msk);
113 this->msk = socket->decrypt_msk(socket, req, res);
114 }
115 this->config->put_socket(this->config, socket, TRUE);
116 return res;
117 }
118 this->config->put_socket(this->config, socket, FALSE);
119 return NULL;
120 }
121
122 METHOD(radius_client_t, get_msk, chunk_t,
123 private_radius_client_t *this)
124 {
125 return this->msk;
126 }
127
128 METHOD(radius_client_t, destroy, void,
129 private_radius_client_t *this)
130 {
131 this->config->destroy(this->config);
132 chunk_clear(&this->msk);
133 free(this->state.ptr);
134 free(this);
135 }
136
137 /**
138 * See header
139 */
140 radius_client_t *radius_client_create(radius_config_t *config)
141 {
142 private_radius_client_t *this;
143
144 INIT(this,
145 .public = {
146 .request = _request,
147 .get_msk = _get_msk,
148 .destroy = _destroy,
149 },
150 .config = config,
151 );
152
153 return &this->public;
154 }