string.c: do not interpret '\\' before '\0' (CVE-2019-15846)
[users/heiko/exim.git] / test / src / mtpscript.c
1 /* A little hacked up program that allows a script to play the part of a remote
2 SMTP/LMTP server on stdin/stdout for testing purposes. Hacked from the more
3 complicated version that does it over a socket. */
4
5
6 /* ANSI C standard includes */
7
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16
17 /* Unix includes */
18
19 #include <errno.h>
20 #include <unistd.h>
21
22 #ifndef CS
23 # define CS (char *)
24 #endif
25
26
27 static FILE *log;
28
29
30 /*************************************************
31 *            SIGALRM handler - crash out         *
32 *************************************************/
33
34 static void
35 sigalrm_handler(int sig)
36 {
37 sig = sig;    /* Keep picky compilers happy */
38 fprintf(log, "Server timed out\n");
39 exit(99);
40 }
41
42
43
44 /*************************************************
45 *                 Main Program                   *
46 *************************************************/
47
48 int main(int argc, char **argv)
49 {
50 char *logfile;
51 char *logmode = "w";
52 FILE *script;
53 unsigned char sbuffer[1024];
54 unsigned char ibuffer[1024];
55
56 if (argc < 3)
57   {
58   fprintf(stdout, "500 Script and log file required\n");
59   exit(1);
60   }
61
62 /* Get the script and log open */
63
64 script = fopen(argv[1], "r");
65 if (script == NULL)
66   {
67   fprintf(stdout, "500 Failed to open script %s: %s\r\n", argv[1],
68     strerror(errno));
69   exit(1);
70   }
71
72 logfile = argv[2];
73 if (logfile[0] == '+')
74   {
75   logfile++;
76   logmode = "a";
77   }
78
79 log = fopen(logfile, logmode);
80 if (log == NULL)
81   {
82   fprintf(stdout, "500 Failed to open log %s: %s\r\n", logfile,
83     strerror(errno));
84   exit(1);
85   }
86
87 /* SIGALRM handler crashes out */
88
89 signal(SIGALRM, sigalrm_handler);
90
91 /* Read the script, and do what it says. */
92
93 while (fgets(CS sbuffer, sizeof(sbuffer), script) != NULL)
94   {
95   int n = (int)strlen(CS sbuffer);
96   while (n > 0 && isspace(sbuffer[n-1])) n--;
97   sbuffer[n] = 0;
98
99   /* If the script line starts with a digit, it is a response line which
100   we are to send. */
101
102   if (isdigit(sbuffer[0]))
103     {
104     fprintf(log, "%s\n", sbuffer);
105     fflush(log);
106     fprintf(stdout, "%s\r\n", sbuffer);
107     fflush(stdout);
108     }
109
110   /* If the script line starts with "*sleep" we just sleep for a while
111   before continuing. Do not write this to the log, as it may not get
112   written at the right place in a log that's being shared. */
113
114   else if (strncmp(CS sbuffer, "*sleep ", 7) == 0)
115     {
116     sleep(atoi(CS sbuffer+7));
117     }
118
119   /* Otherwise the script line is the start of an input line we are expecting
120   from the client, or "*eof" indicating we expect the client to close the
121   connection. Read command line or data lines; the latter are indicated
122   by the expected line being just ".". */
123
124   else
125     {
126     int data = strcmp(CS sbuffer, ".") == 0;
127
128     fprintf(log, "%s\n", sbuffer);
129     fflush(log);
130
131     /* Loop for multiple data lines */
132
133     for (;;)
134       {
135       int n;
136       alarm(5);
137       if (fgets(CS ibuffer, sizeof(ibuffer), stdin) == NULL)
138         {
139         fprintf(log, "%sxpected EOF read from client\n",
140           (strncmp(CS sbuffer, "*eof", 4) == 0)? "E" : "Une");
141         goto END_OFF;
142         }
143       alarm(0);
144       n = (int)strlen(CS ibuffer);
145       while (n > 0 && isspace(ibuffer[n-1])) n--;
146       ibuffer[n] = 0;
147       fprintf(log, "<<< %s\n", ibuffer);
148       if (!data || strcmp(CS ibuffer, ".") == 0) break;
149       }
150
151     /* Check received what was expected */
152
153     if (strncmp(CS sbuffer, CS ibuffer, (int)strlen(CS sbuffer)) != 0)
154       {
155       fprintf(log, "Comparison failed - bailing out\n");
156       goto END_OFF;
157       }
158     }
159   }
160
161 /* This could appear in the wrong place in a shared log, so forgo it. */
162 /* fprintf(log, "End of script\n"); */
163
164 END_OFF:
165 fclose(script);
166 fclose(log);
167
168 exit(0);
169 }
170
171 /* End of mtpscript.c */