Coverage Report

Created: 2026-03-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}