1 /*
2  * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $Id: support.c,v 1.35 2003/02/13 02:38:43 maf Exp $
27  */
28 
29 #include "ftinclude.h"
30 #include "ftlib.h"
31 
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <limits.h>
42 #include <netdb.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <syslog.h>
47 #include <time.h>
48 #include <fcntl.h>
49 
50 #if !HAVE_STRSEP
51   char    *strsep (char **, const char *);
52 #endif
53 
54 #ifndef IN_CLASSD_NET
55 #define IN_CLASSD_NET 0xf0000000
56 #endif
57 
58 /*
59  * lookup table for mask length to mask
60  *
61  *               (first 8)
62  *  128.0.0.0 192.0.0.0 224.0.0.0 240.0.0.0
63  *  248.0.0.0 252.0.0.0 254.0.0.0 255.0.0.0
64  *
65  */
66 uint32_t mask_lookup[] = { 0xffffffff,
67      0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
68      0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
69      0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
70      0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
71      0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
72      0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
73      0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
74      0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff };
75 
76 /*
77  * function ipv4_len2mask
78  *
79  * returns the 32 bit network mask given a length
80  *
81 */
ipv4_len2mask(uint8_t len)82 uint32_t ipv4_len2mask(uint8_t len)
83 {
84   return mask_lookup[(len > 32) ? 0 : len];
85 }
86 
87 /*
88  * function: load_lookup
89  *
90  *  loads a list of , seperated numbers into an array
91  *  ! will invert the list
92  *  - can be used as a range operator
93  *
94  *  example
95  *   1,5-10   == 1,5,6,7,8,9,10
96  *   !1       == all numbers in the range except for 1
97  */
load_lookup(char * s,int size,char * list)98 int load_lookup(char *s, int size, char *list)
99 {
100   char *p;
101   int j, k;
102   unsigned i, i2;
103 
104   p = s;
105 
106   while ((*p == ' ') || (*p == '\t')) ++p;
107   if (*p == '!') {
108     for (k = 0; k < size; ++k)
109       list[k] = 1;
110     k = 0;
111     ++p;
112   } else {
113     for (k = 0; k < size; ++k)
114       list[k] = 0;
115     k = 1;
116   }
117 
118   while (*p) {
119 
120     i = (unsigned)strtol(p, (char**)0L, 0);
121     if (i >= size) return -1;
122     list[i] = k;
123 
124     /* skip to , or - */
125     while (*p && (*p != ',') && (*p != '-')) ++p;
126 
127     if (*p == '-') {
128 
129       ++p;
130       i2 = (unsigned)strtol(p, (char**)0L, 0);
131       if (i2 >= size) return -1;
132       for (j = i; j <= i2; ++j) list[j] = k;
133 
134       /* skip to , or - */
135       while (*p && (*p != ',') && (*p != '-')) ++p;
136     }
137 
138     /* skip past , and - */
139     while (*p && ((*p == ',') || (*p == '-'))) ++p;
140 
141   } /* *p */
142 
143   return 0;
144 
145 } /* load_lookup */
146 
147 /*
148  * function: scan_peeri
149  *
150  * scan peer identifier
151  *
152  * scan 1.2.3.4/1.2.3.4/nn[/nnl]
153  *      locip   remip   port  ttl
154  * into ftpeer struct
155  */
scan_peeri(char * input)156 struct ftpeeri scan_peeri(char *input)
157 {
158   struct ftpeeri ftpi;
159   char *s, *s2, *locip, *remip, *dstport, *ttl;
160 
161   bzero (&ftpi, sizeof ftpi);
162   ftpi.dst_port = FT_PORT;
163 
164   locip = remip = dstport = ttl = (char*)0L;
165 
166   if (!(s = malloc(strlen(input)+1))) {
167     fterr_warn("malloc");
168     return ftpi;
169   }
170 
171   /* keep track of original pointer to free */
172   s2 = s;
173 
174   strcpy(s, input);
175 
176   locip = s;
177   if (*s) {
178   }
179 
180   for (; *s && *s != '/'; ++s);
181   if (*s) {
182     *s = 0;
183     remip = ++s;
184   }
185 
186   for (; *s && *s != '/'; ++s);
187   if (*s) {
188     *s = 0;
189     dstport = ++s;
190   }
191 
192   for (; *s && *s != '/'; ++s);
193   if (*s) {
194     *s = 0;
195     ttl = ++s;
196   }
197 
198   if (locip)
199     ftpi.loc_ip = scan_ip(locip);
200   if (remip)
201     ftpi.rem_ip = scan_ip(remip);
202   if (dstport)
203     ftpi.dst_port = atoi(dstport);
204   if (ttl)
205     ftpi.ttl = atoi(ttl);
206 
207   free (s2);
208 
209   return ftpi;
210 
211 } /* scan_peer */
212 
scan_ip_prefix(char * input)213 struct ip_prefix scan_ip_prefix(char *input)
214 {
215   struct ip_prefix p;
216   char *s, *s2;
217   int has_slash;
218 
219   has_slash = 0;
220 
221   bzero(&p, sizeof p);
222 
223   for (s = input; *s; ++s)
224     if (*s == '/') {
225       has_slash = 1;
226       break;
227     }
228 
229   if (!has_slash) {
230     p.addr = scan_ip(input);
231     if ((IN_CLASSA(p.addr)) && (p.addr == (p.addr & IN_CLASSA_NET)))
232       p.len = 8;
233     else if ((IN_CLASSB(p.addr)) && (p.addr == (p.addr & IN_CLASSB_NET)))
234       p.len = 16;
235     else if ((IN_CLASSC(p.addr)) && (p.addr == (p.addr & IN_CLASSC_NET)))
236       p.len = 24;
237     else if ((IN_CLASSD(p.addr)) && (p.addr == (p.addr & IN_CLASSD_NET)))
238       p.len = 28;
239     else
240       p.len = 32;
241   } else {
242 
243     if (!(s = malloc(strlen(input)+1))) {
244       fterr_warn("malloc");
245       return p;
246     }
247 
248     s2 = s;
249 
250     strcpy(s, input);
251 
252     for (; *s2 && *s2 != '/'; ++s2);
253     if (*s2) {
254       *s2 = 0;
255       ++s2;
256     }
257 
258     p.addr = scan_ip(s);
259     p.len = atoi(s2);
260 
261     free (s);
262   }
263 
264   if (p.len > 32)
265     p.len = 32;
266 
267   return p;
268 
269 } /* scan_ip_prefix */
270 
271 /*
272  * function: scan_ip
273  *
274  *  IP address in string S is converted to a u_long
275  *  (borrowed from tcpdump)
276  *
277  *  left shift any partial dotted quads, ie 10 is 0x0a000000 not 0x0a
278  *  so scan_ip_prefix() works for standard prefix notation, ie 10/8
279  */
scan_ip(char * s)280 uint32_t scan_ip(char *s)
281 {
282   struct hostent *he;
283   struct in_addr *ina;
284   uint32_t addr = 0;
285   unsigned int n;
286   int dns, shift = 0;
287   char *t;
288 
289   /* if there is anything ascii in here, this may be a hostname */
290   for (dns = 0, t = s; *t; ++t) {
291     if (islower((int)*t) || isupper((int)*t)) {
292       dns = 1;
293       break;
294     }
295   }
296 
297   if (dns) {
298 
299     if (!(he = gethostbyname(s)))
300       goto numeric;
301 
302     if (he->h_addrtype != AF_INET)
303       goto numeric;
304 
305     if (he->h_length != sizeof (uint32_t))
306       goto numeric;
307 
308     ina = (struct in_addr*)*he->h_addr_list;
309     return (ntohl(ina->s_addr));
310 
311   } /* dns */
312 
313 numeric:
314   while (1) {
315 
316     /* n is the nibble */
317     n = 0;
318 
319     /* nibble's are . bounded */
320     while (*s && (*s != '.') && (*s != ' ') && (*s != '\t'))
321       n = n * 10 + *s++ - '0';
322 
323     /* shift in the nibble */
324     addr <<=8;
325     addr |= n & 0xff;
326     ++shift;
327 
328     /* return on end of string */
329     if ((!*s) || (*s == ' ') || (*s == '\t'))
330       goto ndone;
331 
332     /* skip the . */
333     ++s;
334   } /* forever */
335 
336 ndone:
337 
338   for (; shift < 4; ++shift)
339     addr <<=8;
340 
341   return addr;
342 
343 } /* scan_ip */
344 
345 
346 /*
347  * function: print_3float
348  *
349  *  format a floating point # to stdout w. 1 trailing space
350  *
351  */
print_3float(float f)352 void print_3float(float f)
353 {
354 
355   char s[10], *c;
356   sprintf(s, "%-3.3f", f);
357   c = s + 1;
358   printf("%s ", c);
359 
360 } /* print_3float */
361 
362 /*
363  * function: print_3float2
364  *
365  *  format a floating point # to stdout w. 2 trailing spaces
366  *
367  */
print_3float2(float f)368 void print_3float2(float f)
369 {
370 
371   char s[10], *c;
372   sprintf(s, "%-3.3f", f);
373   c = s + 1;
374   printf("%s  ", c);
375 
376 } /* print_3float */
377 
378 /* adapted from dd */
scan_size(char * val)379 int64_t scan_size(char *val)
380 {
381   uint64_t num, t;
382   char *expr;
383 
384   if ((num = strtoul(val, &expr, 0)) == ULONG_MAX)
385     goto erange;
386 
387   switch(*expr) {
388 
389     case 0:
390       break;
391 
392     case 'b':
393       t = num;
394       num *= 512;
395       if (t > num)
396         goto erange;
397       break;
398     case 'G':
399       t = num;
400       num *= 1024;
401       num *= 1024;
402       num *= 1024;
403       if (t > num)
404         goto erange;
405       break;
406     case 'K':
407       t = num;
408       num *= 1024;
409       if (t > num)
410         goto erange;
411       break;
412     case 'M':
413       t = num;
414       num *= 1024;
415       num *= 1024;
416       if (t > num)
417         goto erange;
418       break;
419     default:
420       goto erange;
421   }
422 
423   return num;
424 
425 erange:
426 
427   return (int64_t)-1;
428 
429 } /* scan_size */
430 
431 #if HAVE_SIGACTION
432 /*
433  * Function: mysignal()
434  *  POSIX style signals.
435  *
436  *  signal() has different semantics over different versions of unix.
437  *  this emulates signal() with sigaction() to behave like BSD.
438  *
439  * From Stevens Advanced Programming in the UNIX environment
440  *
441  */
mysignal(int signo,void * func)442 void *mysignal(int signo, void *func)
443 {
444   struct sigaction act, oact;
445 
446   act.sa_handler = (void*)func;
447   sigemptyset(&act.sa_mask);
448   act.sa_flags = 0;
449 
450   if (signo == SIGALRM) {
451 #ifdef  SA_INTERRUPT
452   act.sa_flags |= SA_INTERRUPT; /* SunOS */
453 #endif
454   } else {
455 #ifdef SA_RESTART
456   act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */
457 #endif
458   }
459 
460   if (sigaction(signo, &act, &oact) < 0)
461     return SIG_ERR;
462 
463   return oact.sa_handler;
464 } /* signal */
465 
466 #else /* SIGACTION */
467 
mysignal(int signo,void * func)468 void *mysignal(int signo, void *func)
469 { return signal(signo, func) };
470 
471 #endif /* SIGACTION */
472 
473 
474 
475 int unlink_pidfile(int pid, char *file, uint16_t port)
476 {
477   char *c;
478   int ret;
479 
480   if (!(c = (char*)malloc(strlen(file)+16)))
481     return -1;
482 
483   sprintf(c, "%s.%d", file, (int)port);
484 
485   if ((ret = unlink(c)) < 0)
486     fterr_warn("unlink(%s)", c);
487 
488   free (c);
489 
490   return ret;
491 
492 } /* unlink_pidfile */
493 
494 
495 int write_pidfile(int pid, char *file, uint16_t port)
496 {
497   int fd, len;
498   char str[16], *c;
499 
500   if (!(c = (char*)malloc(strlen(file)+16)))
501     return -1;
502 
503   sprintf(c, "%s.%d", file, (int)port);
504 
505   len = sprintf(str, "%u\n", (unsigned)pid);
506 
507   if ((fd = open(c, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0 ) {
508     fterr_warn("open(%s)", c);
509     free (c);
510     return -1;
511   }
512 
513 
514   if (write(fd, str, len) != len) {
515     fterr_warn("write(%s)", c);
516     close (fd);
517     free (c);
518     return -1;
519   }
520 
521   return close (fd);
522 
523 } /* write_pidfile */
524 
525 
526 /*
527  * function get_gmtoff
528  *
529  * return offset from GMT in seconds
530  *
531  * based on compute_tz() code by Michael R. Elkins
532  */
533 int get_gmtoff(time_t t)
534 {
535   struct tm *tmp, local, gmt;
536   time_t t2;
537   int yday;
538   tmp = gmtime(&t);
539   bcopy(tmp, &gmt, sizeof gmt);
540 
541   tmp = localtime(&t);
542   bcopy(tmp, &local, sizeof local);
543 
544   /* calculate difference in seconds */
545   t2 = (local.tm_hour - gmt.tm_hour) * 60; /* to minutes */
546   t2 += (local.tm_min - gmt.tm_min); /* minutes */
547   t2 *= 60; /* to seconds */
548 
549   /* diff day */
550   yday = (local.tm_yday - gmt.tm_yday);
551 
552   if ((yday == -1) || (yday > 1))
553     t2 -= 86400; /* sub one day */
554   else if (yday != 0)
555     t2 += 86400; /* add one day */
556 
557   return t2;
558 
559 } /* get_gmtoff */
560 
561 /*
562  * function: bigsockbuf
563  *
564  * There is no portable way to determine the max send and receive buffers
565  * that can be set for a socket, so guess then decrement that guess by
566  * 2K until the call succeeds.  If n > 1MB then the decrement by .5MB
567  * instead.
568  *
569  * returns size or -1 for error
570 */
571 int bigsockbuf(int fd, int dir, int size)
572 {
573   int n, tries;
574 
575   /* initial size */
576   n = size;
577   tries = 0;
578 
579   while (n > 4096) {
580 
581     if (setsockopt(fd, SOL_SOCKET, dir, (char*)&n, sizeof (n)) < 0) {
582 
583       /* anything other than no buffers available is fatal */
584       if (errno != ENOBUFS) {
585         fterr_warn("setsockopt(size=%d)", n);
586         return -1;
587       }
588 
589       /* try a smaller value */
590 
591       if (n > 1024*1024) /* most systems not > 256K bytes w/o tweaking */
592         n -= 1024*1024;
593       else
594         n -= 2048;
595 
596       ++tries;
597 
598     } else {
599 
600       fterr_info("setsockopt(size=%d)", n);
601       return n;
602 
603     }
604 
605   } /* while */
606 
607   /* no increase in buffer size */
608   return 0;
609 
610 } /* bigsockbuf */
611 
612 /*
613  * function: mkpath
614  *
615  * make the path to a filename.
616  *
617  * returns 0: ok
618  *         -1 fail
619  *
620 */
621 int mkpath(const char *path, mode_t mode)
622 {
623   char *c, *cs = NULL, *c2 = NULL, *p, *p2;
624   int len, ret, done, nodir;
625 
626   len = strlen(path);
627   c = (char*)0L;
628   ret = -1;
629   done = 0;
630 
631   if (!(c = (char*)malloc(len+1))) {
632     fterr_warn("malloc()");
633     goto mkpath_out;
634   }
635 
636   if (!(c2 = (char*)malloc(len+1))) {
637     fterr_warn("malloc()");
638     goto mkpath_out;
639   }
640 
641   cs = c;
642   strcpy(c, path);
643   c2[0] = 0;
644 
645   while (c && !done) {
646 
647     /* break out pathname components in p */
648     if (!(p = strsep(&c, "/")))
649       break;
650 
651     /* end of string? */
652     if (!c)
653       break;
654 
655     for (done = 1, p2 = c; p2 && *p2; ++p2)
656       if (*p2 == '/') {
657         done = 0;
658         break;
659       }
660 
661     /* build path */
662     strcat(c2, p);
663     nodir = 0;
664 
665     if (p[0] == '.' && p[1] == 0)
666       nodir = 1;
667 
668     if (p[0] == '.' && p[1] == '.' && p[2] == 0)
669       nodir = 1;
670 
671     if (p[0] == 0)
672       nodir = 1;
673 
674     if (!nodir) {
675 
676       if (mkdir(c2, mode) < 0) {
677         if (errno != EEXIST) {
678           fterr_warn("mkdir(%s)", c2);
679           goto mkpath_out;
680         }
681       }
682 
683     } /* nodir */
684 
685     strcat(c2, "/");
686 
687   }
688 
689   ret = 0;
690 
691 mkpath_out:
692 
693   if (cs)
694     free(cs);
695 
696   if (c2)
697     free(c2);
698 
699   return ret;
700 
701 } /* mkpath */
702 
703 /*
704  * function: udp_cksum
705  *
706  * calculate checksum of IP pseudo header plus UDP header
707  *
708  */
709 int udp_cksum(struct ip *ip, struct udphdr *up, int len)
710 {
711   uint16_t *word;
712   int sum;
713 
714   word = (uint16_t*)&ip->ip_src.s_addr;
715   sum = *word++;
716   sum += *word;
717 
718   word = (uint16_t*)&ip->ip_dst.s_addr;
719   sum += *word++;
720   sum += *word;
721 
722   sum += htons(len);
723 
724   sum += IPPROTO_UDP<<8;
725 
726   word = (unsigned short*)up;
727   sum += *word++;
728   sum += *word++;
729   sum += *word++;
730 
731   return sum;
732 } /* udp_cksum */
733 
734