From 73093c1dd80b0767943f4596dbabc4d0d3e45c38 Mon Sep 17 00:00:00 2001
From: Adam Shepherd <665-AdamPS@users.noreply.drupalcode.org>
Date: Sat, 6 May 2023 15:14:28 +0100
Subject: [PATCH] Issue #3351129 by AdamPS: Safeguard transport DSN

---
 src/Plugin/MailerTransport/DsnTransport.php |  2 +-
 src/ReplacementSendmailTransportFactory.php | 37 +++++++++++++++++++++
 src/TransportFactoryManager.php             |  7 ++++
 3 files changed, 45 insertions(+), 1 deletion(-)
 create mode 100644 src/ReplacementSendmailTransportFactory.php

diff --git a/src/Plugin/MailerTransport/DsnTransport.php b/src/Plugin/MailerTransport/DsnTransport.php
index 872665d3..b1de99ce 100644
--- a/src/Plugin/MailerTransport/DsnTransport.php
+++ b/src/Plugin/MailerTransport/DsnTransport.php
@@ -57,7 +57,7 @@ class DsnTransport extends TransportBase {
       Transport::fromDsn($dsn);
     }
     catch (\Exception $e) {
-      $form_state->setErrorByName('dsn', $this->t('Invalid DSN.'));
+      $form_state->setErrorByName('dsn', $this->t('Invalid DSN: @message', ['@message' => $e->getMessage()]));
     }
   }
 
diff --git a/src/ReplacementSendmailTransportFactory.php b/src/ReplacementSendmailTransportFactory.php
new file mode 100644
index 00000000..b256dacc
--- /dev/null
+++ b/src/ReplacementSendmailTransportFactory.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\symfony_mailer;
+
+use Drupal\Core\Site\Settings;
+use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
+use Symfony\Component\Mailer\Transport\Dsn;
+use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
+use Symfony\Component\Mailer\Transport\TransportInterface;
+
+/**
+ * Provides a replacement sendmail transport factory that checks the command.
+ */
+final class ReplacementSendmailTransportFactory extends AbstractTransportFactory {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function create(Dsn $dsn): TransportInterface {
+    if ($command = $dsn->getOption('command')) {
+      $commands = Settings::get('mailer_sendmail_commands', []);
+      if (!in_array($command, $commands)) {
+        throw new \RuntimeException("Unsafe sendmail command {$command}");
+      }
+    }
+
+    return (new SendmailTransportFactory())->create($dsn);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSupportedSchemes(): array {
+    return ['sendmail', 'sendmail+smtp'];
+  }
+
+}
diff --git a/src/TransportFactoryManager.php b/src/TransportFactoryManager.php
index 7602e489..0cb3268b 100644
--- a/src/TransportFactoryManager.php
+++ b/src/TransportFactoryManager.php
@@ -3,6 +3,7 @@
 namespace Drupal\symfony_mailer;
 
 use Symfony\Component\Mailer\Transport;
+use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
 use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
 
 /**
@@ -22,6 +23,12 @@ class TransportFactoryManager implements TransportFactoryManagerInterface {
    */
   public function __construct() {
     $this->factories = iterator_to_array(Transport::getDefaultFactories());
+
+    // Replace the sendmail transport factory with our own implementation.
+    $this->factories = array_filter($this->factories, function ($factory) {
+      return !($factory instanceof SendmailTransportFactory);
+    });
+    $this->addFactory(new ReplacementSendmailTransportFactory());
   }
 
   /**
-- 
GitLab