New upstream release.
[debian/iodine.git] / src / common.c
1 /* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
2  * Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <time.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/stat.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <fcntl.h>
29
30 #ifdef WINDOWS32
31 #include <winsock2.h>
32 #include <conio.h>
33 #else
34 #include <arpa/nameser.h>
35 #ifdef DARWIN
36 #include <arpa/nameser8_compat.h>
37 #endif
38 #include <termios.h>
39 #include <err.h>
40 #include <arpa/inet.h>
41 #include <netinet/in.h>
42 #endif
43
44 #include "common.h"
45
46 /* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
47 #if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
48 static int daemon(int nochdir, int noclose)
49 {
50         int fd, i;
51  
52         switch (fork()) {
53                 case 0:
54                         break;
55                 case -1:
56                         return -1;
57                 default:
58                         _exit(0);
59         }
60  
61         if (!nochdir) {
62                 chdir("/");
63         }
64  
65         if (setsid() < 0) {
66                 return -1;
67         }
68         
69         if (!noclose) {
70                 if ((fd = open("/dev/null", O_RDWR)) >= 0) {
71                         for (i = 0; i < 3; i++) {
72                                 dup2(fd, i);
73                         }
74                         if (fd > 2) {
75                                 close(fd);
76                         }
77                 }
78         }
79         return 0;
80 }
81 #endif
82
83 #if defined(__BEOS__) && !defined(__HAIKU__)
84 int setgroups(int count, int *groups)
85 {
86         /* errno = ENOSYS; */
87         return -1;
88 }
89 #endif
90
91
92 void
93 check_superuser(void (*usage_fn)(void))
94 {
95 #ifndef WINDOWS32
96         if (geteuid() != 0) {
97                 warnx("Run as root and you'll be happy.\n");
98                 usage_fn();
99                 /* NOTREACHED */
100         }
101 #endif
102 }
103
104 int 
105 open_dns(int localport, in_addr_t listen_ip) 
106 {
107         struct sockaddr_in addr;
108         int flag = 1;
109         int fd;
110
111         memset(&addr, 0, sizeof(addr));
112         addr.sin_family = AF_INET;
113         addr.sin_port = htons(localport);
114         /* listen_ip already in network byte order from inet_addr, or 0 */
115         addr.sin_addr.s_addr = listen_ip; 
116
117         if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
118                 fprintf(stderr, "got fd %d\n", fd);
119                 err(1, "socket");
120         }
121
122         flag = 1;
123 #ifdef SO_REUSEPORT
124         setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));
125 #endif
126         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
127
128 #ifndef WINDOWS32
129         /* To get destination address from each UDP datagram, see iodined.c:read_dns() */
130         setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
131 #endif
132
133 #ifdef IP_OPT_DONT_FRAG
134         /* Set dont-fragment ip header flag */
135         flag = DONT_FRAG_VALUE;
136         setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
137 #endif
138
139         if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
140                 err(1, "bind");
141
142         fprintf(stderr, "Opened UDP socket\n");
143
144         return fd;
145 }
146
147 void
148 close_dns(int fd)
149 {
150         close(fd);
151 }
152
153 void
154 do_chroot(char *newroot)
155 {
156 #if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))
157         if (chroot(newroot) != 0 || chdir("/") != 0)
158                 err(1, "%s", newroot);
159
160         seteuid(geteuid());
161         setuid(getuid());
162 #else
163         warnx("chroot not available");
164 #endif
165 }
166
167 void
168 do_detach()
169 {
170 #ifndef WINDOWS32
171         fprintf(stderr, "Detaching from terminal...\n");
172         daemon(0, 0);
173         umask(0);
174         alarm(0);
175 #else
176         fprintf(stderr, "Windows version does not support detaching\n");
177 #endif
178 }
179
180 void
181 read_password(char *buf, size_t len)
182 {
183         char pwd[80];
184 #ifndef WINDOWS32
185         struct termios old;
186         struct termios tp;
187
188         tcgetattr(0, &tp);
189         old = tp;
190         
191         tp.c_lflag &= (~ECHO);
192         tcsetattr(0, TCSANOW, &tp);
193 #else
194         int i;
195 #endif
196
197         fprintf(stderr, "Enter password: ");
198         fflush(stderr);
199 #ifndef WINDOWS32
200         scanf("%79s", pwd);
201 #else
202         for (i = 0; i < sizeof(pwd); i++) {
203                 pwd[i] = getch();
204                 if (pwd[i] == '\r' || pwd[i] == '\n') {
205                         pwd[i] = 0;
206                         break;
207                 } else if (pwd[i] == '\b') {
208                         i--;                    /* Remove the \b char */
209                         if (i >=0) i--;         /* If not first char, remove one more */
210                 }
211         }
212 #endif
213         fprintf(stderr, "\n");
214
215 #ifndef WINDOWS32
216         tcsetattr(0, TCSANOW, &old);    
217 #endif
218
219         strncpy(buf, pwd, len);
220         buf[len-1] = '\0';
221 }
222
223 int
224 check_topdomain(char *str)
225 {
226        int i;
227
228        if(str[0] == '.') /* special case */
229                return 1;
230
231        for( i = 0; i < strlen(str); i++) {
232                if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
233                        continue;
234                else 
235                        return 1;
236        }
237        return 0;
238 }
239
240 #ifdef WINDOWS32
241 int
242 inet_aton(const char *cp, struct in_addr *inp)
243 {
244  inp->s_addr = inet_addr(cp);
245  return inp->s_addr != INADDR_ANY;
246 }
247
248 void
249 warn(const char *fmt, ...)
250 {
251         va_list list;
252
253         va_start(list, fmt);
254         if (fmt) fprintf(stderr, fmt, list);
255         if (errno == 0) {
256                 fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); 
257         } else {
258                 fprintf(stderr, ": %s\n", strerror(errno));
259         }
260         va_end(list);
261 }
262
263 void
264 warnx(const char *fmt, ...)
265 {
266         va_list list;
267
268         va_start(list, fmt);
269         if (fmt) fprintf(stderr, fmt, list);
270         fprintf(stderr, "\n");
271         va_end(list);
272 }
273
274 void
275 err(int eval, const char *fmt, ...)
276 {
277         va_list list;
278
279         va_start(list, fmt);
280         warn(fmt, list);
281         va_end(list);
282         exit(eval);
283 }
284
285 void
286 errx(int eval, const char *fmt, ...)
287 {
288         va_list list;
289
290         va_start(list, fmt);
291         warnx(fmt, list);
292         va_end(list);
293         exit(eval);
294 }
295 #endif
296