pfix-srsd: add a -I option
[apps/pfixtools.git] / pfix-srsd / main-srsd.c
index e271eda..0c656f8 100644 (file)
 /*     products derived from this software without specific prior written     */
 /*     permission.                                                            */
 /*                                                                            */
-/*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
-/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
-/*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
-/*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
-/*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
-/*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
-/*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
-/*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
-/*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
-/*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
-/*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
+/*  THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS   */
+/*  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED         */
+/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE    */
+/*  DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY         */
+/*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
+/*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   */
+/*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     */
+/*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       */
+/*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  */
+/*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
+/*  POSSIBILITY OF SUCH DAMAGE.                                               */
+/*                                                                            */
+/*   Copyright (c) 2006-2008 the Authors                                      */
+/*   see AUTHORS and source files for details                                 */
 /******************************************************************************/
 
 /*
@@ -43,7 +46,7 @@
 #include "server.h"
 
 #define DAEMON_NAME             "pfix-srsd"
-#define DAEMON_VERSION          "0.4"
+#define DAEMON_VERSION          "0.5"
 #define DEFAULT_ENCODER_PORT    10001
 #define DEFAULT_DECODER_PORT    10002
 #define RUNAS_USER              "nobody"
@@ -54,6 +57,8 @@ DECLARE_MAIN
 typedef struct srs_config_t {
     srs_t* srs;
     const char* domain;
+    int domainlen;
+    int ignore_ext;
 } srs_config_t;
 
 
@@ -72,7 +77,7 @@ static void *srsd_starter(listener_t *server)
 /* Processing {{{1
  */
 
-void urldecode(char *s, char *end)
+char *urldecode(char *s, char *end)
 {
     char *p = s;
 
@@ -89,7 +94,8 @@ void urldecode(char *s, char *end)
 
         *s++ = *p++;
     }
-    *s++ = '\0';
+    *s = '\0';
+    return s;
 }
 
 int process_srs(client_t *srsd, void* vconfig)
@@ -120,7 +126,7 @@ int process_srs(client_t *srsd, void* vconfig)
         }
 
         if (strncmp("get ", ibuf->data, 4)) {
-                                               err("bad request, not starting with \"get \"");
+            err("bad request, not starting with \"get \"");
             return -1;
         }
 
@@ -128,30 +134,42 @@ int process_srs(client_t *srsd, void* vconfig)
         for (q = nl++; q >= p && isspace(*q); *q-- = '\0');
 
         if (p == q) {
-            buffer_addstr(&*obuf, "400 empty request ???\n");
+            buffer_addstr(obuf, "400 empty request ???\n");
             warn("empty request");
             goto skip;
         }
 
-        urldecode(p, q);
+        q = urldecode(p, q);
 
         if (decoder) {
+            if (config->ignore_ext) {
+                int dlen = config->domainlen;
+
+                if (q - p <= dlen || q[-1 - dlen] != '@' ||
+                    memcmp(q - dlen, config->domain, dlen))
+                {
+                    buffer_addstr(obuf, "200 ");
+                    buffer_add(obuf, p, q - p);
+                    buffer_addch(obuf, '\n');
+                    goto skip;
+                }
+            }
             err = srs_reverse(config->srs, buf, ssizeof(buf), p);
         } else {
             err = srs_forward(config->srs, buf, ssizeof(buf), p, config->domain);
         }
 
         if (err == 0) {
-            buffer_addstr(&*obuf, "200 ");
-            buffer_addstr(&*obuf, buf);
+            buffer_addstr(obuf, "200 ");
+            buffer_addstr(obuf, buf);
         } else {
             switch (SRS_ERROR_TYPE(err)) {
               case SRS_ERRTYPE_SRS:
               case SRS_ERRTYPE_SYNTAX:
-                buffer_addstr(&*obuf, "500 ");
+                buffer_addstr(obuf, "500 ");
                 break;
               default:
-                buffer_addstr(&*obuf, "400 ");
+                buffer_addstr(obuf, "400 ");
                 break;
             }
             buffer_addstr(obuf, srs_strerror(err));
@@ -257,6 +275,7 @@ void usage(void)
           "                 (default: "STR(DEFAULT_DECODER_PORT)")\n"
           "    -p <pidfile> file to write our pid to\n"
           "    -u           unsafe mode: don't drop privilegies\n"
+          "    -I           do not touch mails outside of \"domain\" in decoding mode\n"
           "    -f           stay in foreground\n"
          , stderr);
 }
@@ -272,7 +291,7 @@ int main(int argc, char *argv[])
     int port_dec = DEFAULT_DECODER_PORT;
     const char *pidfile = NULL;
 
-    for (int c = 0; (c = getopt(argc, argv, "hfu" "e:d:p:")) >= 0; ) {
+    for (int c = 0; (c = getopt(argc, argv, "hfuI" "e:d:p:")) >= 0; ) {
         switch (c) {
           case 'e':
             port_enc = atoi(optarg);
@@ -289,6 +308,9 @@ int main(int argc, char *argv[])
           case 'u':
             unsafe = true;
             break;
+          case 'I':
+            config.ignore_ext = true;
+            break;
           default:
             usage();
             return EXIT_FAILURE;
@@ -307,6 +329,7 @@ int main(int argc, char *argv[])
     info("%s v%s...", DAEMON_NAME, DAEMON_VERSION);
 
     config.domain = argv[optind];
+    config.domainlen = strlen(config.domain);
     config.srs = srs_read_secrets(argv[optind + 1]);
     if (!config.srs
         || common_setup(pidfile, unsafe, RUNAS_USER, RUNAS_GROUP,