chiark / gitweb /
microhttpd-util: avoid double free on error
[elogind.git] / src / journal / microhttpd-util.c
index f7f12e1..f693e0f 100644 (file)
 #endif
 
 void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
-        _cleanup_free_ char *f = NULL;
+        char *f;
 
-        if (asprintf(&f, "microhttpd: %s", fmt) <= 0) {
-                log_oom();
-                return;
-        }
+        f = strappenda("microhttpd: ", fmt);
 
         DISABLE_WARNING_FORMAT_NONLITERAL;
         log_metav(LOG_INFO, NULL, 0, NULL, f, ap);
@@ -48,31 +45,45 @@ void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
 }
 
 
-int respond_oom_internal(struct MHD_Connection *connection) {
-        const char *m = "Out of memory.\n";
-
+static int mhd_respond_internal(struct MHD_Connection *connection,
+                                enum MHD_RequestTerminationCode code,
+                                char *buffer,
+                                size_t size,
+                                enum MHD_ResponseMemoryMode mode) {
         struct MHD_Response *response;
-        int ret;
+        int r;
 
         assert(connection);
 
-        response = MHD_create_response_from_buffer(strlen(m), (char*) m, MHD_RESPMEM_PERSISTENT);
+        response = MHD_create_response_from_buffer(size, buffer, mode);
         if (!response)
                 return MHD_NO;
 
+        log_debug("Queing response %u: %s", code, buffer);
         MHD_add_response_header(response, "Content-Type", "text/plain");
-        ret = MHD_queue_response(connection, MHD_HTTP_SERVICE_UNAVAILABLE, response);
+        r = MHD_queue_response(connection, code, response);
         MHD_destroy_response(response);
 
-        return ret;
+        return r;
+}
+
+int mhd_respond(struct MHD_Connection *connection,
+                enum MHD_RequestTerminationCode code,
+                const char *message) {
+
+        return mhd_respond_internal(connection, code,
+                                    (char*) message, strlen(message),
+                                    MHD_RESPMEM_PERSISTENT);
 }
 
-_printf_(3,4)
-int respond_error(struct MHD_Connection *connection,
-                  unsigned code,
-                  const char *format, ...) {
+int mhd_respond_oom(struct MHD_Connection *connection) {
+        return mhd_respond(connection, MHD_HTTP_SERVICE_UNAVAILABLE,  "Out of memory.\n");
+}
+
+int mhd_respondf(struct MHD_Connection *connection,
+                 enum MHD_RequestTerminationCode code,
+                 const char *format, ...) {
 
-        struct MHD_Response *response;
         char *m;
         int r;
         va_list ap;
@@ -87,18 +98,7 @@ int respond_error(struct MHD_Connection *connection,
         if (r < 0)
                 return respond_oom(connection);
 
-        response = MHD_create_response_from_buffer(strlen(m), m, MHD_RESPMEM_MUST_FREE);
-        if (!response) {
-                free(m);
-                return respond_oom(connection);
-        }
-
-        log_debug("Queing response %u: %s", code, m);
-        MHD_add_response_header(response, "Content-Type", "text/plain");
-        r = MHD_queue_response(connection, code, response);
-        MHD_destroy_response(response);
-
-        return r;
+        return mhd_respond_internal(connection, code, m, r, MHD_RESPMEM_MUST_FREE);
 }
 
 #ifdef HAVE_GNUTLS
@@ -229,8 +229,8 @@ int check_permissions(struct MHD_Connection *connection, int *code) {
                                      MHD_CONNECTION_INFO_GNUTLS_SESSION);
         if (!ci) {
                 log_error("MHD_get_connection_info failed: session is unencrypted");
-                *code = respond_error(connection, MHD_HTTP_FORBIDDEN,
-                                      "Encrypted connection is required");
+                *code = mhd_respond(connection, MHD_HTTP_FORBIDDEN,
+                                    "Encrypted connection is required");
                 return -EPERM;
         }
         session = ci->tls_session;
@@ -238,25 +238,25 @@ int check_permissions(struct MHD_Connection *connection, int *code) {
 
         r = get_client_cert(session, &client_cert);
         if (r < 0) {
-                *code = respond_error(connection, MHD_HTTP_UNAUTHORIZED,
-                                      "Authorization through certificate is required");
+                *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED,
+                                    "Authorization through certificate is required");
                 return -EPERM;
         }
 
         r = get_auth_dn(client_cert, &buf);
         if (r < 0) {
-                *code = respond_error(connection, MHD_HTTP_UNAUTHORIZED,
-                                      "Failed to determine distinguished name from certificate");
+                *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED,
+                                    "Failed to determine distinguished name from certificate");
                 return -EPERM;
         }
 
-        log_info("Connection from DN %s", buf);
+        log_info("Connection from %s", buf);
 
         r = verify_cert_authorized(session);
         if (r < 0) {
                 log_warning("Client is not authorized");
-                *code = respond_error(connection, MHD_HTTP_UNAUTHORIZED,
-                                      "Client certificate not signed by recognized authority");
+                *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED,
+                                    "Client certificate not signed by recognized authority");
         }
         return r;
 }