Kannel: Open Source WAP and SMS gateway  svn-r5335
utils.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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 
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 
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 
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;
229  }
230  else
231  panic(0, "Child process signal handlers not initialized before.");
232 }
233 
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  */
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 
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 
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 */
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  exit(WIFEXITED(status) ? WEXITSTATUS(status) : 0);
374  }
375 
376  /* check whether it's panic while start */
377  if (respawn_count == 0 && difftime(time(NULL), last_start) < 2) {
378  info(0, "Child process crashed while starting. Exiting...");
379  info(0, "Going into gwlib_shutdown...");
380  gwlib_shutdown();
381  exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
382  }
383 
384  respawn_count++;
385  if (panic_script && myname && difftime(time(NULL), last_panic) > 300) {
386  time(&last_panic);
387  debug("kannel", 0, "Executing panic script: %s %s %ld", panic_script, myname, respawn_count);
388  execute_panic_script(panic_script, "%s %ld", myname, respawn_count);
389  }
390  /* sleep a while to get e.g. sockets released */
391  gwthread_sleep(5.0);
392  }
393  }
394 }
395 
396 
397 static void write_pid_file(void)
398 {
399  int fd;
400  FILE *file;
401 
402  if (!pid_file)
403  return;
404 
405  fd = open(pid_file, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT|O_EXCL, 0644);
406  if (fd == -1)
407  panic(errno, "Could not open pid-file `%s'", pid_file);
408 
409  file = fdopen(fd, "w");
410  if (!file)
411  panic(errno, "Could not open file-stream `%s'", pid_file);
412 
413  fprintf(file, "%ld\n", (long) (pidfile_owner_pid = getpid()));
414  fclose(file);
415 }
416 
417 static void remove_pid_file(void)
418 {
419  if (!pid_file)
420  return;
421 
422  /* ensure that only pidfile owner can remove it */
423  if (pidfile_owner_pid != getpid())
424  return;
425 
426  if (-1 == unlink(pid_file)) {
427  int initdone = gwlib_initialized();
428  /* we are called at exit so gwlib may be shutdown already, init again */
429  if (!initdone) {
430  gwlib_init();
431  log_set_syslog("kannel", 0);
432  }
433  error(errno, "Could not unlink pid-file `%s'", pid_file);
434  if (!initdone)
435  gwlib_shutdown();
436  }
437 }
438 
439 
440 static int change_user(const char *user)
441 {
442  struct passwd *pass;
443 
444  if (!user)
445  return -1;
446 
447  pass = getpwnam(user);
448  if (!pass) {
449  error(0, "Could not find a user `%s' in system.", user);
450  return -1;
451  }
452 
453  if (-1 == setgid(pass->pw_gid)) {
454  error(errno, "Could not change group id from %ld to %ld.", (long) getgid(), (long) pass->pw_gid);
455  return -1;
456  }
457 
458 #ifdef HAVE_INITGROUPS
459  if (initgroups(user, pass->pw_gid) == -1) {
460  error(errno, "Could not set supplementary group ID's.");
461  }
462 #endif
463 
464  if (-1 == setuid(pass->pw_uid)) {
465  error(errno, "Could not change user id from %ld to %ld.", (long) getuid(), (long) pass->pw_uid);
466  return -1;
467  }
468 
469  return 0;
470 }
471 
472 /*
473  * new datatype functions
474  */
475 
476 
478 {
479  MultibyteInt retval = 0;
480 
481  for(*len=1;; (*len)++, source++) {
482  retval = retval * 0x80 + (*source & 0x7F);
483  if (*source < 0x80) /* if the continue-bit (high bit) is not set */
484  break;
485  }
486  return retval;
487 }
488 
489 
491 {
492  int i, loc = 0;
493  Octet revbuffer[20]; /* we write it backwards */
494 
495  for (;;) {
496  revbuffer[loc++] = (value & 0x7F) + 0x80;
497  if (value >= 0x80)
498  value = value >> 7;
499  else
500  break;
501  }
502  for(i=0; i < loc; i++) /* reverse the buffer */
503  dest[i] = revbuffer[loc-i-1];
504 
505  dest[loc-1] &= 0x7F; /* remove trailer-bit from last */
506 
507  return loc;
508 }
509 
510 
512 {
513  Octet dest;
514  dest = (source & 1) <<7;
515  dest += (source & 2) <<5;
516  dest += (source & 4) <<3;
517  dest += (source & 8) <<1;
518  dest += (source & 16) >>1;
519  dest += (source & 32) >>3;
520  dest += (source & 64) >>5;
521  dest += (source & 128) >>7;
522 
523  return dest;
524 }
525 
526 
528 {
529  /* install fatal signal handler */
530  struct sigaction act;
531  /* set segfault handler */
532  sigemptyset(&act.sa_mask);
533  act.sa_sigaction = fatal_handler;
534  act.sa_flags = SA_SIGINFO;
535  sigaction(SIGSEGV, &act, NULL);
536 }
537 
538 
539 void report_versions(const char *boxname)
540 {
541  Octstr *os;
542 
543  os = version_report_string(boxname);
544  debug("gwlib.gwlib", 0, "%s", octstr_get_cstr(os));
545  octstr_destroy(os);
546 }
547 
548 
549 Octstr *version_report_string(const char *boxname)
550 {
551  struct utsname u;
552 
553  uname(&u);
554  return octstr_format(GW_NAME " %s version `%s'.\nBuild `%s', compiler `%s'.\n"
555  "System %s, release %s, version %s, machine %s.\n"
556  "Hostname %s, IP %s.\n"
557  "Libxml version %s.\n"
558 #ifdef HAVE_LIBSSL
559  "Using "
560 #ifdef HAVE_WTLS_OPENSSL
561  "WTLS library "
562 #endif
563  "%s.\n"
564 #endif
565 #ifdef HAVE_MYSQL
566  "Compiled with MySQL %s, using MySQL %s.\n"
567 #endif
568 #ifdef HAVE_PGSQL
569  "Compiled with PostgreSQL %s.\n"
570 #endif
571 #ifdef HAVE_SDB
572  "Using LibSDB %s.\n"
573 #endif
574 #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3)
575  "Using SQLite %s.\n"
576 #endif
577 #ifdef HAVE_ORACLE
578 #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
579  "Using Oracle OCI %d.%d.\n"
580 #else
581  "Using Oracle OCI.\n"
582 #endif
583 #endif
584 #ifdef HAVE_REDIS
585  "Using hiredis API %d.%d.%d\n"
586 #endif
587  "Using %s malloc.\n",
588  boxname, GW_VERSION,
589 #ifdef __GNUC__
590  (__DATE__ " " __TIME__) ,
591  __VERSION__,
592 #else
593  "unknown" , "unknown",
594 #endif
595  u.sysname, u.release, u.version, u.machine,
598  LIBXML_DOTTED_VERSION,
599 #ifdef HAVE_LIBSSL
600  OPENSSL_VERSION_TEXT,
601 #endif
602 #ifdef HAVE_MYSQL
603  MYSQL_SERVER_VERSION, mysql_get_client_info(),
604 #endif
605 #ifdef HAVE_PGSQL
606  PG_VERSION,
607 #endif
608 #ifdef HAVE_SDB
609  LIBSDB_VERSION,
610 #endif
611 #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3)
612  SQLITE_VERSION,
613 #endif
614 #ifdef HAVE_ORACLE
615 #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
616  OCI_MAJOR_VERSION, OCI_MINOR_VERSION,
617 #endif
618 #endif
619 #ifdef HAVE_REDIS
620  HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH,
621 #endif
622  octstr_get_cstr(gwmem_type()));
623 }
624 
625 
626 int get_and_set_debugs(int argc, char **argv,
627  int (*find_own) (int index, int argc, char **argv))
628 {
629  int i, ret = -1;
630  int debug_lvl = -1;
631  int file_lvl = GW_DEBUG;
632  char *log_file = NULL;
633  char *debug_places = NULL;
634  char *panic_script = NULL, *user = NULL;
635  int parachute = 0, daemonize = 0;
636 
637  for (i=1; i < argc; i++) {
638  if (strcmp(argv[i],"-v")==0 || strcmp(argv[i],"--verbosity")==0) {
639  if (i+1 < argc) {
640  debug_lvl = atoi(argv[i+1]);
641  i++;
642  } else
643  panic(0, "Missing argument for option %s\n", argv[i]);
644  } else if (strcmp(argv[i],"-F")==0 || strcmp(argv[i],"--logfile")==0) {
645  if (i+1 < argc && *(argv[i+1]) != '-') {
646  log_file = argv[i+1];
647  i++;
648  } else
649  panic(0, "Missing argument for option %s\n", argv[i]);
650  } else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--fileverbosity")==0) {
651  if (i+1 < argc) {
652  file_lvl = atoi(argv[i+1]);
653  i++;
654  } else
655  panic(0, "Missing argument for option %s\n", argv[i]);
656  } else if (strcmp(argv[i],"-D")==0 || strcmp(argv[i],"--debug")==0) {
657  if (i+1 < argc) {
658  debug_places = argv[i+1];
659  i++;
660  } else
661  panic(0, "Missing argument for option %s\n", argv[i]);
662  } else if (strcmp(argv[i], "-X")==0 || strcmp(argv[i], "--panic-script")==0) {
663  if (i+1 < argc) {
664  panic_script = argv[i+1];
665  i++;
666  } else
667  panic(0, "Missing argument for option %s\n", argv[i]);
668  } else if (strcmp(argv[i], "-P")==0 || strcmp(argv[i], "--parachute")==0) {
669  parachute = 1;
670  } else if (strcmp(argv[i], "-d")==0 || strcmp(argv[i], "--daemonize")==0) {
671  daemonize = 1;
672  } else if (strcmp(argv[i], "-p")==0 || strcmp(argv[i], "--pid-file")==0) {
673  if (i+1 < argc) {
674  pid_file = argv[i+1];
675  i++;
676  } else
677  panic(0, "Missing argument for option %s\n", argv[i]);
678  } else if (strcmp(argv[i], "-u")==0 || strcmp(argv[i], "--user")==0) {
679  if (i+1 < argc) {
680  user = argv[i+1];
681  i++;
682  } else
683  panic(0, "Missing argument for option %s\n", argv[i]);
684  } else if (strcmp(argv[i], "-g")==0 || strcmp(argv[i], "--generate")==0) {
685  cfg_dump_all();
686  exit(0);
687  } else if (strcmp(argv[i], "--version")==0) {
688  Octstr *version = version_report_string(basename(argv[0]));
689  printf("%s", octstr_get_cstr(version));
690  octstr_destroy(version);
691  exit(0);
692  } else if (strcmp(argv[i],"--")==0) {
693  i++;
694  break;
695  } else if (*argv[i] != '-') {
696  break;
697  } else {
698  if (find_own != NULL) {
699  ret = find_own(i, argc, argv);
700  }
701  if (ret < 0) {
702  fprintf(stderr, "Unknown option %s, exiting.\n", argv[i]);
703  panic(0, "Option parsing failed");
704  } else
705  i += ret; /* advance additional args */
706  }
707  }
708 
709  if (user && -1 == change_user(user))
710  panic(0, "Could not change to user `%s'.", user);
711 
712  /* deamonize */
713  if (daemonize && !become_daemon())
714  exit(0);
715 
716  if (pid_file) {
717  write_pid_file();
718  atexit(remove_pid_file);
719  }
720 
721  if (parachute) {
722  /*
723  * if we are running as daemon so open syslog
724  * in order not to deal with i.e. log rotate.
725  */
726  if (daemonize) {
727  char *ident = strrchr(argv[0], '/');
728  if (!ident)
729  ident = argv[0];
730  else
731  ident++;
732  log_set_syslog(ident, (debug_lvl > -1 ? debug_lvl : 0));
733  }
734  parachute_start(argv[0], panic_script);
735  /* now we are in child process so close syslog */
736  if (daemonize)
737  log_close_all();
738  }
739 
740  if (debug_lvl > -1)
741  log_set_output_level(debug_lvl);
742  if (debug_places != NULL)
743  log_set_debug_places(debug_places);
744  if (log_file != NULL)
745  log_open(log_file, file_lvl, GW_NON_EXCL);
746 
747  info(0, "Debug_lvl = %d, log_file = %s, log_lvl = %d",
748  debug_lvl, log_file ? log_file : "<none>", file_lvl);
749  if (debug_places != NULL)
750  info(0, "Debug places: `%s'", debug_places);
751 
752 
754 
755  return i;
756 }
757 
758 
759 static int pattern_matches_ip(Octstr *pattern, Octstr *ip)
760 {
761  long i, j;
762  long pat_len, ip_len;
763  int pat_c, ip_c;
764 
765  pat_len = octstr_len(pattern);
766  ip_len = octstr_len(ip);
767 
768  i = 0;
769  j = 0;
770  while (i < pat_len && j < ip_len) {
771  pat_c = octstr_get_char(pattern, i);
772  ip_c = octstr_get_char(ip, j);
773  if (pat_c == ip_c) {
774  /* The characters match, go to the next ones. */
775  ++i;
776  ++j;
777  } else if (pat_c != '*') {
778  /* They differ, and the pattern isn't a wildcard one. */
779  return 0;
780  } else {
781  /* We found a wildcard in the pattern. Skip in ip. */
782  ++i;
783  while (j < ip_len && ip_c != '.') {
784  ++j;
785  ip_c = octstr_get_char(ip, j);
786  }
787  }
788  }
789 
790  if (i >= pat_len && j >= ip_len)
791  return 1;
792  return 0;
793 }
794 
795 
796 static int pattern_list_matches_ip(Octstr *pattern_list, Octstr *ip)
797 {
798  List *patterns;
799  Octstr *pattern;
800  int matches;
801 
802  patterns = octstr_split(pattern_list, octstr_imm(";"));
803  matches = 0;
804 
805  while (!matches && (pattern = gwlist_extract_first(patterns)) != NULL) {
806  matches = pattern_matches_ip(pattern, ip);
807  octstr_destroy(pattern);
808  }
809 
811  return matches;
812 }
813 
814 
816 {
817  if (ip == NULL)
818  return 0;
819 
820  if (octstr_len(deny_ip) == 0)
821  return 1;
822 
823  if (allow_ip != NULL && pattern_list_matches_ip(allow_ip, ip))
824  return 1;
825 
827  return 0;
828 
829  return 1;
830 }
831 
832 
834 {
835  if (ip == NULL)
836  return 1;
837 
838  /* If IP not set, allow from Localhost */
839  if (allow_ip == NULL) {
840  if (pattern_list_matches_ip(octstr_imm("127.0.0.1"), ip))
841  return 0;
842  } else {
844  return 0;
845  }
846  return 1;
847 }
848 
849 
851 {
852  /* XXX modify to use just octstr operations
853  */
854  char *b, *p, *n;
855 
856  gw_assert(prefix != NULL);
857  gw_assert(number != NULL);
858 
859  p = octstr_get_cstr(prefix);
860  n = octstr_get_cstr(number);
861 
862 
863  while (*p != '\0') {
864  b = n;
865  for (b = n; *b != '\0'; b++, p++) {
866  if (*p == ';' || *p == '\0') {
867  return 1;
868  }
869  if (*p != *b) break;
870  }
871  if (*p == ';' || *p == '\0') {
872  return 1;
873  }
874  while (*p != '\0' && *p != ';')
875  p++;
876  while (*p == ';') p++;
877  }
878  return 0;
879 }
880 
881 
882 int normalize_number(char *dial_prefixes, Octstr **number)
883 {
884  char *t, *p, *official, *start;
885  int len, official_len;
886 
887  if (dial_prefixes == NULL || dial_prefixes[0] == '\0')
888  return 0;
889 
890  t = official = dial_prefixes;
891  official_len = 0;
892 
893  gw_assert(number != NULL);
894 
895  while(1) {
896 
897  p = octstr_get_cstr(*number);
898  for(start = t, len = 0; ; t++, p++, len++)
899  {
900  if (*t == ',' || *t == ';' || *t == '\0') {
901  if (start != official) {
902  Octstr *nstr;
903  long n;
904 
905  if ( official[0] == '-' ) official_len=0;
906  n = official_len;
907  if (strlen(official) < (size_t) n)
908  n = strlen(official);
909  nstr = octstr_create_from_data(official, n);
910  octstr_insert_data(nstr, official_len,
911  octstr_get_cstr(*number) + len,
912  octstr_len(*number) - len);
914  *number = nstr;
915  }
916  return 1;
917  }
918  if (*p == '\0' || *t != *p)
919  break; /* not matching */
920  }
921  for(; *t != ',' && *t != ';' && *t != '\0'; t++, len++)
922  ;
923  if (*t == '\0') break;
924  if (start == official) official_len = len;
925  if (*t == ';') official = t+1;
926  t++;
927  }
928  return 0;
929 }
930 
931 
932 
933 
934 
935 long decode_network_long(unsigned char *data) {
936  return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
937 }
938 
939 
940 void encode_network_long(unsigned char *data, unsigned long value) {
941  data[0] = (value >> 24) & 0xff;
942  data[1] = (value >> 16) & 0xff;
943  data[2] = (value >> 8) & 0xff;
944  data[3] = value & 0xff;
945 }
946 
947 /* Something that does the same as GNU cfmakeraw. We don't use cfmakeraw
948  so that we always know what it does, and also to reduce configure.in
949  complexity. */
950 
951 void kannel_cfmakeraw (struct termios *tio){
952  /* Block until a charactor is available, but it only needs to be one*/
953  tio->c_cc[VMIN] = 1;
954  tio->c_cc[VTIME] = 0;
955 
956  /* GNU cfmakeraw sets these flags so we had better too...*/
957 
958  /* Control modes */
959  /* Mask out character size (CSIZE), then set it to 8 bits (CS8).
960  * Enable parity bit generation in both directions (PARENB).
961  */
962  tio->c_cflag &= ~(CSIZE|PARENB);
963  tio->c_cflag |= CS8;
964 
965  /* Input Flags,*/
966  /* Turn off all input flags that interfere with the byte stream:
967  * BRKINT - generate SIGINT when receiving BREAK, ICRNL - translate
968  * NL to CR, IGNCR - ignore CR, IGNBRK - ignore BREAK,
969  * INLCR - translate NL to CR, IXON - use XON/XOFF flow control,
970  * ISTRIP - strip off eighth bit.
971  */
972  tio->c_iflag &= ~(BRKINT|ICRNL|IGNCR|IGNBRK|INLCR|IXON|ISTRIP);
973 
974  /* Other flags,*/
975  /* Turn off all local flags that interpret the byte stream:
976  * ECHO - echo input chars, ECHONL - always echo NL even if ECHO is off,
977  * ICANON - enable canonical mode (basically line-oriented mode),
978  * IEXTEN - enable implementation-defined input processing,
979  * ISIG - generate signals when certain characters are received. */
980  tio->c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
981 
982  /* Output flags,*/
983  /* Disable implementation defined processing on the output stream*/
984  tio->c_oflag &= ~OPOST;
985 }
986 
987 
988 int gw_isdigit(int c)
989 {
990  return isdigit(c);
991 }
992 
993 
994 int gw_isxdigit(int c)
995 {
996  return isxdigit(c);
997 }
998 
999 
1000 /* Rounds up the result of a division */
1001 int roundup_div(int a, int b)
1002 {
1003  int t;
1004 
1005  t = a / b;
1006  if (t * b != a)
1007  t += 1;
1008 
1009  return t;
1010 }
1011 
1012 
1013 unsigned long long gw_generate_id(void)
1014 {
1015  /* create a 64 bit unique Id by putting a 32 bit epoch time value
1016  * and a 32 bit random value together */
1017  unsigned long random, timer;
1018 
1019  random = gw_rand();
1020  timer = (unsigned long)time(NULL);
1021 
1022  return ((unsigned long long)timer << 32) + random;
1023 }
1024 
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
static PRINTFLIKE(2, 3)
Definition: utils.c:290
int number
Definition: smsc_cimd2.c:213
void log_set_debug_places(const char *places)
Definition: log.c:746
int size
Definition: wsasm.c:84
void gw_backtrace(void **stack_frames, size_t size, int lock)
Definition: log.c:599
#define PANIC_SCRIPT_MAX_LEN
Definition: utils.c:288
gw_assert(wtls_machine->packet_to_send !=NULL)
static void parachute_sig_handler(int signum)
Definition: utils.c:175
static char * pid_file
Definition: utils.c:142
void encode_network_long(unsigned char *data, unsigned long value)
Definition: utils.c:940
static void write_pid_file(void)
Definition: utils.c:397
static int become_daemon(void)
Definition: utils.c:263
static struct sigaction child_actions[32]
Definition: utils.c:138
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1461
static int pattern_list_matches_ip(Octstr *pattern_list, Octstr *ip)
Definition: utils.c:796
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
unsigned long MultibyteInt
Definition: utils.h:76
int connect_denied(Octstr *allow_ip, Octstr *ip)
Definition: utils.c:833
FILE * file
Definition: log.c:169
int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip)
Definition: utils.c:815
unsigned long long gw_generate_id(void)
Definition: utils.c:1013
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
void log_close_all(void)
Definition: log.c:341
int does_prefix_match(Octstr *prefix, Octstr *number)
Definition: utils.c:850
void * gwlist_extract_first(List *list)
Definition: list.c:305
void log_set_output_level(enum output_level level)
Definition: log.c:253
static int change_user(const char *user)
Definition: utils.c:440
static pid_t pidfile_owner_pid
Definition: utils.c:136
Definition: log.h:69
static Octstr * deny_ip
Definition: bb_udp.c:112
static void parachute_start(const char *myname, const char *panic_script)
Definition: utils.c:315
int gw_isdigit(int c)
Definition: utils.c:988
int roundup_div(int a, int b)
Definition: utils.c:1001
static pid_t child_pid
Definition: utils.c:134
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
char filename[FILENAME_MAX+1]
Definition: log.c:171
void octstr_destroy_item(void *os)
Definition: octstr.c:336
Octstr * get_official_name(void)
Definition: socket.c:627
static int child_actions_init
Definition: utils.c:140
void gwthread_sleep(double seconds)
void log_set_syslog(const char *ident, int syslog_level)
Definition: log.c:284
void cfg_dump_all(void)
Definition: cfg.c:869
static Octstr * allow_ip
Definition: bb_udp.c:111
static void parachute_init_signals(int child)
Definition: utils.c:195
static void remove_pid_file(void)
Definition: utils.c:417
int log_open(char *filename, int level, enum excl_state excl)
Definition: log.c:375
void report_versions(const char *boxname)
Definition: utils.c:539
Octet reverse_octet(Octet source)
Definition: utils.c:511
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
long decode_network_long(unsigned char *data)
Definition: utils.c:935
Octstr * get_official_ip(void)
Definition: socket.c:634
Definition: octstr.c:118
void init_fatal_signals()
Definition: utils.c:527
static int pattern_matches_ip(Octstr *pattern, Octstr *ip)
Definition: utils.c:759
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
#define panic
Definition: log.h:87
void gwlib_shutdown(void)
Definition: gwlib.c:94
MultibyteInt get_variable_value(Octet *source, int *len)
Definition: utils.c:477
int normalize_number(char *dial_prefixes, Octstr **number)
Definition: utils.c:882
static int is_executable(const char *filename)
Definition: utils.c:234
void kannel_cfmakeraw(struct termios *tio)
Definition: utils.c:951
Octstr * version_report_string(const char *boxname)
Definition: utils.c:549
void gwlib_init(void)
Definition: gwlib.c:78
int write_variable_value(MultibyteInt value, Octet *dest)
Definition: utils.c:490
int gw_isxdigit(int c)
Definition: utils.c:994
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
int get_and_set_debugs(int argc, char **argv, int(*find_own)(int index, int argc, char **argv))
Definition: utils.c:626
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
static volatile sig_atomic_t parachute_shutdown
Definition: utils.c:143
int gw_rand(void)
Definition: protected.c:174
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1640
Definition: list.c:102
static int start
unsigned char Octet
Definition: utils.h:75
static void fatal_handler(int sig, siginfo_t *info, void *secret)
Definition: utils.c:146
int gwlib_initialized(void)
Definition: gwlib.c:111
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.