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