00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #include "gw-config.h"
00063
00064 #include <ctype.h>
00065 #include <errno.h>
00066 #include <stdarg.h>
00067 #include <stdio.h>
00068 #include <stdlib.h>
00069 #include <string.h>
00070 #include <time.h>
00071 #include <unistd.h>
00072 #include <termios.h>
00073 #include <signal.h>
00074 #include <sys/types.h>
00075 #include <sys/wait.h>
00076 #include <sys/stat.h>
00077 #include <fcntl.h>
00078 #include <pwd.h>
00079 #include <grp.h>
00080
00081 #include "gwlib.h"
00082
00083
00084 static pid_t child_pid = -1;
00085
00086 static struct sigaction child_actions[32];
00087
00088 static int child_actions_init = 0;
00089
00090 static char *pid_file = NULL;
00091 static volatile sig_atomic_t parachute_shutdown = 0;
00092
00093
00094 static void parachute_sig_handler(int signum)
00095 {
00096 info(0, "Signal %d received, forward to child pid (%ld)", signum, (long) child_pid);
00097
00098
00099 if (child_pid != -1 && getpid() != child_pid)
00100 kill(child_pid, signum);
00101
00102
00103 switch(signum) {
00104 case SIGTERM:
00105 case SIGINT:
00106 case SIGABRT:
00107 if (child_pid == -1)
00108 exit(0);
00109 else
00110 parachute_shutdown = 1;
00111 }
00112 }
00113
00114 static void parachute_init_signals(int child)
00115 {
00116 struct sigaction sa;
00117
00118 if (child_actions_init && child) {
00119 sigaction(SIGTERM, &child_actions[SIGTERM], NULL);
00120 sigaction(SIGQUIT, &child_actions[SIGQUIT], NULL);
00121 sigaction(SIGINT, &child_actions[SIGINT], NULL);
00122 sigaction(SIGABRT, &child_actions[SIGABRT], NULL);
00123 sigaction(SIGHUP, &child_actions[SIGHUP], NULL);
00124 sigaction(SIGALRM, &child_actions[SIGALRM], NULL);
00125 sigaction(SIGUSR1, &child_actions[SIGUSR1], NULL);
00126 sigaction(SIGUSR2, &child_actions[SIGUSR2], NULL);
00127 sigaction(SIGPIPE, &child_actions[SIGPIPE], NULL);
00128 }
00129 else if (!child && !child_actions_init) {
00130 sa.sa_flags = 0;
00131 sigemptyset(&sa.sa_mask);
00132 sa.sa_handler = parachute_sig_handler;
00133 sigaction(SIGTERM, &sa, &child_actions[SIGTERM]);
00134 sigaction(SIGQUIT, &sa, &child_actions[SIGQUIT]);
00135 sigaction(SIGINT, &sa, &child_actions[SIGINT]);
00136 sigaction(SIGABRT, &sa, &child_actions[SIGABRT]);
00137 sigaction(SIGHUP, &sa, &child_actions[SIGHUP]);
00138 sigaction(SIGALRM, &sa, &child_actions[SIGALRM]);
00139 sigaction(SIGUSR1, &sa, &child_actions[SIGUSR1]);
00140 sigaction(SIGUSR2, &sa, &child_actions[SIGUSR2]);
00141 sa.sa_handler = SIG_IGN;
00142 sigaction(SIGPIPE, &sa, &child_actions[SIGPIPE]);
00143 sigaction(SIGTTOU, &sa, NULL);
00144 sigaction(SIGTTIN, &sa, NULL);
00145 sigaction(SIGTSTP, &sa, NULL);
00146 child_actions_init = 1;
00147 }
00148 else
00149 panic(0, "Child process signal handlers not initialized before.");
00150 }
00151
00152 static int is_executable(const char *filename)
00153 {
00154 struct stat buf;
00155
00156 if (stat(filename, &buf)) {
00157 error(errno, "Error while stat of file `%s'", filename);
00158 return 0;
00159 }
00160 if (!S_ISREG(buf.st_mode) && !S_ISLNK(buf.st_mode)) {
00161 error(0, "File `%s' is not a regular file.", filename);
00162 return 0;
00163 }
00164
00165 if (S_IXOTH & buf.st_mode) return 1;
00166
00167 if ((S_IXGRP & buf.st_mode) && buf.st_gid == getgid())
00168 return 1;
00169
00170 if ((S_IXUSR & buf.st_mode) && buf.st_uid == getuid())
00171 return 1;
00172
00173 return 0;
00174 }
00175
00176
00177
00178
00179
00180 static int become_daemon(void)
00181 {
00182 int fd;
00183 if (getppid() != 1) {
00184 signal(SIGTTOU, SIG_IGN);
00185 signal(SIGTTIN, SIG_IGN);
00186 signal(SIGTSTP, SIG_IGN);
00187 if (fork())
00188 return 0;
00189 setsid();
00190 }
00191
00192 close(STDIN_FILENO);
00193 close(STDOUT_FILENO);
00194 close(STDERR_FILENO);
00195 fd = open("/dev/null", O_RDWR);
00196 if (fd == -1)
00197 panic(errno, "Could not open `/dev/null'");
00198 dup(fd);
00199 dup(fd);
00200
00201 chdir("/");
00202 return 1;
00203 }
00204
00205 #define PANIC_SCRIPT_MAX_LEN 4096
00206
00207 static PRINTFLIKE(2,3) void execute_panic_script(const char *panic_script, const char *format, ...)
00208 {
00209 char *args[3];
00210 char buf[PANIC_SCRIPT_MAX_LEN + 1];
00211 va_list ap;
00212
00213 va_start(ap, format);
00214 vsnprintf(buf, PANIC_SCRIPT_MAX_LEN, format, ap);
00215 va_end(ap);
00216
00217 if (fork())
00218 return;
00219
00220 close(STDIN_FILENO);
00221 close(STDOUT_FILENO);
00222 close(STDERR_FILENO);
00223
00224 args[0] = (char*) panic_script;
00225 args[1] = buf;
00226 args[2] = NULL;
00227
00228 execv(args[0], args);
00229 }
00230
00231
00232 static void parachute_start(const char *myname, const char *panic_script) {
00233 time_t last_start = 0, last_panic = 0;
00234 long respawn_count = 0;
00235 int status;
00236
00237
00238 if (panic_script && !is_executable(panic_script))
00239 panic(0, "Panic script `%s' is not executable for us.", panic_script);
00240
00241
00242 parachute_init_signals(0);
00243
00244 for (;;) {
00245 if (respawn_count > 0 && difftime(time(NULL), last_start) < 10) {
00246 error(0, "Child process died too fast, disabling for 30 sec.");
00247 gwthread_sleep(30.0);
00248 }
00249 if (!(child_pid = fork())) {
00250 parachute_init_signals(1);
00251 return;
00252 }
00253 else if (child_pid < 0) {
00254 error(errno, "Could not start child process! Will retry in 5 sec.");
00255 gwthread_sleep(5.0);
00256 continue;
00257 }
00258 else {
00259 time(&last_start);
00260 info(0, "Child process with PID (%ld) started.", (long) child_pid);
00261 do {
00262 if (waitpid(child_pid, &status, 0) == child_pid) {
00263
00264 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
00265 info(0, "Child process exited gracefully, exit...");
00266 gwlib_shutdown();
00267 exit(0);
00268 }
00269 else if (WIFEXITED(status)) {
00270 error(0, "Caught child PID (%ld) which died with return code %d",
00271 (long) child_pid, WEXITSTATUS(status));
00272 child_pid = -1;
00273 }
00274 else if (WIFSIGNALED(status)) {
00275 error(0, "Caught child PID (%ld) which died due to signal %d",
00276 (long) child_pid, WTERMSIG(status));
00277 child_pid = -1;
00278 }
00279 }
00280 else if (errno != EINTR) {
00281 error(errno, "Error while waiting of child process.");
00282 }
00283 } while(child_pid > 0);
00284
00285 if (parachute_shutdown) {
00286
00287 info(0, "Child process crashed while shutdown. Exiting due to signal...");
00288 info(0, "Going into gwlib_shutdown...");
00289 gwlib_shutdown();
00290 info(0, "gwlib_shutdown done... Bye bye...");
00291 exit(WIFEXITED(status) ? WEXITSTATUS(status) : 0);
00292 }
00293
00294
00295 if (respawn_count == 0 && difftime(time(NULL), last_start) < 2) {
00296 info(0, "Child process crashed while starting. Exiting...");
00297 info(0, "Going into gwlib_shutdown...");
00298 gwlib_shutdown();
00299 info(0, "gwlib_shutdown done... Bye bye...");
00300 exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
00301 }
00302
00303 respawn_count++;
00304 if (panic_script && myname && difftime(time(NULL), last_panic) > 300) {
00305 time(&last_panic);
00306 debug("kannel", 0, "Executing panic script: %s %s %ld", panic_script, myname, respawn_count);
00307 execute_panic_script(panic_script, "%s %ld", myname, respawn_count);
00308 }
00309
00310 gwthread_sleep(5.0);
00311 }
00312 }
00313 }
00314
00315
00316 static void write_pid_file(void)
00317 {
00318 int fd;
00319 FILE *file;
00320
00321 if (!pid_file)
00322 return;
00323
00324 fd = open(pid_file, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT|O_EXCL, 0644);
00325 if (fd == -1)
00326 panic(errno, "Could not open pid-file `%s'", pid_file);
00327
00328 file = fdopen(fd, "w");
00329 if (!file)
00330 panic(errno, "Could not open file-stream `%s'", pid_file);
00331
00332 fprintf(file, "%ld\n", (long) getpid());
00333 fclose(file);
00334 }
00335
00336 static void remove_pid_file(void)
00337 {
00338 if (!pid_file)
00339 return;
00340
00341
00342 if (child_pid == 0)
00343 return;
00344
00345 if (-1 == unlink(pid_file))
00346 error(errno, "Could not unlink pid-file `%s'", pid_file);
00347 }
00348
00349 static int change_user(const char *user)
00350 {
00351 struct passwd *pass;
00352
00353 if (!user)
00354 return -1;
00355
00356 pass = getpwnam(user);
00357 if (!pass) {
00358 error(0, "Could not find a user `%s' in system.", user);
00359 return -1;
00360 }
00361
00362 if (-1 == setgid(pass->pw_gid)) {
00363 error(errno, "Could not change group id from %ld to %ld.", (long) getgid(), (long) pass->pw_gid);
00364 return -1;
00365 }
00366
00367 if (initgroups(user, -1) == -1) {
00368 error(errno, "Could not set supplementary group ID's.");
00369 }
00370
00371 if (-1 == setuid(pass->pw_uid)) {
00372 error(errno, "Could not change user id from %ld to %ld.", (long) getuid(), (long) pass->pw_uid);
00373 return -1;
00374 }
00375
00376 return 0;
00377 }
00378
00379
00380
00381
00382
00383
00384
00385 MultibyteInt get_variable_value(Octet *source, int *len)
00386 {
00387 MultibyteInt retval = 0;
00388
00389 for(*len=1;; (*len)++, source++) {
00390 retval = retval * 0x80 + (*source & 0x7F);
00391 if (*source < 0x80)
00392 break;
00393 }
00394 return retval;
00395 }
00396
00397
00398 int write_variable_value(MultibyteInt value, Octet *dest)
00399 {
00400 int i, loc = 0;
00401 Octet revbuffer[20];
00402
00403 for (;;) {
00404 revbuffer[loc++] = (value & 0x7F) + 0x80;
00405 if (value >= 0x80)
00406 value = value >> 7;
00407 else
00408 break;
00409 }
00410 for(i=0; i < loc; i++)
00411 dest[i] = revbuffer[loc-i-1];
00412
00413 dest[loc-1] &= 0x7F;
00414
00415 return loc;
00416 }
00417
00418 Octet reverse_octet(Octet source)
00419 {
00420 Octet dest;
00421 dest = (source & 1) <<7;
00422 dest += (source & 2) <<5;
00423 dest += (source & 4) <<3;
00424 dest += (source & 8) <<1;
00425 dest += (source & 16) >>1;
00426 dest += (source & 32) >>3;
00427 dest += (source & 64) >>5;
00428 dest += (source & 128) >>7;
00429
00430 return dest;
00431 }
00432
00433
00434 int get_and_set_debugs(int argc, char **argv,
00435 int (*find_own) (int index, int argc, char **argv))
00436 {
00437 int i, ret = -1;
00438 int debug_lvl = -1;
00439 int file_lvl = GW_DEBUG;
00440 char *log_file = NULL;
00441 char *debug_places = NULL;
00442 char *panic_script = NULL, *user = NULL;
00443 int parachute = 0, daemonize = 0;
00444
00445 for (i=1; i < argc; i++) {
00446 if (strcmp(argv[i],"-v")==0 || strcmp(argv[i],"--verbosity")==0) {
00447 if (i+1 < argc) {
00448 debug_lvl = atoi(argv[i+1]);
00449 i++;
00450 } else
00451 panic(0, "Missing argument for option %s\n", argv[i]);
00452 } else if (strcmp(argv[i],"-F")==0 || strcmp(argv[i],"--logfile")==0) {
00453 if (i+1 < argc && *(argv[i+1]) != '-') {
00454 log_file = argv[i+1];
00455 i++;
00456 } else
00457 panic(0, "Missing argument for option %s\n", argv[i]);
00458 } else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--fileverbosity")==0) {
00459 if (i+1 < argc) {
00460 file_lvl = atoi(argv[i+1]);
00461 i++;
00462 } else
00463 panic(0, "Missing argument for option %s\n", argv[i]);
00464 } else if (strcmp(argv[i],"-D")==0 || strcmp(argv[i],"--debug")==0) {
00465 if (i+1 < argc) {
00466 debug_places = argv[i+1];
00467 i++;
00468 } else
00469 panic(0, "Missing argument for option %s\n", argv[i]);
00470 } else if (strcmp(argv[i], "-X")==0 || strcmp(argv[i], "--panic-script")==0) {
00471 if (i+1 < argc) {
00472 panic_script = argv[i+1];
00473 i++;
00474 } else
00475 panic(0, "Missing argument for option %s\n", argv[i]);
00476 } else if (strcmp(argv[i], "-P")==0 || strcmp(argv[i], "--parachute")==0) {
00477 parachute = 1;
00478 } else if (strcmp(argv[i], "-d")==0 || strcmp(argv[i], "--daemonize")==0) {
00479 daemonize = 1;
00480 } else if (strcmp(argv[i], "-p")==0 || strcmp(argv[i], "--pid-file")==0) {
00481 if (i+1 < argc) {
00482 pid_file = argv[i+1];
00483 i++;
00484 } else
00485 panic(0, "Missing argument for option %s\n", argv[i]);
00486 } else if (strcmp(argv[i], "-u")==0 || strcmp(argv[i], "--user")==0) {
00487 if (i+1 < argc) {
00488 user = argv[i+1];
00489 i++;
00490 } else
00491 panic(0, "Missing argument for option %s\n", argv[i]);
00492 } else if (strcmp(argv[i], "-g")==0 || strcmp(argv[i], "--generate")==0) {
00493 cfg_dump_all();
00494 exit(0);
00495 } else if (strcmp(argv[i],"--")==0) {
00496 i++;
00497 break;
00498 } else if (*argv[i] != '-') {
00499 break;
00500 } else {
00501 if (find_own != NULL) {
00502 ret = find_own(i, argc, argv);
00503 }
00504 if (ret < 0) {
00505 fprintf(stderr, "Unknown option %s, exiting.\n", argv[i]);
00506 panic(0, "Option parsing failed");
00507 } else
00508 i += ret;
00509 }
00510 }
00511
00512 if (user && -1 == change_user(user))
00513 panic(0, "Could not change to user `%s'.", user);
00514
00515
00516 if (daemonize && !become_daemon())
00517 exit(0);
00518
00519 if (pid_file) {
00520 write_pid_file();
00521 atexit(remove_pid_file);
00522 }
00523
00524 if (parachute) {
00525
00526
00527
00528
00529 if (daemonize) {
00530 char *ident = strrchr(argv[0], '/');
00531 if (!ident)
00532 ident = argv[0];
00533 else
00534 ident++;
00535 log_set_syslog(ident, (debug_lvl > -1 ? debug_lvl : 0));
00536 }
00537 parachute_start(argv[0], panic_script);
00538
00539 if (daemonize)
00540 log_close_all();
00541 }
00542
00543 if (debug_lvl > -1)
00544 log_set_output_level(debug_lvl);
00545 if (debug_places != NULL)
00546 log_set_debug_places(debug_places);
00547 if (log_file != NULL)
00548 log_open(log_file, file_lvl, GW_NON_EXCL);
00549
00550 info(0, "Debug_lvl = %d, log_file = %s, log_lvl = %d",
00551 debug_lvl, log_file ? log_file : "<none>", file_lvl);
00552 if (debug_places != NULL)
00553 info(0, "Debug places: `%s'", debug_places);
00554
00555 return i;
00556 }
00557
00558
00559 static int pattern_matches_ip(Octstr *pattern, Octstr *ip)
00560 {
00561 long i, j;
00562 long pat_len, ip_len;
00563 int pat_c, ip_c;
00564
00565 pat_len = octstr_len(pattern);
00566 ip_len = octstr_len(ip);
00567
00568 i = 0;
00569 j = 0;
00570 while (i < pat_len && j < ip_len) {
00571 pat_c = octstr_get_char(pattern, i);
00572 ip_c = octstr_get_char(ip, j);
00573 if (pat_c == ip_c) {
00574
00575 ++i;
00576 ++j;
00577 } else if (pat_c != '*') {
00578
00579 return 0;
00580 } else {
00581
00582 ++i;
00583 while (j < ip_len && ip_c != '.') {
00584 ++j;
00585 ip_c = octstr_get_char(ip, j);
00586 }
00587 }
00588 }
00589
00590 if (i >= pat_len && j >= ip_len)
00591 return 1;
00592 return 0;
00593 }
00594
00595
00596 static int pattern_list_matches_ip(Octstr *pattern_list, Octstr *ip)
00597 {
00598 List *patterns;
00599 Octstr *pattern;
00600 int matches;
00601
00602 patterns = octstr_split(pattern_list, octstr_imm(";"));
00603 matches = 0;
00604
00605 while (!matches && (pattern = gwlist_extract_first(patterns)) != NULL) {
00606 matches = pattern_matches_ip(pattern, ip);
00607 octstr_destroy(pattern);
00608 }
00609
00610 gwlist_destroy(patterns, octstr_destroy_item);
00611 return matches;
00612 }
00613
00614
00615 int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip)
00616 {
00617 if (ip == NULL)
00618 return 0;
00619
00620 if (octstr_len(deny_ip) == 0)
00621 return 1;
00622
00623 if (allow_ip != NULL && pattern_list_matches_ip(allow_ip, ip))
00624 return 1;
00625
00626 if (pattern_list_matches_ip(deny_ip, ip))
00627 return 0;
00628
00629 return 1;
00630 }
00631
00632
00633 int connect_denied(Octstr *allow_ip, Octstr *ip)
00634 {
00635 if (ip == NULL)
00636 return 1;
00637
00638
00639 if (allow_ip == NULL) {
00640 if (pattern_list_matches_ip(octstr_imm("127.0.0.1"), ip))
00641 return 0;
00642 } else {
00643 if (pattern_list_matches_ip(allow_ip, ip))
00644 return 0;
00645 }
00646 return 1;
00647 }
00648
00649
00650 int does_prefix_match(Octstr *prefix, Octstr *number)
00651 {
00652
00653
00654 char *b, *p, *n;
00655
00656 gw_assert(prefix != NULL);
00657 gw_assert(number != NULL);
00658
00659 p = octstr_get_cstr(prefix);
00660 n = octstr_get_cstr(number);
00661
00662
00663 while (*p != '\0') {
00664 b = n;
00665 for (b = n; *b != '\0'; b++, p++) {
00666 if (*p == ';' || *p == '\0') {
00667 return 1;
00668 }
00669 if (*p != *b) break;
00670 }
00671 if (*p == ';' || *p == '\0') {
00672 return 1;
00673 }
00674 while (*p != '\0' && *p != ';')
00675 p++;
00676 while (*p == ';') p++;
00677 }
00678 return 0;
00679 }
00680
00681
00682 int normalize_number(char *dial_prefixes, Octstr **number)
00683 {
00684 char *t, *p, *official, *start;
00685 int len, official_len;
00686
00687 if (dial_prefixes == NULL || dial_prefixes[0] == '\0')
00688 return 0;
00689
00690 t = official = dial_prefixes;
00691 official_len = 0;
00692
00693 gw_assert(number != NULL);
00694
00695 while(1) {
00696
00697 p = octstr_get_cstr(*number);
00698 for(start = t, len = 0; ; t++, p++, len++)
00699 {
00700 if (*t == ',' || *t == ';' || *t == '\0') {
00701 if (start != official) {
00702 Octstr *nstr;
00703 long n;
00704
00705 if ( official[0] == '-' ) official_len=0;
00706 n = official_len;
00707 if (strlen(official) < (size_t) n)
00708 n = strlen(official);
00709 nstr = octstr_create_from_data(official, n);
00710 octstr_insert_data(nstr, official_len,
00711 octstr_get_cstr(*number) + len,
00712 octstr_len(*number) - len);
00713 octstr_destroy(*number);
00714 *number = nstr;
00715 }
00716 return 1;
00717 }
00718 if (*p == '\0' || *t != *p)
00719 break;
00720 }
00721 for(; *t != ',' && *t != ';' && *t != '\0'; t++, len++)
00722 ;
00723 if (*t == '\0') break;
00724 if (start == official) official_len = len;
00725 if (*t == ';') official = t+1;
00726 t++;
00727 }
00728 return 0;
00729 }
00730
00731
00732
00733
00734
00735 long decode_network_long(unsigned char *data) {
00736 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
00737 }
00738
00739
00740 void encode_network_long(unsigned char *data, unsigned long value) {
00741 data[0] = (value >> 24) & 0xff;
00742 data[1] = (value >> 16) & 0xff;
00743 data[2] = (value >> 8) & 0xff;
00744 data[3] = value & 0xff;
00745 }
00746
00747
00748
00749
00750
00751 void kannel_cfmakeraw (struct termios *tio){
00752
00753 tio->c_cc[VMIN] = 1;
00754 tio->c_cc[VTIME] = 0;
00755
00756
00757
00758
00759
00760
00761
00762 tio->c_cflag &= ~(CSIZE|PARENB);
00763 tio->c_cflag |= CS8;
00764
00765
00766
00767
00768
00769
00770
00771
00772 tio->c_iflag &= ~(BRKINT|ICRNL|IGNCR|IGNBRK|INLCR|IXON|ISTRIP);
00773
00774
00775
00776
00777
00778
00779
00780 tio->c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
00781
00782
00783
00784 tio->c_oflag &= ~OPOST;
00785 }
00786
00787
00788 int gw_isdigit(int c)
00789 {
00790 return isdigit(c);
00791 }
00792
00793
00794 int gw_isxdigit(int c)
00795 {
00796 return isxdigit(c);
00797 }
00798
00799
00800
00801 int roundup_div(int a, int b)
00802 {
00803 int t;
00804
00805 t = a / b;
00806 if (t * b != a)
00807 t += 1;
00808
00809 return t;
00810 }
00811
00812
00813 unsigned long long gw_generate_id(void)
00814 {
00815
00816
00817 unsigned long random, timer;
00818
00819 random = gw_rand();
00820 timer = (unsigned long)time(NULL);
00821
00822 return ((unsigned long long)timer << 32) + random;
00823 }
00824
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.