check for username, too
[freeradius.git] / src / main / auth.c
index e99eba0..79e639e 100644 (file)
@@ -38,7 +38,7 @@ char *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli)
 {
        VALUE_PAIR      *cli;
        VALUE_PAIR      *pair;
-       uint16_t        port = 0;
+       uint32_t        port = 0;       /* RFC 2865 NAS-Port is 4 bytes */
        char const      *tls = "";
 
        if ((cli = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) == NULL) {
@@ -197,7 +197,7 @@ static int CC_HINT(nonnull) rad_check_password(REQUEST *request)
         *      Warn if more than one Auth-Type was found, because only the last
         *      one found will actually be used.
         */
-       if ((auth_type_count > 1) && (rad_debug_lvl)) {
+       if ((auth_type_count > 1) && (rad_debug_lvl) && request->username) {
                RERROR("Warning:  Found %d auth-types on request for user '%s'",
                        auth_type_count, request->username->vp_strvalue);
        }
@@ -327,13 +327,13 @@ int rad_postauth(REQUEST *request)
                /*
                 *      We WERE going to have a nice reply, but
                 *      something went wrong.  So we've got to run
-                *      Post-Auth-Type Reject, which is defined in the
-                *      dictionaries as having value "1".
+                *      Post-Auth-Type Reject.
                 */
                if (request->reply->code != PW_CODE_ACCESS_REJECT) {
                        RDEBUG("Using Post-Auth-Type Reject");
 
-                       process_post_auth(1, request);
+                       request->reply->code = PW_CODE_ACCESS_REJECT;
+                       process_post_auth(PW_POST_AUTH_TYPE_REJECT, request);
                }
 
                fr_state_discard(request, request->packet);
@@ -709,6 +709,98 @@ int rad_virtual_server(REQUEST *request)
        RDEBUG("Virtual server %s received request", request->server);
        rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
 
+       if (!request->username) {
+               request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+       }
+
+       /*
+        *      Complain about possible issues related to tunnels.
+        */
+       if (request->parent && request->parent->username && request->username) {
+               /*
+                *      Look at the full User-Name with realm.
+                */
+               if (request->parent->username->da->attr == PW_STRIPPED_USER_NAME) {
+                       vp = fr_pair_find_by_num(request->parent->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+                       rad_assert(vp != NULL);
+               } else {
+                       vp = request->parent->username;
+               }
+
+               /*
+                *      If the names aren't identical, we do some detailed checks.
+                */
+               if (strcmp(vp->vp_strvalue, request->username->vp_strvalue) != 0) {
+                       char const *outer, *inner;
+
+                       outer = strchr(vp->vp_strvalue, '@');
+
+                       /*
+                        *      If there's no realm, or there's a user identifier before
+                        *      the realm name, check the user identifier.
+                        *
+                        *      It SHOULD be "anonymous", or "anonymous@realm"
+                        */
+                       if (outer) {
+                               if ((outer != vp->vp_strvalue) &&
+                                   ((vp->vp_length < 10) || (memcmp(vp->vp_strvalue, "anonymous@", 10) != 0))) {
+                                       RWDEBUG("Outer User-Name is not anonymized.  User privacy is compromised.");
+                               } /* else it is anonymized */
+
+                               /*
+                                *      Check when there's no realm, and without the trailing '@'
+                                */
+                       } else if ((vp->vp_length < 9) || (memcmp(vp->vp_strvalue, "anonymous", 9) != 0)) {
+                                       RWDEBUG("Outer User-Name is not anonymized.  User privacy is compromised.");
+
+                       } /* else the user identifier is anonymized */
+
+                       /*
+                        *      Look for an inner realm, which may or may not exist.
+                        */
+                       inner = strchr(request->username->vp_strvalue, '@');
+                       if (outer && inner) {
+                               outer++;
+                               inner++;
+
+                               /*
+                                *      The realms are different, do
+                                *      more detailed checks.
+                                */
+                               if (strcmp(outer, inner) != 0) {
+                                       size_t outer_len, inner_len;
+
+                                       outer_len = vp->vp_length;
+                                       outer_len -= (outer - vp->vp_strvalue);
+
+                                       inner_len = request->username->vp_length;
+                                       inner_len -= (inner - request->username->vp_strvalue);
+
+                                       /*
+                                        *      Inner: secure.example.org
+                                        *      Outer: example.org
+                                        */
+                                       if (inner_len > outer_len) {
+                                               char const *suffix;
+
+                                               suffix = inner + (inner_len - outer_len) - 1;
+
+                                               if ((*suffix != '.') ||
+                                                   (strcmp(suffix + 1, outer) != 0)) {
+                                                       RWDEBUG("Possible spoofing: Inner realm '%s' is not a subdomain of the outer realm '%s'", inner, outer);
+                                               }
+
+                                       } else {
+                                               RWDEBUG("Possible spoofing: Inner realm and outer realms are different");
+                                       }
+                               }
+                       }
+
+               } else {
+                       RWDEBUG("Outer and inner identities are the same.  User privacy is compromised.");
+               }
+       }
+
        RDEBUG("server %s {", request->server);
        RINDENT();