/src/freeradius-server/src/lib/server/auth.c
Line | Count | Source |
1 | | /* |
2 | | * This program is free software; you can redistribute it and/or modify |
3 | | * it under the terms of the GNU General Public License as published by |
4 | | * the Free Software Foundation; either version 2 of the License, or |
5 | | * (at your option) any later version. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
15 | | */ |
16 | | |
17 | | /** |
18 | | * $Id: 712d65a61c6d5b01b9ece8f42d19e8e1f19943a2 $ |
19 | | * |
20 | | * @file src/lib/server/auth.c |
21 | | * @brief The old authentication state machine. |
22 | | * |
23 | | * @copyright 2000,2006 The FreeRADIUS server project |
24 | | * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl) |
25 | | * @copyright 2000 Jeff Carneal (jeff@apex.net) |
26 | | */ |
27 | | RCSID("$Id: 712d65a61c6d5b01b9ece8f42d19e8e1f19943a2 $") |
28 | | |
29 | | #include <freeradius-devel/io/listen.h> |
30 | | #include <freeradius-devel/server/auth.h> |
31 | | #include <freeradius-devel/server/module.h> |
32 | | #include <freeradius-devel/server/protocol.h> |
33 | | #include <freeradius-devel/server/state.h> |
34 | | #include <freeradius-devel/unlang/call.h> |
35 | | |
36 | | #include <freeradius-devel/util/print.h> |
37 | | #include <freeradius-devel/radius/defs.h> |
38 | | |
39 | | |
40 | | /* |
41 | | * Run a virtual server auth and postauth |
42 | | * |
43 | | */ |
44 | | unlang_action_t rad_virtual_server(unlang_result_t *p_result, request_t *request) |
45 | 0 | { |
46 | 0 | RDEBUG("Virtual server %s received request NOT IMPLEMENTED", cf_section_name2(unlang_call_current(request))); |
47 | 0 | log_request_pair_list(L_DBG_LVL_1, request, NULL, &request->request_pairs, NULL); |
48 | | |
49 | | /* |
50 | | * Just push the virtual server onto the stack? |
51 | | * |
52 | | * Except that the caller expects this function to be run |
53 | | * _synchronously_, and all of that needs to be fixed. |
54 | | */ |
55 | 0 | RETURN_UNLANG_FAIL; |
56 | |
|
57 | | #if 0 |
58 | | { |
59 | | fr_pair_t *username, *parent_username = NULL; |
60 | | fr_pair_t *vp; |
61 | | |
62 | | username = fr_pair_find_by_num(&request->request_pairs, 0, FR_STRIPPED_USER_NAME); |
63 | | if (!username) username = fr_pair_find_by_num(&request->request_pairs, 0, FR_USER_NAME); |
64 | | |
65 | | if (request->parent) { |
66 | | parent_username = fr_pair_find_by_num(&request->parent->request_pairs, 0, FR_STRIPPED_USER_NAME); |
67 | | if (!parent_username) parent_username = fr_pair_find_by_num(&request->parent->request_pairs, 0, FR_USER_NAME); |
68 | | } |
69 | | |
70 | | /* |
71 | | * Complain about possible issues related to tunnels. |
72 | | */ |
73 | | if (username && parent_username) { |
74 | | /* |
75 | | * Look at the full User-Name with realm. |
76 | | */ |
77 | | if (parent_username->da->attr == FR_STRIPPED_USER_NAME) { |
78 | | vp = fr_pair_find_by_num(&request->parent->request_pairs, 0, FR_USER_NAME); |
79 | | if (!vp) goto runit; |
80 | | } else { |
81 | | vp = parent_username; |
82 | | } |
83 | | |
84 | | /* |
85 | | * If the names aren't identical, we do some detailed checks. |
86 | | */ |
87 | | if (strcmp(vp->vp_strvalue, username->vp_strvalue) != 0) { |
88 | | char const *outer, *inner; |
89 | | |
90 | | outer = strchr(vp->vp_strvalue, '@'); |
91 | | |
92 | | /* |
93 | | * If there's no realm, or there's a user identifier before |
94 | | * the realm name, check the user identifier. |
95 | | * |
96 | | * It SHOULD be "anonymous", or "anonymous@realm" |
97 | | */ |
98 | | if (outer) { |
99 | | if ((outer != vp->vp_strvalue) && |
100 | | ((vp->vp_length < 10) || (memcmp(vp->vp_strvalue, "anonymous@", 10) != 0))) { |
101 | | RWDEBUG("Outer User-Name is not anonymized. User privacy is compromised."); |
102 | | } /* else it is anonymized */ |
103 | | |
104 | | /* |
105 | | * Check when there's no realm, and without the trailing '@' |
106 | | */ |
107 | | } else if ((vp->vp_length < 9) || (memcmp(vp->vp_strvalue, "anonymous", 9) != 0)) { |
108 | | RWDEBUG("Outer User-Name is not anonymized. User privacy is compromised."); |
109 | | |
110 | | } /* else the user identifier is anonymized */ |
111 | | |
112 | | /* |
113 | | * Look for an inner realm, which may or may not exist. |
114 | | */ |
115 | | inner = strchr(username->vp_strvalue, '@'); |
116 | | if (outer && inner) { |
117 | | outer++; |
118 | | inner++; |
119 | | |
120 | | /* |
121 | | * The realms are different, do |
122 | | * more detailed checks. |
123 | | */ |
124 | | if (strcmp(outer, inner) != 0) { |
125 | | size_t outer_len, inner_len; |
126 | | |
127 | | outer_len = vp->vp_length; |
128 | | outer_len -= (outer - vp->vp_strvalue); |
129 | | |
130 | | inner_len = username->vp_length; |
131 | | inner_len -= (inner - username->vp_strvalue); |
132 | | |
133 | | /* |
134 | | * Inner: secure.example.org |
135 | | * Outer: example.org |
136 | | */ |
137 | | if (inner_len > outer_len) { |
138 | | char const *suffix; |
139 | | |
140 | | suffix = inner + (inner_len - outer_len) - 1; |
141 | | |
142 | | if ((*suffix != '.') || |
143 | | (strcmp(suffix + 1, outer) != 0)) { |
144 | | RWDEBUG("Possible spoofing: Inner realm '%s' is not a " |
145 | | "subdomain of the outer realm '%s'", inner, outer); |
146 | | } |
147 | | |
148 | | } else { |
149 | | RWDEBUG("Possible spoofing: Inner realm and " |
150 | | "outer realms are different"); |
151 | | } |
152 | | } |
153 | | } |
154 | | |
155 | | } else { |
156 | | RWDEBUG("Outer and inner identities are the same. User privacy is compromised."); |
157 | | } |
158 | | } |
159 | | } |
160 | | |
161 | | if (!request->async) { |
162 | | #ifdef STATIC_ANALYZER |
163 | | if (!request->parent) RETURN_UNLANG_FAIL; |
164 | | #endif |
165 | | fr_assert(request->parent != NULL); |
166 | | |
167 | | request->async = talloc_memdup(request, request->parent->async, sizeof(fr_async_t)); |
168 | | talloc_set_name_const(request->async, talloc_get_name(request->parent->async)); |
169 | | } |
170 | | |
171 | | RDEBUG("server %s {", cf_section_name2(unlang_call_current(request))); |
172 | | request->async->process(&final, |
173 | | MODULE_CTX(module_rlm_by_data(request->async->process_inst), NULL, NULL, NULL), |
174 | | request); |
175 | | RDEBUG("} # server %s", cf_section_name2(unlang_call_current(request))); |
176 | | |
177 | | fr_cond_assert(final == RLM_MODULE_OK); |
178 | | |
179 | | if (!request->reply->code || |
180 | | (request->reply->code == FR_RADIUS_CODE_ACCESS_REJECT)) { |
181 | | RETURN_UNLANG_REJECT; |
182 | | } |
183 | | |
184 | | if (request->reply->code == FR_RADIUS_CODE_ACCESS_CHALLENGE) { |
185 | | RETURN_UNLANG_HANDLED; |
186 | | } |
187 | | |
188 | | RETURN_UNLANG_OK; |
189 | | #endif |
190 | 0 | } |
191 | | |
192 | | /* |
193 | | * Debug the packet if requested. |
194 | | */ |
195 | | void common_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *pairs, bool received) |
196 | 0 | { |
197 | 0 | #ifdef WITH_IFINDEX_NAME_RESOLUTION |
198 | 0 | char if_name[IFNAMSIZ]; |
199 | 0 | #endif |
200 | |
|
201 | 0 | if (!packet) return; |
202 | 0 | if (!RDEBUG_ENABLED) return; |
203 | | |
204 | | |
205 | 0 | log_request(L_DBG, L_DBG_LVL_1, request, __FILE__, __LINE__, "%s code %u Id %i from %s%pV%s:%i to %s%pV%s:%i " |
206 | 0 | #ifdef WITH_IFINDEX_NAME_RESOLUTION |
207 | 0 | "%s%s%s" |
208 | 0 | #endif |
209 | 0 | "length %zu", |
210 | 0 | received ? "Received" : "Sent", |
211 | 0 | packet->code, |
212 | 0 | packet->id, |
213 | 0 | packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "", |
214 | 0 | fr_box_ipaddr(packet->socket.inet.src_ipaddr), |
215 | 0 | packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "", |
216 | 0 | packet->socket.inet.src_port, |
217 | 0 | packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "", |
218 | 0 | fr_box_ipaddr(packet->socket.inet.dst_ipaddr), |
219 | 0 | packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "", |
220 | 0 | packet->socket.inet.dst_port, |
221 | 0 | #ifdef WITH_IFINDEX_NAME_RESOLUTION |
222 | 0 | packet->socket.inet.ifindex ? "via " : "", |
223 | 0 | packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "", |
224 | 0 | packet->socket.inet.ifindex ? " " : "", |
225 | 0 | #endif |
226 | 0 | packet->data_len); |
227 | |
|
228 | 0 | if (received) { |
229 | 0 | log_request_pair_list(L_DBG_LVL_1, request, NULL, pairs, NULL); |
230 | 0 | } else { |
231 | 0 | log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, pairs, NULL); |
232 | 0 | } |
233 | 0 | } |