/src/freeradius-server/src/protocols/radius/radius.h
Line | Count | Source |
1 | | #pragma once |
2 | | /* |
3 | | * This program is free software; you can redistribute it and/or modify |
4 | | * it under the terms of the GNU General Public License as published by |
5 | | * the Free Software Foundation; either version 2 of the License, or |
6 | | * (at your option) any later version. |
7 | | * |
8 | | * This program is distributed in the hope that it will be useful, |
9 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | * GNU General Public License for more details. |
12 | | * |
13 | | * You should have received a copy of the GNU General Public License |
14 | | * along with this program; if not, write to the Free Software |
15 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
16 | | */ |
17 | | |
18 | | /* |
19 | | * $Id: 1626f0d95d45327f72272ea4fc85a25a0cc74a3a $ |
20 | | * |
21 | | * @file protocols/radius/radius.h |
22 | | * @brief Structures and prototypes for base RADIUS functionality. |
23 | | * |
24 | | * @copyright 1999-2017 The FreeRADIUS server project |
25 | | */ |
26 | | #include <freeradius-devel/radius/defs.h> |
27 | | #include <freeradius-devel/util/packet.h> |
28 | | #include <freeradius-devel/util/rand.h> |
29 | | #include <freeradius-devel/util/log.h> |
30 | | #include <freeradius-devel/util/dbuff.h> |
31 | | #include <freeradius-devel/io/test_point.h> |
32 | | |
33 | | #define RADIUS_AUTH_VECTOR_OFFSET 4 |
34 | 0 | #define RADIUS_HEADER_LENGTH 20 |
35 | 9.24k | #define RADIUS_MAX_STRING_LENGTH 253 |
36 | | #define RADIUS_MAX_TUNNEL_PASSWORD_LENGTH 249 |
37 | 0 | #define RADIUS_AUTH_VECTOR_LENGTH 16 |
38 | | #define RADIUS_MESSAGE_AUTHENTICATOR_LENGTH 16 |
39 | | #define RADIUS_MAX_ATTRIBUTES 255 |
40 | 0 | #define RADIUS_MAX_PACKET_SIZE 4096 |
41 | | |
42 | | #define RADIUS_VENDORPEC_USR 429 |
43 | | #define RADIUS_VENDORPEC_LUCENT 4846 |
44 | | #define RADIUS_VENDORPEC_STARENT 8164 |
45 | | |
46 | | /* |
47 | | * protocols/radius/base.c |
48 | | */ |
49 | | |
50 | | |
51 | 0 | #define FR_RADIUS_PACKET_CODE_VALID(_x) ((_x > 0) && (_x < FR_RADIUS_CODE_MAX)) |
52 | | |
53 | 0 | #define AUTH_PASS_LEN (RADIUS_AUTH_VECTOR_LENGTH) |
54 | | |
55 | | #define FR_TUNNEL_FR_ENC_LENGTH(_x) (2 + 1 + _x + PAD(_x + 1, 16)) |
56 | | |
57 | | /** Control whether Message-Authenticator is required in Access-Requests |
58 | | * |
59 | | * @note Don't change the enum values. They allow efficient bistmasking. |
60 | | */ |
61 | | typedef enum { |
62 | | FR_RADIUS_REQUIRE_MA_NO = 0x00, //!< Do not require Message-Authenticator |
63 | | FR_RADIUS_REQUIRE_MA_YES = 0x01, //!< Require Message-Authenticator |
64 | | FR_RADIUS_REQUIRE_MA_AUTO = 0x02, //!< Only require Message-Authenticator if we've previously |
65 | | ///< received a packet from this client with Message-Authenticator. |
66 | | ///< @note This isn't used by the radius protocol code, but may be used |
67 | | ///< to drive logic in modules. |
68 | | |
69 | | } fr_radius_require_ma_t; |
70 | | |
71 | | /** Control whether Proxy-State is allowed in Access-Requests |
72 | | * |
73 | | * @note Don't change the enum values. They allow efficient bistmasking. |
74 | | */ |
75 | | typedef enum { |
76 | | FR_RADIUS_LIMIT_PROXY_STATE_NO = 0x00, //!< Do not limit Proxy-State. Allow proxy-state to be sent in |
77 | | ///< all packets. |
78 | | FR_RADIUS_LIMIT_PROXY_STATE_YES = 0x01, //!< Limit Proxy-State. Do not allow Proxy-State to be sent in |
79 | | ///< packets which do not have a Message-Authenticator attribute. |
80 | | |
81 | | FR_RADIUS_LIMIT_PROXY_STATE_AUTO = 0x02, //!< Do not allow Proxy-State unless: |
82 | | ///< - All packets received from a client have containted proxy state. |
83 | | ///< - The client has sent a packet with a Message-Authenticator. |
84 | | ///< @note This isn't used by the radius protocol code, but may be used |
85 | | ///< to drive logic in modules. |
86 | | } fr_radius_limit_proxy_state_t; |
87 | | |
88 | | /** Failure reasons */ |
89 | | typedef enum { |
90 | | FR_RADIUS_FAIL_NONE = 0, |
91 | | FR_RADIUS_FAIL_MIN_LENGTH_PACKET, |
92 | | FR_RADIUS_FAIL_MAX_LENGTH_PACKET, |
93 | | FR_RADIUS_FAIL_MIN_LENGTH_FIELD, |
94 | | FR_RADIUS_FAIL_MIN_LENGTH_MISMATCH, |
95 | | FR_RADIUS_FAIL_UNKNOWN_PACKET_CODE, |
96 | | FR_RADIUS_FAIL_UNEXPECTED_REQUEST_CODE, |
97 | | FR_RADIUS_FAIL_UNEXPECTED_RESPONSE_CODE, |
98 | | FR_RADIUS_FAIL_TOO_MANY_ATTRIBUTES, |
99 | | |
100 | | FR_RADIUS_FAIL_INVALID_ATTRIBUTE, |
101 | | |
102 | | FR_RADIUS_FAIL_HEADER_OVERFLOW, |
103 | | FR_RADIUS_FAIL_ATTRIBUTE_TOO_SHORT, |
104 | | FR_RADIUS_FAIL_ATTRIBUTE_OVERFLOW, |
105 | | FR_RADIUS_FAIL_ATTRIBUTE_DECODE, |
106 | | |
107 | | FR_RADIUS_FAIL_MA_INVALID_LENGTH, |
108 | | FR_RADIUS_FAIL_MA_MISSING, |
109 | | FR_RADIUS_FAIL_MA_INVALID, |
110 | | FR_RADIUS_FAIL_MA_TOO_MANY, |
111 | | FR_RADIUS_FAIL_PROXY_STATE_MISSING_MA, |
112 | | |
113 | | FR_RADIUS_FAIL_VERIFY, |
114 | | FR_RADIUS_FAIL_NO_MATCHING_REQUEST, |
115 | | FR_RADIUS_FAIL_IO_ERROR, |
116 | | FR_RADIUS_FAIL_MAX |
117 | | } fr_radius_decode_fail_t; |
118 | | |
119 | | extern char const *fr_radius_decode_fail_reason[FR_RADIUS_FAIL_MAX + 1]; |
120 | | |
121 | | typedef struct { |
122 | | fr_pair_t *parent; |
123 | | fr_dcursor_t cursor; |
124 | | } fr_radius_tag_ctx_t; |
125 | | |
126 | | typedef struct { |
127 | | char const *secret; |
128 | | size_t secret_length; |
129 | | |
130 | | bool secure_transport; //!< for TLS |
131 | | |
132 | | uint64_t proxy_state; |
133 | | } fr_radius_ctx_t; |
134 | | |
135 | | typedef struct { |
136 | | fr_radius_ctx_t const *common; |
137 | | |
138 | | uint8_t const *request_authenticator; |
139 | | |
140 | | fr_fast_rand_t rand_ctx; //!< for tunnel passwords |
141 | | |
142 | | uint8_t tag; //!< current tag for encoding |
143 | | |
144 | | uint8_t request_code; |
145 | | |
146 | | uint8_t code; |
147 | | uint8_t id; |
148 | | |
149 | | bool add_proxy_state; //!< do we add a Proxy-State? |
150 | | bool seen_message_authenticator; |
151 | | bool foreign; //!< are we in a foreign protocol? |
152 | | #ifdef NAS_VIOLATES_RFC |
153 | | bool allow_vulnerable_clients; //!< for vendors who violate the RFCs. |
154 | | #endif |
155 | | |
156 | | } fr_radius_encode_ctx_t; |
157 | | |
158 | | typedef struct { |
159 | | fr_radius_ctx_t const *common; |
160 | | |
161 | | uint8_t const *request_authenticator; |
162 | | |
163 | | TALLOC_CTX *tmp_ctx; //!< for temporary things cleaned up during decoding |
164 | | uint8_t const *end; //!< end of the packet |
165 | | |
166 | | fr_radius_decode_fail_t reason; //!< reason for decode failure |
167 | | |
168 | | uint8_t request_code; //!< original code for the request. |
169 | | |
170 | | bool tunnel_password_zeros; //!< check for trailing zeros on decode |
171 | | bool verify; //!< can skip verify for dynamic clients |
172 | | bool require_message_authenticator; |
173 | | bool limit_proxy_state; //!< Don't allow Proxy-State in requests |
174 | | |
175 | | fr_radius_tag_ctx_t **tags; //!< for decoding tagged attributes |
176 | | fr_pair_list_t *tag_root; //!< Where to insert tag attributes. |
177 | | TALLOC_CTX *tag_root_ctx; //!< Where to allocate new tag attributes. |
178 | | } fr_radius_decode_ctx_t; |
179 | | |
180 | | typedef enum { |
181 | | RADIUS_FLAG_ENCRYPT_INVALID = -1, //!< Invalid encryption flag. |
182 | | RADIUS_FLAG_ENCRYPT_NONE = 0, //!< No encryption. |
183 | | RADIUS_FLAG_ENCRYPT_USER_PASSWORD = 1, //!< Encrypt attribute RFC 2865 style. |
184 | | RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD = 2, //!< Encrypt attribute RFC 2868 style. |
185 | | RADIUS_FLAG_ENCRYPT_ASCEND_SECRET = 3, //!< Encrypt attribute ascend style. |
186 | | } fr_radius_attr_flags_encrypt_t; |
187 | | |
188 | | typedef struct { |
189 | | unsigned int long_extended : 1; //!< Attribute is a long extended attribute |
190 | | unsigned int extended : 1; //!< Attribute is an extended attribute |
191 | | unsigned int concat : 1; //!< Attribute is concatenated |
192 | | unsigned int has_tag : 1; //!< Attribute has a tag |
193 | | unsigned int abinary : 1; //!< Attribute is in "abinary" format |
194 | | fr_radius_attr_flags_encrypt_t encrypt; //!< Attribute is encrypted |
195 | | } fr_radius_attr_flags_t; |
196 | | |
197 | | DIAG_OFF(unused-function) |
198 | | extern fr_dict_protocol_t libfreeradius_radius_dict_protocol; |
199 | | |
200 | | /** Return RADIUS-specific flags for a given attribute |
201 | | * |
202 | | * Assert in debug builds when the attribute belongs to another dictionary, as |
203 | | * the flags of one protocol say nothing about an attribute of another. |
204 | | * |
205 | | * If the attribute does not carry the protocol-specific extension, then assert. |
206 | | * Other builds log the error and return zeroed flags instead of NULL. |
207 | | */ |
208 | | static inline fr_radius_attr_flags_t const * fr_radius_attr_flags(fr_dict_attr_t const *da) |
209 | 0 | { |
210 | 0 | static fr_radius_attr_flags_t const no_flags = {}; |
211 | 0 | fr_radius_attr_flags_t const *flags; |
212 | 0 |
|
213 | 0 | fr_assert_msg(fr_dict_protocol(da->dict) == &libfreeradius_radius_dict_protocol, |
214 | 0 | "%s is not a RADIUS attribute, it is from the \"%s\" dictionary", |
215 | 0 | da->name, fr_dict_root(da->dict)->name); |
216 | 0 |
|
217 | 0 | flags = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); |
218 | 0 | if (!fr_cond_assert_msg(flags, "%s is not a RADIUS attribute, it has no protocol extension", |
219 | 0 | da->name)) return &no_flags; |
220 | 0 |
|
221 | 0 | return flags; |
222 | 0 | } Unexecuted instantiation: list.c:fr_radius_attr_flags Unexecuted instantiation: abinary.c:fr_radius_attr_flags |
223 | | |
224 | | static inline bool fr_radius_flag_has_tag(fr_dict_attr_t const *da) |
225 | 0 | { |
226 | 0 | return fr_radius_attr_flags(da)->has_tag; |
227 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_has_tag Unexecuted instantiation: list.c:fr_radius_flag_has_tag Unexecuted instantiation: abinary.c:fr_radius_flag_has_tag |
228 | | |
229 | | static inline bool fr_radius_flag_concat(fr_dict_attr_t const *da) |
230 | 0 | { |
231 | 0 | return fr_radius_attr_flags(da)->concat; |
232 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_concat Unexecuted instantiation: list.c:fr_radius_flag_concat Unexecuted instantiation: abinary.c:fr_radius_flag_concat |
233 | | |
234 | | static inline bool fr_radius_flag_abinary(fr_dict_attr_t const *da) |
235 | 0 | { |
236 | 0 | return fr_radius_attr_flags(da)->abinary; |
237 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_abinary Unexecuted instantiation: list.c:fr_radius_flag_abinary Unexecuted instantiation: abinary.c:fr_radius_flag_abinary |
238 | | |
239 | | static inline fr_radius_attr_flags_encrypt_t fr_radius_flag_encrypted(fr_dict_attr_t const *da) |
240 | 0 | { |
241 | 0 | return fr_radius_attr_flags(da)->encrypt; |
242 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_encrypted Unexecuted instantiation: list.c:fr_radius_flag_encrypted Unexecuted instantiation: abinary.c:fr_radius_flag_encrypted |
243 | | |
244 | | static inline bool fr_radius_flag_extended(fr_dict_attr_t const *da) |
245 | 0 | { |
246 | 0 | fr_radius_attr_flags_t const *flags = fr_radius_attr_flags(da); |
247 | |
|
248 | 0 | return flags->extended || flags->long_extended; |
249 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_extended Unexecuted instantiation: list.c:fr_radius_flag_extended Unexecuted instantiation: abinary.c:fr_radius_flag_extended |
250 | | |
251 | | static inline bool fr_radius_flag_long_extended(fr_dict_attr_t const *da) |
252 | 0 | { |
253 | 0 | return fr_radius_attr_flags(da)->long_extended; |
254 | 0 | } Unexecuted instantiation: encode.c:fr_radius_flag_long_extended Unexecuted instantiation: list.c:fr_radius_flag_long_extended Unexecuted instantiation: abinary.c:fr_radius_flag_long_extended |
255 | | DIAG_ON(unused-function) |
256 | | |
257 | | extern fr_table_num_sorted_t const fr_radius_require_ma_table[]; |
258 | | extern size_t fr_radius_require_ma_table_len; |
259 | | |
260 | | extern fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[]; |
261 | | extern size_t fr_radius_limit_proxy_state_table_len; |
262 | | |
263 | | extern fr_table_num_sorted_t const fr_radius_request_name_table[]; |
264 | | extern size_t fr_radius_request_name_table_len; |
265 | | |
266 | | extern char const *fr_radius_packet_name[FR_RADIUS_CODE_MAX]; |
267 | | |
268 | | /* |
269 | | * protocols/radius/base.c |
270 | | */ |
271 | | int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX]); |
272 | | |
273 | | int fr_radius_sign(uint8_t *packet, uint8_t const *vector, |
274 | | uint8_t const *secret, size_t secret_len) CC_HINT(nonnull (1,3)); |
275 | | |
276 | | int fr_radius_verify(uint8_t *packet, uint8_t const *vector, |
277 | | uint8_t const *secret, size_t secret_len, |
278 | | bool require_message_authenticator, bool limit_proxy_state) CC_HINT(nonnull (1,3)); |
279 | | |
280 | | bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, |
281 | | uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason) CC_HINT(nonnull (1,2)); |
282 | | |
283 | | ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, |
284 | | char const *secret, size_t secret_len, uint8_t const *vector); |
285 | | |
286 | | ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code); |
287 | | |
288 | | ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx) CC_HINT(nonnull); |
289 | | |
290 | | ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, |
291 | | uint8_t *packet, size_t packet_len, |
292 | | fr_radius_decode_ctx_t *decode_ctx) CC_HINT(nonnull); |
293 | | |
294 | | ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, |
295 | | uint8_t *packet, size_t packet_len, |
296 | | uint8_t const *vector, char const *secret) CC_HINT(nonnull(1,2,3,6)); |
297 | | |
298 | | int fr_radius_global_init(void); |
299 | | |
300 | | void fr_radius_global_free(void); |
301 | | |
302 | | /* |
303 | | * protocols/radius/packet.c |
304 | | */ |
305 | | ssize_t fr_radius_packet_encode(fr_packet_t *packet, fr_pair_list_t *list, |
306 | | fr_packet_t const *original, |
307 | | char const *secret) CC_HINT(nonnull (1,2,4)); |
308 | | |
309 | | bool fr_packet_ok(fr_packet_t *packet, uint32_t max_attributes, bool require_message_authenticator, |
310 | | fr_radius_decode_fail_t *reason) CC_HINT(nonnull (1)); |
311 | | |
312 | | int fr_radius_packet_verify(fr_packet_t *packet, fr_packet_t *original, |
313 | | char const *secret) CC_HINT(nonnull (1,3)); |
314 | | int fr_radius_packet_sign(fr_packet_t *packet, fr_packet_t const *original, |
315 | | char const *secret) CC_HINT(nonnull (1,3)); |
316 | | |
317 | | fr_packet_t *fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_message_authenticator); |
318 | | int fr_radius_packet_send(fr_packet_t *packet, fr_pair_list_t *list, |
319 | | fr_packet_t const *original, char const *secret) CC_HINT(nonnull (1,2,4)); |
320 | | |
321 | | #define fr_packet_log_hex(_log, _packet) _fr_packet_log_hex(_log, _packet, __FILE__, __LINE__) |
322 | | void _fr_packet_log_hex(fr_log_t const *log, fr_packet_t const *packet, char const *file, int line) CC_HINT(nonnull); |
323 | | |
324 | | /* |
325 | | * protocols/radius/abinary.c |
326 | | */ |
327 | | ssize_t fr_radius_encode_abinary(fr_pair_t const *vp, fr_dbuff_t *dbuff); |
328 | | |
329 | | ssize_t fr_radius_decode_abinary(fr_pair_t *vp, uint8_t const *data, size_t data_len); |
330 | | |
331 | | /* |
332 | | * protocols/radius/encode.c |
333 | | */ |
334 | | ssize_t fr_radius_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx); |
335 | | |
336 | | ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list) CC_HINT(nonnull); |
337 | | |
338 | | /* |
339 | | * protocols/radius/decode.c |
340 | | */ |
341 | | int fr_radius_decode_tlv_ok(uint8_t const *data, size_t length, size_t dv_type, size_t dv_length); |
342 | | |
343 | | ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, fr_pair_list_t *list, |
344 | | fr_dict_attr_t const *parent, |
345 | | uint8_t const *data, size_t const attr_len, |
346 | | void *packet_ctx) CC_HINT(nonnull); |
347 | | |
348 | | ssize_t fr_radius_decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *list, |
349 | | fr_dict_attr_t const *parent, |
350 | | uint8_t const *data, size_t data_len, |
351 | | fr_radius_decode_ctx_t *packet_ctx) CC_HINT(nonnull); |
352 | | |
353 | | ssize_t fr_radius_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *list, |
354 | | uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx) CC_HINT(nonnull); |
355 | | |
356 | | ssize_t fr_radius_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, |
357 | | uint8_t const *data, size_t data_len) CC_HINT(nonnull); |
358 | | |
359 | | void fr_radius_packet_header_log(fr_log_t const *log, fr_packet_t *packet, bool received); |
360 | | |
361 | | void fr_radius_packet_log(fr_log_t const *log, fr_packet_t *packet, fr_pair_list_t *list, bool received); |