Added contact info to README-repo_or_cz.html.
[iii.git] / wrapper.c
blob997110050fe9717cddafdbaf5bc3f50ec8c510dc
1 #include <sys/stat.h>
2 #include <sys/types.h>
3 #include <sys/wait.h>
5 #include <err.h>
6 #include <errno.h>
7 #include <signal.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
13 #define LOCATE_HP(a, b) (((a) - (b)) / 2 + 1)
15 static size_t host_is_valid(char *);
16 static size_t is_sh_clear(char *);
17 static int port_is_valid(char *);
18 static void usage(void);
20 int
21 main(int argc, char **argv)
23 const unsigned int uargc = (unsigned int)argc;
24 char *args[2] = {NULL, NULL}, *init = NULL;
25 size_t n, o, s;
26 int ch, rv;
27 pid_t pids[2], sid;
29 if (uargc < 3) usage();
30 while ((ch = getopt(argc, argv, "i:s:")) != -1)
31 switch (ch) {
32 case 'i':
33 if (is_sh_clear(optarg))
34 errx(1, "sh(1) meta-characters and quotation"
35 " marks are not allowed in `ii arg'.");
36 args[0] = optarg;
37 break;
38 case 's':
39 if (is_sh_clear(optarg))
40 errx(1, "sh(1) meta-characters and quotation"
41 " marks are not allowed in `sh arg'.");
42 args[1] = optarg;
43 break;
44 default:
45 usage();
46 /* NOTREACHED */
49 for (o = 1; o < uargc - 2; o++)
50 if (!strcmp(argv[o], "--"))
51 break;
52 o++; /* argv[o] is now the first hostname, hopefully: */
53 if ((uargc - o) & 1) usage();
55 for (n = o; n < uargc; n++) /* Validate the hosts and ports. */
56 if ((n - o) & 1) {
57 if ((rv = port_is_valid(argv[n])) < 0)
58 errx(1, "Port number `%lu' is not in range.",
59 (unsigned long)LOCATE_HP(n, o));
60 else if (rv > 0)
61 errx(1, "Character `%lu' in port `%lu' is not"
62 " allowed.", (unsigned long)rv,
63 (unsigned long)LOCATE_HP(n, o));
64 } else
65 if ((rv = host_is_valid(argv[n])) != NULL)
66 errx(1, "Character `%lu' in hostname `%lu' is"
67 " not allowed.", (unsigned long)rv,
68 (unsigned long)LOCATE_HP(n, o));
70 if (args[0]) printf("ii arg: `%s'.\n", args[0]);
71 if (args[1]) printf("sh arg: `%s'.\n", args[1]);
72 for (n = o; n < uargc - 1; n += 2)
73 printf("Server[%lu]: %s:%d\n", (unsigned long)LOCATE_HP(n, o),
74 argv[n], atoi(argv[n + 1]));
76 pids[0] = fork();
77 if (pids[0] < 0)
78 exit(1);
79 else if (pids[0] > 0)
80 exit(0);
82 umask(0);
84 sid = setsid();
85 if (sid < 0)
86 _exit(1);
88 if ((chdir("/")) < 0)
89 _exit(1);
91 close(STDIN_FILENO);
92 close(STDOUT_FILENO);
93 close(STDERR_FILENO);
95 srandom(time(NULL));
97 for (;;) {
98 if (args[1] && pids[1] > 0) {
99 if (kill(pids[1], SIGKILL) && errno != ESRCH)
100 _exit(1);
101 waitpid(0, NULL, 0);
104 /* http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx */
105 n = o + 1 + random() * 1.0 / ( RAND_MAX + 1.0 ) * (uargc - o - 1);
106 if ((n - o) & 1) n--;
107 s = strlen(args[0]) + strlen(argv[n]) + strlen(argv[n + 1]) + 10
108 + sizeof(EXECUTABLE);
110 if ((init = calloc(s, 1)) == NULL)
111 _exit(1);
112 strlcpy(init, EXECUTABLE" ", s);
113 strlcat(init, args[0], s);
114 strlcat(init, " -s ", s);
115 strlcat(init, argv[n], s);
116 strlcat(init, " -p ", s);
117 strlcat(init, argv[n + 1], s);
119 if (args[1]) {
120 pids[1] = fork();
121 if (pids[1] < 0) {
122 _exit(1);
123 } else if (pids[1] > 0) {
124 system(init);
125 free(init);
126 continue;
129 sleep(SSLEEP);
130 system(args[1]);
131 _exit(0);
132 } else {
133 system(init);
134 free(init);
139 static size_t
140 host_is_valid(char *h)
142 size_t n;
145 * Permitted characters in a hostname:
146 * a-z (0x61 <= c <= 0x7a)
147 * 0-9 (0x30 <= c <= 0x39)
148 * A-Z (0x41 <= c <= 0x5a)
149 * .-
151 for (n = 0; n < strlen(h); n++)
152 if (((h[n] < 0x61 || h[n] > 0x7a) && (h[n] < 0x30 ||
153 h[n] > 0x39) && (h[n] < 0x41 || h[n] > 0x5a))
154 && h[n] != '.' && h[n] != '-')
155 return n + 1;
156 return 0;
159 static size_t
160 is_sh_clear(char *s)
162 size_t n;
164 for (n = 0; n < strlen(s); n++)
165 if (s[n] == '<' || s[n] == '>' || s[n] == '|' || s[n] == ';' ||
166 s[n] == '(' || s[n] == ')' || s[n] == '&' || s[n] == '"' ||
167 s[n] == '\'')
168 if (n && s[n - 1] != '\\')
169 return n + 1;
170 return 0;
173 static int
174 port_is_valid(char *p)
176 size_t n;
178 if (atoi(p) < 1 || atoi(p) > 65535)
179 return -1;
181 for (n = 0; n < strlen(p); n++)
182 if (p[n] < 0x30 || p[n] > 0x39)
183 return n + 1;
184 return 0;
187 static void
188 usage(void)
190 extern char *__progname;
192 (void)fprintf(stderr, "usage: %s [-i ii arg] [-s sh arg] \\\n\t --"
193 " host1 port1 [host2 port2 ...]\n", __progname);
194 exit(1);