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