* Fixed a bunch of potential unterminated string and/or buffer overrun errors.
authorUrban Wallasch <urban.wallasch@freenet.de>
Sun, 4 Aug 2019 09:55:47 +0000 (11:55 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sun, 4 Aug 2019 09:55:47 +0000 (11:55 +0200)
* Refactored some code.

telehttpd.c

index d81d474d2d9d345d982a7678244e580179ce3c99..9d31190b8f0668c101c77f11e9a37b0d59bf9128 100644 (file)
 #include "telemetry.h"
 #include "tele2json.h"
 
-static struct telemetry_state_t *telemetry;
-static struct telemetry_state_t telemetry0;
+struct thread_data_t {
+    int sock;
+    struct telemetry_state_t tele;
+};
 
 struct {
     int port;
@@ -40,12 +42,10 @@ struct {
     false,
 };
 
-struct thread_data_t {
-    int sock;
-    struct telemetry_state_t tele;
-};
+static struct telemetry_state_t *telemetry;
+static struct telemetry_state_t telemetry0;
 
-static volatile int force_quit;
+static volatile sig_atomic_t force_quit;
 
 static void handle_signal(int sig) {
     fprintf (stderr, "SIGNAL: %d\n", sig);
@@ -93,12 +93,34 @@ static int check_shm( bool retry ) {
     return 0;
 }
 
+static size_t copy_field_val( char *buf, size_t bufsz, const char *needle, const char *haystack, const char *def ) {
+    const char *s;
+    size_t l;
+
+    if ( NULL != ( s = strstr( haystack, needle ) ) ) {
+        const char *e;
+        s += strlen( needle );
+        if ( NULL != ( e = strstr( s, "\r\n" ) ) )
+            l = e - s;
+        else
+            s = NULL;
+    }
+    if ( NULL == s ) {
+        s = def;
+        l = def ? strlen( def ) : 0;
+    }
+    l = l < bufsz ? l : 0;
+    for ( size_t i = 0; i < l; i++ )
+        buf[i] = s[i];
+    buf[l] = '\0';
+    return l;
+}
+
 static void respond( struct thread_data_t *td, const char *req ) {
-    char buf[4096];
+    int n;
+    char buf[4096]; // Must be large enough to satisfy tele2json()!
     char origin[256];
     char host[256];
-    const char *s;
-    int fd = td->sock;
     enum respond_code {
         r_index,
         r_json,
@@ -112,61 +134,70 @@ static void respond( struct thread_data_t *td, const char *req ) {
     else
         code = r_none;
 
+    copy_field_val( host, sizeof host, "Host: ", req, cfg.host );
+
     switch (code) {
     case r_json:
-    case r_index:
-        if ( NULL != (s = strstr(req, "Origin: ")) ) {
-            s += 8; //strlen("Origin: ");
-            const char *e = strstr(s, "\r\n");
-            strncpy(origin, s, e-s);
-        }
-        else
-            strcpy(origin, cfg.origin);
-
-        if ( NULL != (s = strstr(req, "Host: ")) ) {
-            s += 6;//strlen("Host: ");
-            const char *e = strstr(s, "\r\n");
-            strncpy(host, s, e-s);
-        }
-        else
-            strcpy(host, cfg.host);
-
-        if (r_json == code){
-            write(fd, buf, sprintf(buf, "HTTP/1.1 200 OK\r\n"));
-            write(fd, buf, sprintf(buf, "Host: %s\r\n", host));
-            write(fd, buf, sprintf(buf, "Access-Control-Allow-Origin: %s\r\n", origin));
-            write(fd, buf, sprintf(buf, "Content-type: text/json\r\n"));
-            write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
-            write( fd, buf, tele2json(buf, sizeof buf, &td->tele) );
-        }
-        else {
-            struct file_info_t fi;
-            if (0 == fserv_open_server(cfg.idxfile, &fi)){
-                write(fd, buf, sprintf(buf, "HTTP/1.1 200 OK\r\n"));
-                write(fd, buf, sprintf(buf, "Host: %s\r\n", host));
-                write(fd, buf, sprintf(buf, "Content-type: text/html\r\n"));
-                write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
-                fserv_sendfile(fd, &fi);
-                fserv_close(&fi);
+        copy_field_val( origin, sizeof origin, "Origin: ", req, cfg.origin );
+        n = snprintf( buf, sizeof buf,
+                "HTTP/1.1 200 OK\r\n"
+                "Host: %s\r\n"
+                "Access-Control-Allow-Origin: %s\r\n"
+                "Content-type: text/json\r\n"
+                "Connection: close\r\n"
+                "\r\n",
+                host,
+                origin
+            );
+        if ( 0 < n && (size_t)n < sizeof buf && n == write( td->sock, buf, n ) )
+            write( td->sock, buf, tele2json( buf, sizeof buf, &td->tele ) );
+        break;
+    case r_index: {
+        struct file_info_t fi;
+        if ( 0 == fserv_open_server( cfg.idxfile, &fi ) ){
+            n = snprintf( buf, sizeof buf,
+                    "HTTP/1.1 200 OK\r\n"
+                    "Host: %s\r\n"
+                    "Content-type: text/html\r\n"
+                    "Connection: close\r\n"
+                    "\r\n",
+                    host
+                );
+            if ( 0 < n && (size_t)n < sizeof buf && n == write( td->sock, buf, n ) ) {
+                fserv_sendfile( td->sock, &fi );
+                fserv_close( &fi );
             }
-            else
-                goto SEND_404;
         }
+        else
+            goto SEND_404;
         break;
+    }
     case r_none:
     SEND_404:
-        write(fd, buf, sprintf(buf, "HTTP/1.1 404 Not Found\r\n"));
-        write(fd, buf, sprintf(buf, "Host: localhost\r\n"));
-        write(fd, buf, sprintf(buf, "Content-type: text/plain\r\n"));
-        write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
-        write(fd, buf, sprintf(buf, "404 Not Found"));
+        n = snprintf( buf, sizeof buf,
+                "HTTP/1.1 404 Not Found\r\n"
+                "Host: %s\r\n"
+                "Content-type: text/plain\r\n"
+                "Connection: close\r\n"
+                "\r\n"
+                "404 Not Found",
+                host
+            );
+        if ( 0 < n && (size_t)n < sizeof buf )
+            write( td->sock, buf, n );
         break;
     default:
-        write(fd, buf, sprintf(buf, "HTTP/1.1 500 Internal Server Error\r\n"));
-        write(fd, buf, sprintf(buf, "Host: localhost\r\n"));
-        write(fd, buf, sprintf(buf, "Content-type: text/plain\r\n"));
-        write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
-        write(fd, buf, sprintf(buf, "500 Internal Server Error"));
+        n = snprintf( buf, sizeof buf,
+                "HTTP/1.1 500 Internal Server Error\r\n"
+                "Host: %s\r\n"
+                "Content-type: text/plain\r\n"
+                "Connection: close\r\n"
+                "\r\n"
+                "500 Internal Server Error",
+                host
+            );
+        if ( 0 < n && (size_t)n < sizeof buf )
+            write( td->sock, buf, n );
         break;
     }
 }