]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
run policies to see if we can accept the RadSec connection
authorAlan T. DeKok <aland@freeradius.org>
Fri, 2 Apr 2021 16:32:50 +0000 (12:32 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 2 Apr 2021 16:32:50 +0000 (12:32 -0400)
src/include/listen.h
src/main/listen.c
src/main/tls_listen.c

index 4f50bbf8088b0a8f08f38baf65fd304325d01168..c5b45f0a7e9c83ea1d9f473c4467663e808330cd 100644 (file)
@@ -80,6 +80,7 @@ struct rad_listen {
 
 #ifdef WITH_TLS
        fr_tls_server_conf_t *tls;
+       bool            check_client_connections;
 #endif
 
        rad_listen_recv_t recv;
@@ -146,6 +147,12 @@ typedef struct listen_socket_t {
        pthread_mutex_t mutex;
        uint8_t         *data;
        size_t          partial;
+       enum {
+               LISTEN_TLS_INIT = 0,
+               LISTEN_TLS_CHECKING,
+               LISTEN_TLS_SETUP,
+               LISTEN_TLS_RUNNING,
+       } state;
 #endif
 
        RADCLIENT_LIST  *clients;
index 27ce67c6bc61fd216b42d0a114243d6512e9f7e6..5b9fd287d59c8f1a0973e63c5a95b53c58287b90 100644 (file)
@@ -1068,6 +1068,10 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
                        }
 #endif
 
+
+                       rcode = cf_item_parse(cs, "check_client_connections", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &this->check_client_connections), "no");
+                       if (rcode < 0) return -1;
+
                }
 #else  /* WITH_TLS */
                /*
@@ -2114,6 +2118,14 @@ static int proxy_socket_tcp_recv(rad_listen_t *listener)
 
 static int client_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
 {
+#ifdef WITH_TLS
+       /*
+        *      Don't encode fake packets.
+        */
+       listen_socket_t *sock = listener->data;
+       if (sock->state == LISTEN_TLS_CHECKING) return 0;
+#endif
+
        if (!request->reply->code) return 0;
 
        if (rad_encode(request->reply, request->packet, request->client->secret) < 0) {
index bedbd0cd6718c36cc277050419a5dda93e900a8e..d0e8530919447549d64c159aac8ea927b84b4d61 100644 (file)
@@ -187,6 +187,17 @@ static int tls_socket_recv(rad_listen_t *listener)
 
        request = sock->request;
 
+       if (sock->state == LISTEN_TLS_SETUP) {
+               RDEBUG3("Setting connection state to RUNNING");
+               sock->state = LISTEN_TLS_RUNNING;
+
+               if (sock->ssn->clean_out.used < 20) {
+                       goto get_application_data;
+               }
+
+               goto read_application_data;
+       }
+
        RDEBUG3("Reading from socket %d", request->packet->sockfd);
        PTHREAD_MUTEX_LOCK(&sock->mutex);
 
@@ -198,7 +209,7 @@ static int tls_socket_recv(rad_listen_t *listener)
        if (SSL_pending(sock->ssn->ssl)) {
                RDEBUG3("Reading pending buffered data");
                sock->ssn->dirty_in.used = 0;
-               goto get_application_data;
+               goto check_for_setup;
        }
 
        rcode = read(request->packet->sockfd,
@@ -253,12 +264,42 @@ static int tls_socket_recv(rad_listen_t *listener)
                }
 
                /*
-                *      FIXME: Run the request through a virtual
-                *      server in order to see if we like the
-                *      certificate presented by the client.
+                *      Else we MUST be finished the SSL setup.
                 */
        }
 
+       /*
+        *      Run the request through a virtual server in
+        *      order to see if we like the certificate
+        *      presented by the client.
+        */
+check_for_setup:
+       if (sock->state == LISTEN_TLS_INIT) {
+               rad_assert(SSL_is_init_finished(sock->ssn->ssl));
+               sock->ssn->is_init_finished = true;
+               if (!listener->check_client_connections) {
+                       sock->state = LISTEN_TLS_RUNNING;
+                       goto get_application_data;
+               }
+
+               RDEBUG("Checking initial connection");
+               request->packet->vps = fr_pair_list_copy(request->packet, sock->certs);
+               rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, "&request:");
+
+               /*
+                *      Fake out a Status-Server packet, which
+                *      does NOT have a Message-Authenticator,
+                *      or any other contents.
+                */
+               request->packet->code = PW_CODE_STATUS_SERVER;
+               request->packet->data = talloc_zero_array(packet, uint8_t, 20);
+               request->packet->data[0] = PW_CODE_STATUS_SERVER;
+               request->packet->data[3] = 20;
+               sock->state = LISTEN_TLS_CHECKING;
+               PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+               return 1;
+       }
+
        /*
         *      Try to get application data.
         */
@@ -276,6 +317,16 @@ get_application_data:
                return 0;
        }
 
+       /*
+        *      Hold application data if we're not yet in the RUNNING
+        *      state.
+        */
+       if (sock->state != LISTEN_TLS_RUNNING) {
+               RDEBUG3("Holding application data until setup is complete");
+               return 0;
+       }
+
+read_application_data:
        /*
         *      We now have a bunch of application data.
         */
@@ -360,6 +411,7 @@ redo:
        rad_assert(client != NULL);
 
        packet = talloc_steal(NULL, sock->packet);
+       sock->request->packet = NULL;
        sock->packet = NULL;
 
        /*
@@ -407,7 +459,11 @@ redo:
 #endif
 
        case PW_CODE_STATUS_SERVER:
-               if (!main_config.status_server) {
+               if (!main_config.status_server
+#ifdef WITH_TLS
+                   && !listener->check_client_connections
+#endif
+                       ) {
                        FR_STATS_INC(auth, total_unknown_types);
                        WARN("Ignoring Status-Server request due to security configuration");
                        rad_free(&packet);
@@ -470,6 +526,30 @@ int dual_tls_send(rad_listen_t *listener, REQUEST *request)
 
        if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
 
+       /*
+        *      See if the policies allowed this connection.
+        */
+       if (sock->state == LISTEN_TLS_CHECKING) {
+               if (request->reply->code != PW_CODE_ACCESS_ACCEPT) {
+                       REDEBUG("Rejecting client TLS connection");
+                       listener->status = RAD_LISTEN_STATUS_REMOVE_NOW;
+                       listener->tls = NULL; /* parent owns this! */
+
+                       /*
+                        *      Tell the event handler that an FD has disappeared.
+                        */
+                       radius_update_listener(listener);
+                       return 0;
+               }
+
+               rad_assert(sock->request->packet != request->packet);
+
+               RDEBUG("Accepting client TLS connection");
+               sock->state = LISTEN_TLS_SETUP;
+               (void) dual_tls_recv(listener);
+               return 0;
+       }
+
        /*
         *      Accounting reject's are silently dropped.
         *