1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  *    if any, must include the following acknowledgment:
22  *       "This product includes software developed by the
23  *        Kannel Group (http://www.kannel.org/)."
24  *    Alternately, this acknowledgment may appear in the software itself,
25  *    if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For written permission, please
30  *    contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  *    nor may "Kannel" appear in their name, without prior written
34  *    permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group.  For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * utils.c - generally useful, non-application specific functions for Gateway
59  *
60  */
61 
62 #include "gw-config.h"
63 
64 #include <ctype.h>
65 #include <errno.h>
66 #include <stdarg.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <time.h>
71 #include <unistd.h>
72 #include <termios.h>
73 #include <signal.h>
74 #include <sys/types.h>
75 #include <sys/wait.h>
76 #include <sys/stat.h>
77 #include <sys/utsname.h>
78 #include <fcntl.h>
79 #include <pwd.h>
80 #include <grp.h>
81 #include <libgen.h>
82 
83 #if HAVE_UCONTEXT
84 #include <sys/ucontext.h>
85 #endif
86 
87 #include "gwlib.h"
88 
89 #if HAVE_BACKTRACE
90 #include <execinfo.h> /*backtrace */
91 #endif
92 
93 /* Headers required for the version dump. */
94 #if defined(HAVE_LIBSSL) || defined(HAVE_WTLS_OPENSSL)
95 #include <openssl/opensslv.h>
96 #endif
97 #ifdef HAVE_MYSQL
98 #include <mysql_version.h>
99 #include <mysql.h>
100 #endif
101 /*
102  * PostgreSQL drives us in a mess here slights. Even
103  * if our own configure run didn't detect openssl and hence
104  * gw-config.h has no HAVE_LIBSSL set, it is generally set
105  * on most distro in <pg_config.h>, so we end up in unresolved
106  * items at some point. We trick this by undef it again here.
107  */
108 #ifdef HAVE_PGSQL
109 # ifndef HAVE_LIBSSL
110 # define UNDEF_LIBSSL 1
111 # endif
112 #include <libpq-fe.h>
113 #include <pg_config.h>
114 # ifdef UNDEF_LIBSSL
115 # undef HAVE_LIBSSL
116 # undef UNDEF_LIBSSL
117 # endif
118 #endif  /* HAVE_PGSQL */
119 #ifdef HAVE_SQLITE
120 #include <sqlite.h>
121 #endif
122 #ifdef HAVE_SQLITE3
123 #include <sqlite3.h>
124 #endif
125 #ifdef HAVE_ORACLE
126 #include <oci.h>
127 #endif
128 #ifdef HAVE_REDIS
129 #include <hiredis.h>
130 #endif
131 
132 
133 /* pid of child process when parachute is used */
134 static pid_t child_pid = -1;
135 /* pid of pid file owner */
136 static pid_t pidfile_owner_pid = -1;
137 /* saved child signal handlers */
138 static struct sigaction child_actions[32];
139 /* just a flag that child signal handlers are stored */
140 static int child_actions_init = 0;
141 /* our pid file name */
142 static char *pid_file = NULL;
143 static volatile sig_atomic_t parachute_shutdown = 0;
144 
145 
fatal_handler(int sig,siginfo_t * info,void * secret)146 static void fatal_handler(int sig, siginfo_t *info, void *secret)
147 {
148 #ifdef HAVE_BACKTRACE
149     void *trace[50];
150 #ifdef REG_EIP
151     ucontext_t *uc = (ucontext_t*)secret;
152 #endif
153     size_t size;
154 #endif
155     struct sigaction act;
156 
157     act.sa_handler = SIG_DFL;
158     sigemptyset(&act.sa_mask);
159     act.sa_flags = 0;
160     sigaction(sig, &act, NULL);
161 
162 #ifdef HAVE_BACKTRACE
163     size = backtrace(trace, sizeof(trace) / sizeof(void*));
164 #ifdef REG_EIP
165     /* overwrite sigaction with caller's address */
166     trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
167 #endif
168     gw_backtrace(trace, size, 0);
169 #endif
170 
171     raise(sig);
172 }
173 
174 
parachute_sig_handler(int signum)175 static void parachute_sig_handler(int signum)
176 {
177     info(0, "Signal %d received, forward to child pid (%ld)", signum, (long) child_pid);
178 
179     /* we do not handle any signal, just forward these to child process */
180     if (child_pid != -1 && getpid() != child_pid)
181         kill(child_pid, signum);
182 
183     /* if signal received and no child there, terminating */
184     switch(signum) {
185         case SIGTERM:
186         case SIGINT:
187         case SIGABRT:
188             if (child_pid == -1)
189                 exit(0);
190             else
191                 parachute_shutdown = 1;
192     }
193 }
194 
parachute_init_signals(int child)195 static void parachute_init_signals(int child)
196 {
197     struct sigaction sa;
198 
199     if (child_actions_init && child) {
200         sigaction(SIGTERM, &child_actions[SIGTERM], NULL);
201         sigaction(SIGQUIT, &child_actions[SIGQUIT], NULL);
202         sigaction(SIGINT,  &child_actions[SIGINT], NULL);
203         sigaction(SIGABRT, &child_actions[SIGABRT], NULL);
204         sigaction(SIGHUP,  &child_actions[SIGHUP], NULL);
205         sigaction(SIGALRM, &child_actions[SIGALRM], NULL);
206         sigaction(SIGUSR1, &child_actions[SIGUSR1], NULL);
207         sigaction(SIGUSR2, &child_actions[SIGUSR2], NULL);
208         sigaction(SIGPIPE, &child_actions[SIGPIPE], NULL);
209     }
210     else if (!child && !child_actions_init) {
211         sa.sa_flags = 0;
212         sigemptyset(&sa.sa_mask);
213         sa.sa_handler = parachute_sig_handler;
214         sigaction(SIGTERM, &sa, &child_actions[SIGTERM]);
215         sigaction(SIGQUIT, &sa, &child_actions[SIGQUIT]);
216         sigaction(SIGINT,  &sa, &child_actions[SIGINT]);
217         sigaction(SIGABRT, &sa, &child_actions[SIGABRT]);
218         sigaction(SIGHUP,  &sa, &child_actions[SIGHUP]);
219         sigaction(SIGALRM, &sa, &child_actions[SIGALRM]);
220         sigaction(SIGUSR1, &sa, &child_actions[SIGUSR1]);
221         sigaction(SIGUSR2, &sa, &child_actions[SIGUSR2]);
222         sa.sa_handler = SIG_IGN;
223         sigaction(SIGPIPE, &sa, &child_actions[SIGPIPE]);
224         sigaction(SIGTTOU, &sa, NULL);
225         sigaction(SIGTTIN, &sa, NULL);
226         sigaction(SIGTSTP, &sa, NULL);
227         child_actions_init = 1;
228         init_fatal_signals();
229     }
230     else
231         panic(0, "Child process signal handlers not initialized before.");
232 }
233 
is_executable(const char * filename)234 static int is_executable(const char *filename)
235 {
236     struct stat buf;
237 
238     if (stat(filename, &buf)) {
239         error(errno, "Error while stat of file `%s'", filename);
240         return 0;
241     }
242     if (!S_ISREG(buf.st_mode) && !S_ISLNK(buf.st_mode)) {
243         error(0, "File `%s' is not a regular file.", filename);
244         return 0;
245     }
246     /* others has exec permission */
247     if (S_IXOTH & buf.st_mode)
248         return 1;
249     /* group has exec permission */
250     if ((S_IXGRP & buf.st_mode) && buf.st_gid == getgid())
251         return 1;
252     /* owner has exec permission */
253     if ((S_IXUSR & buf.st_mode) && buf.st_uid == getuid())
254         return 1;
255 
256     return 0;
257 }
258 
259 /*
260  * become daemon.
261  * returns 0 for father process; 1 for child process
262  */
become_daemon(void)263 static int become_daemon(void)
264 {
265     int fd;
266     if (getppid() != 1) {
267        signal(SIGTTOU, SIG_IGN);
268        signal(SIGTTIN, SIG_IGN);
269        signal(SIGTSTP, SIG_IGN);
270        if (fork())
271           return 0;
272        setsid();
273     }
274 
275     close(STDIN_FILENO);
276     close(STDOUT_FILENO);
277     close(STDERR_FILENO);
278     fd = open("/dev/null", O_RDWR); /* stdin */
279     if (fd == -1)
280         panic(errno, "Could not open `/dev/null'");
281     dup(fd); /* stdout */
282     dup(fd); /* stderr */
283 
284     chdir("/");
285     return 1;
286 }
287 
288 #define PANIC_SCRIPT_MAX_LEN 4096
289 
execute_panic_script(const char * panic_script,const char * format,...)290 static PRINTFLIKE(2,3) void execute_panic_script(const char *panic_script, const char *format, ...)
291 {
292     char *args[3];
293     char buf[PANIC_SCRIPT_MAX_LEN + 1];
294     va_list ap;
295 
296     va_start(ap, format);
297     vsnprintf(buf, PANIC_SCRIPT_MAX_LEN, format, ap);
298     va_end(ap);
299 
300     if (fork())
301        return;
302 
303     close(STDIN_FILENO);
304     close(STDOUT_FILENO);
305     close(STDERR_FILENO);
306 
307     args[0] = (char*) panic_script;
308     args[1] = buf;
309     args[2] = NULL;
310 
311     execv(args[0], args);
312 }
313 
314 
parachute_start(const char * myname,const char * panic_script)315 static void parachute_start(const char *myname, const char *panic_script) {
316     time_t last_start = 0, last_panic = 0;
317     long respawn_count = 0;
318     int status;
319 
320 
321     if (panic_script && !is_executable(panic_script))
322         panic(0, "Panic script `%s' is not executable for us.", panic_script);
323 
324     /* setup sighandler */
325     parachute_init_signals(0);
326 
327     for (;;) {
328         if (respawn_count > 0 && difftime(time(NULL), last_start) < 10) {
329             error(0, "Child process died too fast, disabling for 30 sec.");
330             gwthread_sleep(30.0);
331         }
332         if (!(child_pid = fork())) { /* child process */
333             parachute_init_signals(1); /* reset sighandlers */
334 	    return;
335         }
336 	else if (child_pid < 0) {
337 	    error(errno, "Could not start child process! Will retry in 5 sec.");
338 	    gwthread_sleep(5.0);
339             continue;
340 	}
341 	else { /* father process */
342 	    time(&last_start);
343             info(0, "Child process with PID (%ld) started.", (long) child_pid);
344             do {
345                 if (waitpid(child_pid, &status, 0) == child_pid) {
346                     /* check here why child terminated */
347                    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
348                        info(0, "Child process exited gracefully, exit...");
349                        gwlib_shutdown();
350                        exit(0);
351                    }
352                    else if (WIFEXITED(status)) {
353                        error(0, "Caught child PID (%ld) which died with return code %d",
354                            (long) child_pid, WEXITSTATUS(status));
355                        child_pid = -1;
356                    }
357                    else if (WIFSIGNALED(status)) {
358                        error(0, "Caught child PID (%ld) which died due to signal %d",
359                            (long) child_pid, WTERMSIG(status));
360                        child_pid = -1;
361                    }
362                 }
363                 else if (errno != EINTR) {
364                     error(errno, "Error while waiting of child process.");
365                 }
366             } while(child_pid > 0);
367 
368             if (parachute_shutdown) {
369                 /* may only happens if child process crashed while shutdown */
370                 info(0, "Child process crashed while shutdown. Exiting due to signal...");
371                 info(0, "Going into gwlib_shutdown...");
372                 gwlib_shutdown();
373                 info(0, "gwlib_shutdown done... Bye bye...");
374                 exit(WIFEXITED(status) ? WEXITSTATUS(status) : 0);
375             }
376 
377             /* check whether it's panic while start */
378             if (respawn_count == 0 && difftime(time(NULL), last_start) < 2) {
379                 info(0, "Child process crashed while starting. Exiting...");
380                 info(0, "Going into gwlib_shutdown...");
381                 gwlib_shutdown();
382                 info(0, "gwlib_shutdown done... Bye bye...");
383                 exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
384             }
385 
386             respawn_count++;
387             if (panic_script && myname && difftime(time(NULL), last_panic) > 300) {
388                 time(&last_panic);
389                 debug("kannel", 0, "Executing panic script: %s %s %ld", panic_script, myname, respawn_count);
390                 execute_panic_script(panic_script, "%s %ld", myname, respawn_count);
391             }
392             /* sleep a while to get e.g. sockets released */
393             gwthread_sleep(5.0);
394 	}
395     }
396 }
397 
398 
write_pid_file(void)399 static void write_pid_file(void)
400 {
401     int fd;
402     FILE *file;
403 
404     if (!pid_file)
405         return;
406 
407     fd = open(pid_file, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT|O_EXCL, 0644);
408     if (fd == -1)
409         panic(errno, "Could not open pid-file `%s'", pid_file);
410 
411     file = fdopen(fd, "w");
412     if (!file)
413         panic(errno, "Could not open file-stream `%s'", pid_file);
414 
415     fprintf(file, "%ld\n", (long) (pidfile_owner_pid = getpid()));
416     fclose(file);
417 }
418 
remove_pid_file(void)419 static void remove_pid_file(void)
420 {
421     if (!pid_file)
422         return;
423 
424     /* ensure that only pidfile owner can remove it */
425     if (pidfile_owner_pid != getpid())
426         return;
427 
428     if (-1 == unlink(pid_file)) {
429         int initdone = gwlib_initialized();
430         /* we are called at exit so gwlib may be shutdown already, init again */
431         if (!initdone) {
432             gwlib_init();
433             log_set_syslog("kannel", 0);
434         }
435         error(errno, "Could not unlink pid-file `%s'", pid_file);
436         if (!initdone)
437             gwlib_shutdown();
438     }
439 }
440 
441 
change_user(const char * user)442 static int change_user(const char *user)
443 {
444     struct passwd *pass;
445 
446     if (!user)
447         return -1;
448 
449     pass = getpwnam(user);
450     if (!pass) {
451         error(0, "Could not find a user `%s' in system.", user);
452         return -1;
453     }
454 
455     if (-1 == setgid(pass->pw_gid)) {
456         error(errno, "Could not change group id from %ld to %ld.", (long) getgid(), (long) pass->pw_gid);
457         return -1;
458     }
459 
460 #ifdef HAVE_INITGROUPS
461     if (initgroups(user, pass->pw_gid) == -1) {
462         error(errno, "Could not set supplementary group ID's.");
463     }
464 #endif
465 
466     if (-1 == setuid(pass->pw_uid)) {
467         error(errno, "Could not change user id from %ld to %ld.", (long) getuid(), (long) pass->pw_uid);
468         return -1;
469     }
470 
471     return 0;
472 }
473 
474 /*
475  * new datatype functions
476  */
477 
478 
get_variable_value(Octet * source,int * len)479 MultibyteInt get_variable_value(Octet *source, int *len)
480 {
481     MultibyteInt retval = 0;
482 
483     for(*len=1;; (*len)++, source++) {
484 	retval = retval * 0x80 + (*source & 0x7F);
485 	if (*source < 0x80)  /* if the continue-bit (high bit) is not set */
486 	    break;
487     }
488     return retval;
489 }
490 
491 
write_variable_value(MultibyteInt value,Octet * dest)492 int write_variable_value(MultibyteInt value, Octet *dest)
493 {
494     int i, loc = 0;
495     Octet revbuffer[20];	/* we write it backwards */
496 
497     for (;;) {
498 	revbuffer[loc++] = (value & 0x7F) + 0x80;
499 	if (value >= 0x80)
500 	    value = value >> 7;
501 	else
502 	    break;
503     }
504     for(i=0; i < loc; i++)		/* reverse the buffer */
505 	dest[i] = revbuffer[loc-i-1];
506 
507     dest[loc-1] &= 0x7F;	/* remove trailer-bit from last */
508 
509     return loc;
510 }
511 
512 
reverse_octet(Octet source)513 Octet reverse_octet(Octet source)
514 {
515     Octet	dest;
516     dest = (source & 1) <<7;
517     dest += (source & 2) <<5;
518     dest += (source & 4) <<3;
519     dest += (source & 8) <<1;
520     dest += (source & 16) >>1;
521     dest += (source & 32) >>3;
522     dest += (source & 64) >>5;
523     dest += (source & 128) >>7;
524 
525     return dest;
526 }
527 
528 
init_fatal_signals()529 void init_fatal_signals()
530 {
531     /* install fatal signal handler */
532     struct sigaction act;
533     /* set segfault handler */
534     sigemptyset(&act.sa_mask);
535     act.sa_sigaction = fatal_handler;
536     act.sa_flags = SA_SIGINFO;
537     sigaction(SIGSEGV, &act, NULL);
538 }
539 
540 
report_versions(const char * boxname)541 void report_versions(const char *boxname)
542 {
543     Octstr *os;
544 
545     os = version_report_string(boxname);
546     debug("gwlib.gwlib", 0, "%s", octstr_get_cstr(os));
547     octstr_destroy(os);
548 }
549 
550 
version_report_string(const char * boxname)551 Octstr *version_report_string(const char *boxname)
552 {
553     struct utsname u;
554 
555     uname(&u);
556     return octstr_format(GW_NAME " %s version `%s'.\nBuild `%s', compiler `%s'.\n"
557                          "System %s, release %s, version %s, machine %s.\n"
558              "Hostname %s, IP %s.\n"
559              "Libxml version %s.\n"
560 #ifdef HAVE_LIBSSL
561              "Using "
562 #ifdef HAVE_WTLS_OPENSSL
563              "WTLS library "
564 #endif
565              "%s.\n"
566 #endif
567 #ifdef HAVE_MYSQL
568              "Compiled with MySQL %s, using MySQL %s.\n"
569 #endif
570 #ifdef HAVE_PGSQL
571              "Compiled with PostgreSQL %s.\n"
572 #endif
573 #ifdef HAVE_SDB
574              "Using LibSDB %s.\n"
575 #endif
576 #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3)
577              "Using SQLite %s.\n"
578 #endif
579 #ifdef HAVE_ORACLE
580 #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
581              "Using Oracle OCI %d.%d.\n"
582 #else
583              "Using Oracle OCI.\n"
584 #endif
585 #endif
586 #ifdef HAVE_REDIS
587              "Using hiredis API %d.%d.%d\n"
588 #endif
589              "Using %s malloc.\n",
590              boxname, GW_VERSION,
591 #ifdef __GNUC__
592              (__DATE__ " " __TIME__) ,
593              __VERSION__,
594 #else
595              "unknown" , "unknown",
596 #endif
597              u.sysname, u.release, u.version, u.machine,
598              octstr_get_cstr(get_official_name()),
599              octstr_get_cstr(get_official_ip()),
600              LIBXML_DOTTED_VERSION,
601 #ifdef HAVE_LIBSSL
602              OPENSSL_VERSION_TEXT,
603 #endif
604 #ifdef HAVE_MYSQL
605              MYSQL_SERVER_VERSION, mysql_get_client_info(),
606 #endif
607 #ifdef HAVE_PGSQL
608              PG_VERSION,
609 #endif
610 #ifdef HAVE_SDB
611              LIBSDB_VERSION,
612 #endif
613 #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3)
614              SQLITE_VERSION,
615 #endif
616 #ifdef HAVE_ORACLE
617 #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
618              OCI_MAJOR_VERSION, OCI_MINOR_VERSION,
619 #endif
620 #endif
621 #ifdef HAVE_REDIS
622 			 HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH,
623 #endif
624              octstr_get_cstr(gwmem_type()));
625 }
626 
627 
get_and_set_debugs(int argc,char ** argv,int (* find_own)(int index,int argc,char ** argv))628 int get_and_set_debugs(int argc, char **argv,
629 		       int (*find_own) (int index, int argc, char **argv))
630 {
631     int i, ret = -1;
632     int debug_lvl = -1;
633     int file_lvl = GW_DEBUG;
634     char *log_file = NULL;
635     char *debug_places = NULL;
636     char *panic_script = NULL, *user = NULL;
637     int parachute = 0, daemonize = 0;
638 
639     for (i=1; i < argc; i++) {
640         if (strcmp(argv[i],"-v")==0 || strcmp(argv[i],"--verbosity")==0) {
641             if (i+1 < argc) {
642                 debug_lvl = atoi(argv[i+1]);
643                 i++;
644             } else
645                 panic(0, "Missing argument for option %s\n", argv[i]);
646         } else if (strcmp(argv[i],"-F")==0 || strcmp(argv[i],"--logfile")==0) {
647             if (i+1 < argc && *(argv[i+1]) != '-') {
648                 log_file = argv[i+1];
649                 i++;
650             } else
651                 panic(0, "Missing argument for option %s\n", argv[i]);
652         } else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--fileverbosity")==0) {
653             if (i+1 < argc) {
654                 file_lvl = atoi(argv[i+1]);
655                 i++;
656             } else
657                 panic(0, "Missing argument for option %s\n", argv[i]);
658         } else if (strcmp(argv[i],"-D")==0 || strcmp(argv[i],"--debug")==0) {
659             if (i+1 < argc) {
660                 debug_places = argv[i+1];
661                 i++;
662             } else
663                 panic(0, "Missing argument for option %s\n", argv[i]);
664         } else if (strcmp(argv[i], "-X")==0 || strcmp(argv[i], "--panic-script")==0) {
665             if (i+1 < argc) {
666                 panic_script = argv[i+1];
667                 i++;
668             } else
669                 panic(0, "Missing argument for option %s\n", argv[i]);
670         } else if (strcmp(argv[i], "-P")==0 || strcmp(argv[i], "--parachute")==0) {
671             parachute = 1;
672         } else if (strcmp(argv[i], "-d")==0 || strcmp(argv[i], "--daemonize")==0) {
673             daemonize = 1;
674         } else if (strcmp(argv[i], "-p")==0 || strcmp(argv[i], "--pid-file")==0) {
675             if (i+1 < argc) {
676                 pid_file = argv[i+1];
677                 i++;
678             } else
679                 panic(0, "Missing argument for option %s\n", argv[i]);
680         } else if (strcmp(argv[i], "-u")==0 || strcmp(argv[i], "--user")==0) {
681             if (i+1 < argc) {
682                 user = argv[i+1];
683                 i++;
684             } else
685                 panic(0, "Missing argument for option %s\n", argv[i]);
686         } else if (strcmp(argv[i], "-g")==0 || strcmp(argv[i], "--generate")==0) {
687             cfg_dump_all();
688             exit(0);
689         } else if (strcmp(argv[i], "--version")==0) {
690             Octstr *version = version_report_string(basename(argv[0]));
691             printf("%s", octstr_get_cstr(version));
692             octstr_destroy(version);
693             exit(0);
694         } else if (strcmp(argv[i],"--")==0) {
695             i++;
696             break;
697         } else if (*argv[i] != '-') {
698             break;
699         } else {
700             if (find_own != NULL) {
701            	ret = find_own(i, argc, argv);
702         }
703         if (ret < 0) {
704             fprintf(stderr, "Unknown option %s, exiting.\n", argv[i]);
705             panic(0, "Option parsing failed");
706         } else
707             i += ret;	/* advance additional args */
708         }
709     }
710 
711     if (user && -1 == change_user(user))
712         panic(0, "Could not change to user `%s'.", user);
713 
714     /* deamonize */
715     if (daemonize && !become_daemon())
716        exit(0);
717 
718     if (pid_file) {
719         write_pid_file();
720         atexit(remove_pid_file);
721     }
722 
723     if (parachute) {
724         /*
725          * if we are running as daemon so open syslog
726          * in order not to deal with i.e. log rotate.
727          */
728         if (daemonize) {
729             char *ident = strrchr(argv[0], '/');
730             if (!ident)
731                 ident = argv[0];
732             else
733                 ident++;
734             log_set_syslog(ident, (debug_lvl > -1 ? debug_lvl : 0));
735         }
736         parachute_start(argv[0], panic_script);
737         /* now we are in child process so close syslog */
738         if (daemonize)
739             log_close_all();
740     }
741 
742     if (debug_lvl > -1)
743         log_set_output_level(debug_lvl);
744     if (debug_places != NULL)
745         log_set_debug_places(debug_places);
746     if (log_file != NULL)
747         log_open(log_file, file_lvl, GW_NON_EXCL);
748 
749     info(0, "Debug_lvl = %d, log_file = %s, log_lvl = %d",
750          debug_lvl, log_file ? log_file : "<none>", file_lvl);
751     if (debug_places != NULL)
752 	    info(0, "Debug places: `%s'", debug_places);
753 
754 
755     init_fatal_signals();
756 
757     return i;
758 }
759 
760 
pattern_matches_ip(Octstr * pattern,Octstr * ip)761 static int pattern_matches_ip(Octstr *pattern, Octstr *ip)
762 {
763     long i, j;
764     long pat_len, ip_len;
765     int pat_c, ip_c;
766 
767     pat_len = octstr_len(pattern);
768     ip_len = octstr_len(ip);
769 
770     i = 0;
771     j = 0;
772     while (i < pat_len && j < ip_len) {
773 	pat_c = octstr_get_char(pattern, i);
774 	ip_c = octstr_get_char(ip, j);
775 	if (pat_c == ip_c) {
776 	    /* The characters match, go to the next ones. */
777 	    ++i;
778 	    ++j;
779 	} else if (pat_c != '*') {
780 	    /* They differ, and the pattern isn't a wildcard one. */
781 	    return 0;
782 	} else {
783 	    /* We found a wildcard in the pattern. Skip in ip. */
784 	    ++i;
785 	    while (j < ip_len && ip_c != '.') {
786 		++j;
787 		ip_c = octstr_get_char(ip, j);
788 	    }
789 	}
790     }
791 
792     if (i >= pat_len && j >= ip_len)
793     	return 1;
794     return 0;
795 }
796 
797 
pattern_list_matches_ip(Octstr * pattern_list,Octstr * ip)798 static int pattern_list_matches_ip(Octstr *pattern_list, Octstr *ip)
799 {
800     List *patterns;
801     Octstr *pattern;
802     int matches;
803 
804     patterns = octstr_split(pattern_list, octstr_imm(";"));
805     matches = 0;
806 
807     while (!matches && (pattern = gwlist_extract_first(patterns)) != NULL) {
808 	matches = pattern_matches_ip(pattern, ip);
809 	octstr_destroy(pattern);
810     }
811 
812     gwlist_destroy(patterns, octstr_destroy_item);
813     return matches;
814 }
815 
816 
is_allowed_ip(Octstr * allow_ip,Octstr * deny_ip,Octstr * ip)817 int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip)
818 {
819     if (ip == NULL)
820 	return 0;
821 
822     if (octstr_len(deny_ip) == 0)
823 	return 1;
824 
825     if (allow_ip != NULL && pattern_list_matches_ip(allow_ip, ip))
826 	return 1;
827 
828     if (pattern_list_matches_ip(deny_ip, ip))
829     	return 0;
830 
831     return 1;
832 }
833 
834 
connect_denied(Octstr * allow_ip,Octstr * ip)835 int connect_denied(Octstr *allow_ip, Octstr *ip)
836 {
837     if (ip == NULL)
838 	return 1;
839 
840     /* If IP not set, allow from Localhost */
841     if (allow_ip == NULL) {
842 	if (pattern_list_matches_ip(octstr_imm("127.0.0.1"), ip))
843 	    return 0;
844     } else {
845 	if (pattern_list_matches_ip(allow_ip, ip))
846 	    return 0;
847     }
848     return 1;
849 }
850 
851 
does_prefix_match(Octstr * prefix,Octstr * number)852 int does_prefix_match(Octstr *prefix, Octstr *number)
853 {
854     /* XXX modify to use just octstr operations
855      */
856     char *b, *p, *n;
857 
858     gw_assert(prefix != NULL);
859     gw_assert(number != NULL);
860 
861     p = octstr_get_cstr(prefix);
862     n = octstr_get_cstr(number);
863 
864 
865     while (*p != '\0') {
866         b = n;
867         for (b = n; *b != '\0'; b++, p++) {
868             if (*p == ';' || *p == '\0') {
869                 return 1;
870             }
871             if (*p != *b) break;
872         }
873         if (*p == ';' || *p == '\0') {
874             return 1;
875         }
876         while (*p != '\0' && *p != ';')
877             p++;
878         while (*p == ';') p++;
879     }
880     return 0;
881 }
882 
883 
normalize_number(char * dial_prefixes,Octstr ** number)884 int normalize_number(char *dial_prefixes, Octstr **number)
885 {
886     char *t, *p, *official, *start;
887     int len, official_len;
888 
889     if (dial_prefixes == NULL || dial_prefixes[0] == '\0')
890         return 0;
891 
892     t = official = dial_prefixes;
893     official_len = 0;
894 
895     gw_assert(number != NULL);
896 
897     while(1) {
898 
899     	p = octstr_get_cstr(*number);
900         for(start = t, len = 0; ; t++, p++, len++)
901 	{
902             if (*t == ',' || *t == ';' || *t == '\0') {
903                 if (start != official) {
904                     Octstr *nstr;
905 		    long n;
906 
907 		    if ( official[0] == '-' ) official_len=0;
908 		    n = official_len;
909 		    if (strlen(official) < (size_t) n)
910 		    	n = strlen(official);
911                     nstr = octstr_create_from_data(official, n);
912                     octstr_insert_data(nstr, official_len,
913                                            octstr_get_cstr(*number) + len,
914                                            octstr_len(*number) - len);
915                     octstr_destroy(*number);
916                     *number = nstr;
917                 }
918                 return 1;
919             }
920             if (*p == '\0' || *t != *p)
921                 break;          /* not matching */
922         }
923         for(; *t != ',' && *t != ';' && *t != '\0'; t++, len++)
924             ;
925         if (*t == '\0') break;
926         if (start == official) official_len = len;
927         if (*t == ';') official = t+1;
928         t++;
929     }
930     return 0;
931 }
932 
933 
934 
935 
936 
decode_network_long(unsigned char * data)937 long decode_network_long(unsigned char *data) {
938         return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
939 }
940 
941 
encode_network_long(unsigned char * data,unsigned long value)942 void encode_network_long(unsigned char *data, unsigned long value) {
943         data[0] = (value >> 24) & 0xff;
944         data[1] = (value >> 16) & 0xff;
945         data[2] = (value >> 8) & 0xff;
946         data[3] = value & 0xff;
947 }
948 
949 /* Something that does the same as GNU cfmakeraw. We don't use cfmakeraw
950    so that we always know what it does, and also to reduce configure.in
951    complexity. */
952 
kannel_cfmakeraw(struct termios * tio)953 void kannel_cfmakeraw (struct termios *tio){
954     /* Block until a charactor is available, but it only needs to be one*/
955     tio->c_cc[VMIN]    = 1;
956     tio->c_cc[VTIME]   = 0;
957 
958     /* GNU cfmakeraw sets these flags so we had better too...*/
959 
960     /* Control modes */
961     /* Mask out character size (CSIZE), then set it to 8 bits (CS8).
962      * Enable parity bit generation in both directions (PARENB).
963      */
964     tio->c_cflag      &= ~(CSIZE|PARENB);
965     tio->c_cflag      |= CS8;
966 
967     /* Input Flags,*/
968     /* Turn off all input flags that interfere with the byte stream:
969      * BRKINT - generate SIGINT when receiving BREAK, ICRNL - translate
970      * NL to CR, IGNCR - ignore CR, IGNBRK - ignore BREAK,
971      * INLCR - translate NL to CR, IXON - use XON/XOFF flow control,
972      * ISTRIP - strip off eighth bit.
973      */
974     tio->c_iflag &= ~(BRKINT|ICRNL|IGNCR|IGNBRK|INLCR|IXON|ISTRIP);
975 
976     /* Other flags,*/
977     /* Turn off all local flags that interpret the byte stream:
978      * ECHO - echo input chars, ECHONL - always echo NL even if ECHO is off,
979      * ICANON - enable canonical mode (basically line-oriented mode),
980      * IEXTEN - enable implementation-defined input processing,
981      * ISIG - generate signals when certain characters are received. */
982     tio->c_lflag      &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
983 
984     /* Output flags,*/
985     /* Disable implementation defined processing on the output stream*/
986     tio->c_oflag      &= ~OPOST;
987 }
988 
989 
gw_isdigit(int c)990 int gw_isdigit(int c)
991 {
992     return isdigit(c);
993 }
994 
995 
gw_isxdigit(int c)996 int gw_isxdigit(int c)
997 {
998     return isxdigit(c);
999 }
1000 
1001 
1002 /* Rounds up the result of a division */
roundup_div(int a,int b)1003 int roundup_div(int a, int b)
1004 {
1005     int t;
1006 
1007     t = a / b;
1008     if (t * b != a)
1009         t += 1;
1010 
1011     return t;
1012 }
1013 
1014 
gw_generate_id(void)1015 unsigned long long gw_generate_id(void)
1016 {
1017     /* create a 64 bit unique Id by putting a 32 bit epoch time value
1018      * and a 32 bit random value together */
1019     unsigned long random, timer;
1020 
1021     random = gw_rand();
1022     timer = (unsigned long)time(NULL);
1023 
1024     return ((unsigned long long)timer << 32) + random;
1025 }
1026 
1027