Prevent wrapper.c from flooding the IRC server.
[iii.git] / wrapper.c
blobcba27c074e04aee8edc8bda83f1bd65f823e7870
1 /*
2 * The author of this work has dedicated it to the public by waiving all of his
3 * or her rights to the work under copyright law and all related or neighboring
4 * legal rights he or she had in the work, to the extent allowable by law.
5 */
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
10 #include <err.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
18 #define LOCATE_HP(a, b) (((a) - (b)) / 2 + 1)
20 static size_t host_is_valid(char *);
21 static size_t is_sh_clear(char *);
22 static int port_is_valid(char *);
23 static void usage(void);
25 int
26 main(int argc, char **argv)
28 const unsigned int uargc = (unsigned int)argc;
29 char *args[2] = {NULL, NULL}, *init = NULL;
30 size_t n, o, s;
31 int ch, rv;
32 pid_t pids[2], sid;
34 if (uargc < 3) usage();
35 while ((ch = getopt(argc, argv, "i:s:")) != -1)
36 switch (ch) {
37 case 'i':
38 if (is_sh_clear(optarg))
39 errx(1, "sh(1) meta-characters and quotation"
40 " marks are not allowed in `ii arg'.");
41 args[0] = optarg;
42 break;
43 case 's':
44 if (is_sh_clear(optarg))
45 errx(1, "sh(1) meta-characters and quotation"
46 " marks are not allowed in `sh arg'.");
47 args[1] = optarg;
48 break;
49 default:
50 usage();
51 /* NOTREACHED */
54 for (o = 1; o < uargc - 2; o++)
55 if (!strcmp(argv[o], "--"))
56 break;
57 o++; /* argv[o] is now the first hostname, hopefully: */
58 if ((uargc - o) & 1) usage();
60 for (n = o; n < uargc; n++) /* Validate the hosts and ports. */
61 if ((n - o) & 1) {
62 if ((rv = port_is_valid(argv[n])) < 0)
63 errx(1, "Port number `%lu' is not in range.",
64 (unsigned long)LOCATE_HP(n, o));
65 else if (rv > 0)
66 errx(1, "Character `%lu' in port `%lu' is not"
67 " allowed.", (unsigned long)rv,
68 (unsigned long)LOCATE_HP(n, o));
69 } else
70 if ((rv = host_is_valid(argv[n])) != NULL)
71 errx(1, "Character `%lu' in hostname `%lu' is"
72 " not allowed.", (unsigned long)rv,
73 (unsigned long)LOCATE_HP(n, o));
75 if (args[0]) printf("ii arg: `%s'.\n", args[0]);
76 if (args[1]) printf("sh arg: `%s'.\n", args[1]);
77 for (n = o; n < uargc - 1; n += 2)
78 printf("Server[%lu]: %s:%d\n", (unsigned long)LOCATE_HP(n, o),
79 argv[n], atoi(argv[n + 1]));
81 pids[0] = fork();
82 if (pids[0] < 0)
83 exit(1);
84 else if (pids[0] > 0)
85 exit(0);
87 umask(0);
89 sid = setsid();
90 if (sid < 0)
91 _exit(1);
93 if ((chdir("/")) < 0)
94 _exit(1);
96 close(STDIN_FILENO);
97 close(STDOUT_FILENO);
98 close(STDERR_FILENO);
100 srandom(time(NULL));
102 for (;;) {
103 if (args[1] && pids[1] > 0) {
104 if (kill(pids[1], SIGKILL) && errno != ESRCH)
105 _exit(1);
106 waitpid(0, NULL, 0);
109 sleep(LOOP_SLEEP);
111 /* http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx */
112 n = o + 1 + random() * 1.0 / ( RAND_MAX + 1.0 ) * (uargc - o - 1);
113 if ((n - o) & 1) n--;
114 s = strlen(args[0]) + strlen(argv[n]) + strlen(argv[n + 1]) + 10
115 + sizeof(II_EXEC);
117 if ((init = calloc(s, 1)) == NULL)
118 _exit(1);
119 strlcpy(init, II_EXEC" ", s);
120 strlcat(init, args[0], s);
121 strlcat(init, " -s ", s);
122 strlcat(init, argv[n], s);
123 strlcat(init, " -p ", s);
124 strlcat(init, argv[n + 1], s);
126 if (args[1]) {
127 pids[1] = fork();
128 if (pids[1] < 0) {
129 _exit(1);
130 } else if (pids[1] > 0) {
131 system(init);
132 free(init);
133 continue;
136 sleep(CHLD_SLEEP);
137 system(args[1]);
138 _exit(0);
139 } else {
140 system(init);
141 free(init);
146 static size_t
147 host_is_valid(char *h)
149 size_t n;
152 * Permitted characters in a hostname:
153 * a-z (0x61 <= c <= 0x7a)
154 * 0-9 (0x30 <= c <= 0x39)
155 * A-Z (0x41 <= c <= 0x5a)
156 * .-
158 for (n = 0; n < strlen(h); n++)
159 if (((h[n] < 0x61 || h[n] > 0x7a) && (h[n] < 0x30 ||
160 h[n] > 0x39) && (h[n] < 0x41 || h[n] > 0x5a))
161 && h[n] != '.' && h[n] != '-')
162 return n + 1;
163 return 0;
166 static size_t
167 is_sh_clear(char *s)
169 size_t n;
171 for (n = 0; n < strlen(s); n++)
172 if (s[n] == '<' || s[n] == '>' || s[n] == '|' || s[n] == ';' ||
173 s[n] == '(' || s[n] == ')' || s[n] == '&' || s[n] == '"' ||
174 s[n] == '\'')
175 if (n && s[n - 1] != '\\')
176 return n + 1;
177 return 0;
180 static int
181 port_is_valid(char *p)
183 size_t n;
185 if (atoi(p) < 1 || atoi(p) > 65535)
186 return -1;
188 for (n = 0; n < strlen(p); n++)
189 if (p[n] < 0x30 || p[n] > 0x39)
190 return n + 1;
191 return 0;
194 static void
195 usage(void)
197 extern char *__progname;
199 (void)fprintf(stderr, "usage: %s [-i ii arg] [-s sh arg] \\\n\t --"
200 " host1 port1 [host2 port2 ...]\n", __progname);
201 exit(1);