1 /***********************************************************
2 *       libsrs_alt - A simple SRS implementation           *
3 ***********************************************************/
4 
5 /* �2004 Miles Wilton <miles@mirtol.com> */
6 
7 /* License: GPL */
8 
9 /* This file:
10 
11    srs.c
12 
13    srs command line tool and daemon
14 */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <signal.h>
25 
26 
27 #include "src/srs_alt.h"
28 
29 /* Prototypes */
30 
31 int main(int argc, char **argv, char **env);
32 int display_help(void);
33 int add_secret(char *secret);
34 int do_forward(FILE *fh, char *add, char *als);
35 int do_reverse(FILE *fh, char *add);
36 int start_srs(void);
37 int srsd(void);
38 void handle_signal(int signum);
39 
40 
41 /* Defs */
42 
43 #define MAX_FILE_LINE_LENGTH            1024
44 #define MAX_SOCKET_LINE_LENGTH          1024
45 #define MAX_SOCKET_WAITING              8
46 
47 
48 /* Global vars */
49 
50 char *alias = NULL;
51 int hashlength = SRS_DEFAULT_HASH_LEN;
52 char separator = '=';
53 char **secrets = NULL;
54 int secrets_size = 0;
55 int secrets_count = 0;
56 int mode = 0;
57 char *socket_name = "/tmp/srsd";
58 
59 srs_t *srs;
60 srs_t **srsa;
61 
62 
63 /***********************************************************
64     main
65 
66 */
67 
main(int argc,char ** argv,char ** env)68 int main(int argc, char **argv, char **env)
69 {
70     int n, m, r;
71     char *add;
72     char srsbuf[SRS_MAX_ADDRESS_LENGTH+1];
73 
74     /*
75        -- PROCESS COMMAND LINE --
76     */
77     for(n = 1; n < argc; n++)
78     {
79         if(argv[n][0] == '-')
80         {
81             // Flag
82             if(argv[n][1] == '-')
83                 m = 2;
84             else
85                 m = 1;
86 
87             if(strncasecmp(&argv[n][m], "address=", 8) == 0)
88             {
89                 // Ok, savr for later
90             }
91             else if(strncasecmp(&argv[n][m], "alias=", 6) == 0)
92             {
93                 if((alias = strchr(&argv[n][m+6], '@')) == NULL)
94                     alias = &argv[n][m+6];
95                 else
96                     alias++;
97             }
98             else if(strncasecmp(&argv[n][m], "d", 2) == 0)
99             {
100                 if(mode != 0)
101                 {
102                     fprintf(stderr, "ERROR: reverse, forward and d flags are mutually exclusive\n\n");
103                     exit(1);
104                 }
105                 mode = -1;
106             }
107             else if(strncasecmp(&argv[n][m], "forward", 8) == 0)
108             {
109                 if(mode != 0)
110                 {
111                     fprintf(stderr, "ERROR: reverse, forward and d flags are mutually exclusive\n\n");
112                     exit(1);
113                 }
114                 mode = 1;
115             }
116             else if(strncasecmp(&argv[n][m], "hashlength=", 11) == 0)
117             {
118                 hashlength = atoi(&argv[n][m+11]);
119                 if(hashlength < 1)
120                 {
121                     fprintf(stderr, "ERROR: Invalid hash length\n\n");
122                     exit(1);
123                 }
124             }
125             else if(strncasecmp(&argv[n][m], "help", 5) == 0)
126             {
127                 display_help();
128                 exit(0);
129             }
130             else if(strncasecmp(&argv[n][m], "reverse", 8) == 0)
131             {
132                 if(mode != 0)
133                 {
134                     fprintf(stderr, "ERROR: reverse, forward and d flags are mutually exclusive\n\n");
135                     exit(1);
136                 }
137                 mode = 2;
138             }
139             else if(strncasecmp(&argv[n][m], "secret=", 7) == 0)
140             {
141                 if(add_secret(&argv[n][m+7]))
142                 {
143                     fprintf(stderr, "ERROR: Out of memory\n\n");
144                     exit(1);
145                 }
146             }
147             else if(strncasecmp(&argv[n][m], "secretfile=", 11) == 0)
148             {
149                 FILE *fh;
150                 char buf[MAX_FILE_LINE_LENGTH];
151                 int l;
152 
153                 if((fh = fopen(&argv[n][m+11], "r")) == NULL)
154                 {
155                     fprintf(stderr, "ERROR: Could not open file '%s'\n\n", &argv[n][m+11]);
156                     exit(1);
157                 }
158 
159                 // Read in file and add secrets
160                 while(fgets(buf, MAX_FILE_LINE_LENGTH, fh))
161                 {
162                     l = strnlen(buf, MAX_FILE_LINE_LENGTH);
163                     if(buf[l-1] == '\n')
164                     {
165                         buf[l-1] = 0;
166                         l--;
167                     }
168 
169                     if(l > 0)
170                     {
171                         if(add_secret(strdup(buf)))
172                         {
173                             fprintf(stderr, "ERROR: Out of memory\n\n");
174                             exit(1);
175                         }
176                     }
177                 }
178 
179                 fclose(fh);
180             }
181             else if(strncasecmp(&argv[n][m], "separator=", 10) == 0)
182             {
183                 char c = argv[n][m+10];
184                 if(c == '+' || c == '-' || c == '=')
185                     separator = c;
186                 else
187                 {
188                     fprintf(stderr, "ERROR: Invalid separtor '%c'\n\n", c);
189                     exit(1);
190                 }
191             }
192             else if(strncasecmp(&argv[n][m], "socket=", 7) == 0)
193             {
194                 if(mode != -1)
195                 {
196                     fprintf(stderr, "ERROR: socket must come after d\n\n");
197                     exit(1);
198                 }
199                 socket_name = &argv[n][m+7];
200             }
201             else
202             {
203                 fprintf(stderr, "ERROR: Unknown flag '%s'\n\n", argv[n]);
204                 exit(1);
205             }
206         }
207     }
208 
209 
210     /*
211        -- CHECK SETTINGS --
212     */
213     if(mode == 1 && alias == NULL)
214     {
215         fprintf(stderr, "ERROR: You must specify an alias\n\n");
216         exit(1);
217     }
218 
219     if(secrets_count == 0)
220     {
221         fprintf(stderr, "ERROR: No secret specified\n\n");
222         exit(1);
223     }
224 
225 
226     /*
227        -- SET UP SRS HANDLES --
228     */
229     start_srs();
230 
231 
232     /*
233        -- PERFORM TASK --
234     */
235     if(mode == 1 || mode == 2)
236     {
237         // Command line call
238         n = 1;
239         for(n = 1; n < argc; n++)
240         {
241             if(argv[n][0] == '-')
242             {
243                 // Flag
244                 if(argv[n][1] == '-')
245                     m = 2;
246                 else
247                     m = 1;
248 
249                 // If not address flag, go on to next param
250                 if(strncasecmp(&argv[n][m], "address=", 8) != 0)
251                     continue;
252 
253                 // Set pointer
254                 add = &argv[n][m+8];
255             }
256             else
257                 add = argv[n];
258 
259             // Do it
260             if(mode == 1)
261                 do_forward(stdout, add, alias);
262             else
263                 do_reverse(stdout, add);
264         }
265     }
266     else if(mode == -1)
267         // Daemonise
268         srsd();
269     else
270     {
271         printf("ERROR: You must specify one of forward, reverse or d\n\n");
272         exit(1);
273     }
274 
275     // Should never get here!
276     return -1;
277 }
278 
279 
280 /***********************************************************
281     display_help - show help text
282 
283 */
display_help(void)284 int display_help(void)
285 {
286     printf("srs - libsrs_alt library http://opsec.eu/src/srs/\n(C)2004 Miles Wilton\n\n");
287     printf("Syntax: srs <flags> <address>+\n\n");
288     printf("    Actions\n");
289     printf("        -d               Run daemon\n");
290     printf("        --forward        Perform SRS forward on address\n");
291     printf("        --reverse        Perform SRS reverse on address\n");
292     printf("\n    Options\n");
293     printf("        --address=       Different way of specifying addresses to process\n");
294     printf("        --alias=         Alias domain (or address) for SRS forward\n");
295     printf("        --hashlength=    Characters in hash length\n");
296     printf("        --help           Display this help\n");
297     printf("        --secret=        SRS secret\n");
298     printf("        --secretfile=    Read file for SRS secret(s)\n");
299     printf("        --separator=     SRS separator, must be + - or =\n");
300     printf("        --socket=        Specify SRS socket for daemon\n");
301     printf("\nSyntax compatible with perl implementation Mail::SRS\nMultiple secrets and addresses supported, can also use - instead of --\n\n");
302 
303     return 0;
304 }
305 
306 
307 /***********************************************************
308     add_secret
309 
310 */
311 
add_secret(char * secret)312 int add_secret(char *secret)
313 {
314     // Check array space
315     if(secrets == NULL)
316     {
317         secrets = (char **)malloc(32 * sizeof(char *));
318         if(secrets == NULL)
319             return 1;
320         secrets_size = 32;
321     }
322 
323     if(secrets_size == secrets_count)
324     {
325         char **ra;
326 
327         ra = (char **)realloc(secrets, (secrets_count + 32) * sizeof(char *));
328         if(ra == NULL)
329             return 1;
330         secrets = (char **)ra;
331         secrets_count += 32;
332     }
333 
334     // Add to array
335     secrets[secrets_count++] = secret;
336 
337     return 0;
338 }
339 
340 
341 /***********************************************************
342     do_forward
343 
344 */
345 
do_forward(FILE * fh,char * add,char * als)346 int do_forward(FILE *fh, char *add, char *als)
347 {
348     char srsbuf[SRS_MAX_ADDRESS_LENGTH];
349     int r;
350 
351     // SRS Forward
352     if((r = srs_forward(srs, add, als, srsbuf, SRS_MAX_ADDRESS_LENGTH)) & SRS_RESULT_FAIL)
353         fprintf(fh, "ERROR: Address '%s' failed - %s\n", add, srs_geterrormsg(r));
354     else
355         fprintf(fh, "%s\n", srsbuf);
356 
357     return 0;
358 }
359 
360 
361 /***********************************************************
362     do_reverse
363 
364 */
365 
do_reverse(FILE * fh,char * add)366 int do_reverse(FILE *fh, char *add)
367 {
368     char srsbuf[SRS_MAX_ADDRESS_LENGTH];
369     int m, r;
370 
371     // SRS Reverse
372     for(m = 0; m < secrets_count; m++)
373     {
374         if((r = srs_reverse(srsa[m], add, srsbuf, SRS_MAX_ADDRESS_LENGTH)) & SRS_RESULT_FAIL)
375         {
376             if(r == SRS_RESULT_NOTSRS || r == SRS_RESULT_BADSRS || r == SRS_RESULT_HASHTOOSHORT
377                     || r == SRS_RESULT_BADTIMESTAMP || r == SRS_RESULT_BADTIMESTAMP)
378                 m = secrets_count;
379         }
380         else
381             break;
382     }
383 
384     if(m >= secrets_count)
385         fprintf(fh, "ERROR: Could not validate address '%s' - %s\n", add, srs_geterrormsg(r));
386     else
387     {
388         fprintf(fh, "%s\n", srsbuf);
389         if(r == SRS_RESULT_CASEBROKEN)
390             fprintf(fh, "WARNING: Case broken on hash in address '%s'\n", add);
391     }
392 }
393 
394 
395 /***********************************************************
396     start_srs
397 
398 */
399 
start_srs(void)400 int start_srs(void)
401 {
402     int n;
403 
404     if(mode == 1)
405     {
406         // Only one secret required, even if multiple secrets given
407         if((srs = srs_open(secrets[0], strnlen(secrets[0], SRS_MAX_SECRET_LENGTH), 0, hashlength, hashlength)) == NULL)
408         {
409             fprintf(stderr, "ERROR: SRS initialisation failed\n\n");
410             exit(1);
411         }
412     }
413     else
414     {
415         // For reverse or daemon, all secrets required
416         if((srsa = (srs_t **)malloc(secrets_count * sizeof(srs_t *))) == NULL)
417         {
418             fprintf(stderr, "ERROR: Out of memory\n\n");
419             exit(1);
420         }
421 
422         for(n = 0; n < secrets_count; n++)
423             if((srsa[n] = srs_open(secrets[n], strnlen(secrets[n], SRS_MAX_SECRET_LENGTH), 0, hashlength, hashlength)) == NULL)
424             {
425                 fprintf(stderr, "ERROR: SRS initialisation failed\n\n");
426                 exit(1);
427             }
428 
429         srs = srsa[0];
430     }
431 
432     return 0;
433 }
434 
435 
436 /***********************************************************
437     srsd
438 
439 */
440 
srsd(void)441 int srsd(void)
442 {
443     int n, children = 0;
444 
445     if((n = fork()) == 0)
446     {
447         // Child - open a socket and wait...
448 
449         int s, sl, ns, csl;
450         struct sockaddr_un *sa, cs;
451 
452         if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == 0)
453         {
454             printf("ERROR: Could not create socket\n\n");
455             exit(1);
456         }
457 
458         // Setup socket bind
459         sl = sizeof(sa->sun_family) + strlen(socket_name);
460         if((sa = (struct sockaddr_un *)malloc(sl)) == NULL)
461         {
462             printf("ERROR: Out of memory\n\n");
463             exit(1);
464         }
465 
466         sa->sun_family = AF_UNIX;
467         strcpy(sa->sun_path, socket_name);
468 
469         // Delete any file that might obstruct socket
470         unlink(socket_name);
471 
472         // Bind to socket
473         if(bind(s, (struct sockaddr *)sa, sl) != 0)
474         {
475             printf("ERROR: Could not bind to socket\n\n");
476             exit(1);
477         }
478 
479         // Listen for connections
480         if(listen(s, MAX_SOCKET_WAITING) != 0)
481         {
482             printf("ERROR: Could not listen to socket\n\n");
483             exit(1);
484         }
485 
486         // Setup SIGCHLD handler
487         signal(SIGCHLD, handle_signal);
488 
489         // Accept connections
490         csl = sizeof(cs);
491 
492         while((ns = accept(s, (struct sockaddr *)&cs, &csl)) > 0)
493         {
494             // Start thread to process request
495             if(fork() == 0)
496             {
497                 FILE *sr;
498                 char buf[MAX_SOCKET_LINE_LENGTH];
499                 int nn, nl;
500 
501                 // Open for reading
502                 if((sr = fdopen(ns, "r+")) == NULL)
503                 {
504                     printf("ERROR: Failed to open descriptor\n");
505 
506                     // Close socket and continue
507                     close(ns);
508                     continue;
509                 }
510 
511                 // Wait for command
512                 fgets(buf, MAX_SOCKET_LINE_LENGTH, sr);
513                 nl = strnlen(buf, MAX_SOCKET_LINE_LENGTH);
514 
515                 // Remove \n from end of string
516                 {
517                 if(buf[nl-1] == '\n')
518                     buf[nl-1] = 0;
519                     nl--;
520                 }
521 
522                 // Process command
523                 if(strncasecmp(buf, "forward ", 8) == 0)
524                 {
525                     for(nn = 8; nn < nl; nn++)
526                         if(buf[nn] == ' ')
527                             break;
528                     if(nn >= nl)
529                         fprintf(sr, "ERROR\n");
530                     else
531                     {
532                         buf[nn++] = 0;
533                         do_forward(sr, &buf[n+8], &buf[nn]);
534                     }
535                 }
536                 else if(strncasecmp(buf, "reverse ", 8) == 0)
537                     do_reverse(sr, &buf[n+8]);
538                 else
539                     fprintf(sr, "ERROR\n");
540 
541                 // Close stream
542                 fclose(sr);
543 
544                 // Close socket
545                 close(ns);
546 
547                 // End thread
548                 exit(0);
549             }
550             else
551             {
552                 // Close socket handle as far as parent is concerned
553                 close(ns);
554             }
555 
556             // Reset csl
557             csl = sizeof(cs);
558         }
559 
560         // Close socket
561         close(s);
562 
563         // Close handles and free memory
564         for(n = 0; n < secrets_count; n++)
565             srs_close(srsa[n]);
566         free(srsa);
567         free(secrets);
568 
569         exit(0);
570     }
571     else
572     {
573         // Parent - quits peacably if successful
574         printf("srs - libsrs_alt library http://srs.mirtol.com/\n�2004 Miles Wilton\n\n");
575         if(n == -1)
576         {
577             printf("ERROR: fork() failed\n");
578             exit(1);
579         }
580 
581         printf("Daemon started\n");
582         exit(0);
583     }
584 }
585 
586 
587 /***********************************************************
588     srsd
589 
590 */
591 
handle_signal(int signum)592 void handle_signal(int signum)
593 {
594     if(signum == SIGCHLD)
595         wait(NULL);
596 }
597 
598