void main_exit(int code) { #if USING_DMALLOC dmalloc_log_unfreed(); dmalloc_shutdown(); #endif exit(code); }
static void cleanup(void) { #ifdef DMALLOC dmalloc_verify(0); dmalloc_log_unfreed(); #endif #ifdef JLIB jv_check_mem(); #endif }
static void l2tp_toggle_debug(void) { #ifdef USL_DMALLOC dmalloc_log_unfreed(); dmalloc_log_stats(); dmalloc_log_heap_map(); #endif l2tp_opt_debug = !l2tp_opt_debug; }
static void cleanup(void) { alcDestroyContext(cc); #ifdef DMALLOC dmalloc_verify(0); dmalloc_log_unfreed(); #endif #ifdef JLIB jv_check_mem(); #endif }
/* under Linux a sighandler must reenable itself */ void sig_handler(int sig) { logmsg(LOG_INFO, "%s: signal %i received", STR_PROGNAME, sig); signal(sig, sig_handler); output_stats(); reset_stats(); #ifdef DMALLOC logmsg(LOG_DEBUG, "%s: dumping dmalloc statistics", STR_PROGNAME); dmalloc_log_stats(); dmalloc_log_unfreed(); #endif }
int main(int argc, char** argv) { int c; char* p; uid_t uid, gid, client_gid, root_gid; struct passwd* pw; struct group* gr; struct stat st; int localsocket = 1; /* * compilerwarnung: "client_gid may be used uninitialized" * sowas will man ja nun wirklich nicht ... */ uid = gid = client_gid = root_gid = 0; while ((c = getopt(argc, argv, "bc:d:hfg:k:m:n:s:t:u:vx")) > 0) { switch (c) { case 'b': /* break contentheader */ logmsg(LOG_INFO, "option -b is ignored for compatibily reasons, you may remove it safely"); break; case 'c': /* clientgroup */ opt_clientgroup = optarg; if ((gr = getgrnam(opt_clientgroup)) == NULL) { logmsg(LOG_ERR, "unknown clientgroup: getgrnam(%s) failed", opt_group); exit(EX_DATAERR); } client_gid = gr->gr_gid; break; case 'd': /* Loglevel */ opt_loglevel = (int) strtoul(optarg, &p, 10); if (p != NULL && *p != '\0') { printf("debug-level is not valid integer: %s\n", optarg); exit(EX_DATAERR); } p = NULL; if (opt_loglevel < 0 || opt_loglevel > 7) { printf("loglevel out of range 0..7: %i\n", opt_loglevel); exit(EX_DATAERR); } break; case 'f': /* signer from header, not from envelope */ opt_signerfromheader = 1; break; case 'g': /* group */ opt_group = optarg; if ((gr = getgrnam(opt_group)) == NULL) { printf("unknown group: getgrnam(%s) failed", opt_group); exit(EX_DATAERR); } break; case 'k': /* keepdir */ opt_keepdir = optarg; if (stat(opt_keepdir, &st) < 0) { printf("directory to keep data: %s: %s", opt_keepdir, strerror(errno)); exit(EX_DATAERR); } if (!S_ISDIR(st.st_mode)) { printf("directory to keep data: %s is not a directory", opt_keepdir); exit(EX_DATAERR); } /* Zugriffsrechte werden spaeter geprueft, wenn zur richtigen uid gewechselt wurde */ break; case '?': /* help */ case 'h': usage(); exit(EX_OK); case 'm': /* Signingtable cdbfilename */ opt_signingtable = optarg; break; case 'n': /* Modetable cdbfilename */ opt_modetable = optarg; break; case 's': /* Miltersocket */ opt_miltersocket = optarg; break; case 't': /* Timeout */ opt_timeout = (int) strtoul(optarg, &p, 10); if (p != NULL && *p != '\0') { printf("timeout is not valid integer: %s\n", optarg); exit(EX_DATAERR); } p = NULL; if (opt_timeout < 0 ) { printf("negative milter connection timeout: %i\n", opt_timeout); exit(EX_DATAERR); } break; case 'u': /* user */ opt_user = optarg; /* get passwd/group entries for opt_user and opt_group */ if ((pw = getpwnam(opt_user)) == NULL) { logmsg(LOG_ERR, "unknown user: getpwnam(%s) failed", opt_user); exit(EX_DATAERR); } break; case 'v': /* Version */ version(); exit(EX_OK); case 'x': /* add X-Header */ opt_addxheader = (int) !opt_addxheader; break; default: usage(); exit(EX_USAGE); } } /* open syslog an say helo */ openlog(STR_PROGNAME, LOG_PID, LOG_MAIL); logmsg(LOG_NOTICE, "starting %s %s listening on %s, loglevel %i", STR_PROGNAME, STR_PROGVERSION, opt_miltersocket, opt_loglevel); /* force a new processgroup */ if ((setsid() == -1)) logmsg(LOG_DEBUG, "ignoring that setsid() failed"); if (opt_timeout > 0 && smfi_settimeout(opt_timeout) != MI_SUCCESS) { logmsg(LOG_ERR, "could not set milter timeout"); exit(EX_SOFTWARE); } logmsg(LOG_INFO, "miltertimeout set to %i", opt_timeout); if (smfi_setconn(opt_miltersocket) != MI_SUCCESS) { logmsg(LOG_ERR, "could not set milter socket"); exit(EX_SOFTWARE); } if (smfi_register(callbacks) != MI_SUCCESS) { logmsg(LOG_ERR, "could not register milter"); exit(EX_SOFTWARE); } /* * User- und Gruppennamen stehen nun fest. Testen, ob es diese gibt * und uid / gid ermitteln */ if ((pw = getpwnam(opt_user)) == NULL) { logmsg(LOG_ERR, "unknown user: getpwnam(%s) failed", opt_user); exit(EX_DATAERR); } uid = pw->pw_uid; if ((gr = getgrnam(opt_group)) == NULL) { logmsg(LOG_ERR, "unknown group: getgrnam(%s) failed", opt_group); exit(EX_SOFTWARE); } gid = gr->gr_gid; /* wenn nicht als Parameter angegeben, gehört ein Unix-Socket erstmal der gleichen Gruppe */ if (opt_clientgroup == NULL) client_gid = gid; /* wenn inet in optarg gefunden wird *und* das auch noch direkt am Anfang * dann ist's kein lokaler socket */ if (((p = strstr(opt_miltersocket, "inet")) != NULL) && opt_miltersocket == p) localsocket = 0; if (localsocket == 1) { /* den Socket oeffnen */ if (smfi_opensocket(REMOVE_EXISTING_SOCKETS) != MI_SUCCESS) { logmsg(LOG_ERR, "could not open milter socket %s", opt_miltersocket); exit(EX_SOFTWARE); } /* testen, ob's den Socket nun gibt */ p = opt_miltersocket + strlen("local:"); if (stat(p, &st) < 0) { p = opt_miltersocket + strlen("unix:"); if (stat(p, &st) < 0) { logmsg(LOG_ERR, "miltersocket does not exist: %m", strerror(errno)); exit(EX_DATAERR); } } /* gid der Gruppe root */ if ((gr = getgrnam("root")) == NULL) { logmsg(LOG_ERR, "unknown rootgroup: getgrnam(root) failed"); exit(EX_SOFTWARE); } root_gid = gr->gr_gid; /* clientgroup muss != root und != opt_group sein */ if ((client_gid == gid) || (client_gid == root_gid)) { logmsg(LOG_ERR, "clientgroup %s must be neither %s nor %s", opt_clientgroup, "root", opt_group); exit(EX_DATAERR); } /* nun die Rechte setzen */ if (chown(p, uid, client_gid) != 0) { logmsg(LOG_ERR, "chown(%s, %i, %i) failed: %m", p, uid, client_gid, strerror(errno)); exit(EX_SOFTWARE); } if (chmod(p, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) { logmsg(LOG_ERR, "chmod(%s, 0660) failed: %m", p, strerror(errno)); exit(EX_SOFTWARE); } logmsg(LOG_INFO, "changed socket %s to owner/group: %i/%i, mode: 0660", opt_miltersocket, uid, client_gid); } /* gid/uid setzen */ if (setgid(gid) != 0) { logmsg(LOG_ERR, "setgid(%i) failed: %s", gr->gr_gid, strerror(errno)); exit(EX_SOFTWARE); } if (setuid(uid) != 0) { logmsg(LOG_ERR, "setuid(%i) failed: %s", pw->pw_uid, strerror(errno)); exit(EX_SOFTWARE); } /* aktuelle uid/gid pruefen und loggen */ uid = getuid(); gid = getgid(); if (uid == 0 || gid == 0) { logmsg(LOG_ERR, "too much priveleges, %s will not start under root", STR_PROGNAME); exit(EX_DATAERR); } logmsg(LOG_INFO, "running as uid: %i, gid: %i", (int) uid, (int) gid); if (opt_keepdir != NULL) { if (S_IRWXO & st.st_mode) { logmsg(LOG_ERR, "directory to keep data: %s: permissions too open: remove any access for other", opt_keepdir); exit(EX_DATAERR); } if (access(opt_keepdir, R_OK) < 0 && errno == EACCES) { logmsg(LOG_ERR, "directory to keep data: %s: permissions too strong: no read access", opt_keepdir); exit(EX_DATAERR); } if (access(opt_keepdir, W_OK) < 0 && errno == EACCES) { logmsg(LOG_ERR, "directory to keep data: %s: permissions too strong: no write access", opt_keepdir); exit(EX_DATAERR); } if (access(opt_keepdir, X_OK) < 0 && errno == EACCES) { logmsg(LOG_ERR, "directory to keep data: %s: permissions too strong: no execute access", opt_keepdir); exit(EX_DATAERR); } logmsg(LOG_INFO, "directory to keep data: %s", opt_keepdir); } dict_open(opt_signingtable, &dict_signingtable); if (opt_modetable) dict_open(opt_modetable, &dict_modetable); /* initialize OpenSSL */ SSL_library_init(); OpenSSL_add_all_algorithms(); /* get meaningful error messages */ SSL_load_error_strings(); ERR_load_crypto_strings(); /* Statistik initialisieren */ init_stats(); /* Signal-Handler fuer SIGALRM */ signal(SIGALRM, sig_handler); /* Run milter */ if ((c = smfi_main()) != MI_SUCCESS) logmsg(LOG_ERR, "Milter startup failed"); else logmsg(LOG_NOTICE, "stopping %s %s listening on %s", STR_PROGNAME, STR_PROGVERSION, opt_miltersocket); dict_close(&dict_signingtable); if (opt_modetable) dict_close(&dict_modetable); /* cleanup OpenSSL */ ERR_free_strings(); EVP_cleanup(); output_stats(); #ifdef DMALLOC dmalloc_log_stats(); dmalloc_log_unfreed(); dmalloc_shutdown(); #endif exit(c); }
int main (int argc, char *argv[]) { int sts; int i; int buflen; int access; char buff [BUFFER_SIZE]; sip_ticket_t ticket; extern char *optarg; /* Defined in libc getopt and unistd.h */ int ch1; char configfile[64]="siproxd"; /* basename of configfile */ int config_search=1; /* search the config file */ int cmdline_debuglevel=0; char *pidfilename=NULL; struct sigaction act; log_set_stderr(1); /* * setup signal handlers */ act.sa_handler=sighandler; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; if (sigaction(SIGTERM, &act, NULL)) { ERROR("Failed to install SIGTERM handler"); } if (sigaction(SIGINT, &act, NULL)) { ERROR("Failed to install SIGINT handler"); } if (sigaction(SIGUSR2, &act, NULL)) { ERROR("Failed to install SIGUSR2 handler"); } /* * prepare default configuration */ make_default_config(); log_set_pattern(configuration.debuglevel); /* * parse command line */ { #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"debug", required_argument, NULL, 'd'}, {"pid-file", required_argument, NULL,'p'}, {0,0,0,0} }; while ((ch1 = getopt_long(argc, argv, "hc:d:p:", long_options, &option_index)) != -1) { #else /* ! HAVE_GETOPT_LONG */ while ((ch1 = getopt(argc, argv, "hc:d:p:")) != -1) { #endif switch (ch1) { case 'h': /* help */ DEBUGC(DBCLASS_CONFIG,"option: help"); fprintf(stderr,str_helpmsg); exit(0); break; case 'c': /* load config file */ DEBUGC(DBCLASS_CONFIG,"option: config file=%s",optarg); i=sizeof(configfile)-1; strncpy(configfile,optarg,i-1); configfile[i]='\0'; config_search=0; break; case 'd': /* set debug level */ DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg); cmdline_debuglevel=atoi(optarg); log_set_pattern(cmdline_debuglevel); break; case 'p': pidfilename = optarg; break; default: DEBUGC(DBCLASS_CONFIG,"no command line options"); break; } } } /* * Init stuff */ INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" starting up"); /* read the config file */ if (read_config(configfile, config_search) == STS_FAILURE) exit(1); /* if a debug level > 0 has been given on the commandline use its value and not what is in the config file */ if (cmdline_debuglevel != 0) { configuration.debuglevel=cmdline_debuglevel; } /* * open a the pwfile instance, so we still have access after * we possibly have chroot()ed to somewhere. */ if (configuration.proxy_auth_pwfile) { siproxd_passwordfile = fopen(configuration.proxy_auth_pwfile, "r"); } else { siproxd_passwordfile = NULL; } /* set debug level as desired */ log_set_pattern(configuration.debuglevel); log_set_listen_port(configuration.debugport); /* change user and group IDs */ secure_enviroment(); /* daemonize if requested to */ if (configuration.daemonize) { DEBUGC(DBCLASS_CONFIG,"daemonizing"); if (fork()!=0) exit(0); setsid(); if (fork()!=0) exit(0); log_set_stderr(0); INFO("daemonized, pid=%i", getpid()); } /* write PID file of main thread */ if (pidfilename == NULL) pidfilename = configuration.pid_file; if (pidfilename) { FILE *pidfile; DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename); sts=unlink(configuration.pid_file); if ((sts==0) ||(errno == ENOENT)) { if ((pidfile=fopen(pidfilename, "w"))) { fprintf(pidfile,"%i\n",(int)getpid()); fclose(pidfile); } else { WARN("couldn't create new PID file: %s", strerror(errno)); } } else { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* initialize the RTP proxy */ sts=rtpproxy_init(); if (sts != STS_SUCCESS) { ERROR("unable to initialize RTP proxy - aborting"); exit(1); } /* init the oSIP parser */ parser_init(); /* listen for incoming messages */ sts=sipsock_listen(); if (sts == STS_FAILURE) { /* failure to allocate SIP socket... */ ERROR("unable to bind to SIP listening socket - aborting"); exit(1); } /* initialize the registration facility */ register_init(); /* * silence the log - if so required... */ log_set_silence(configuration.silence_log); INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" started"); /***************************** * Main loop *****************************/ while (!exit_program) { DEBUGC(DBCLASS_BABBLE,"going into sipsock_wait\n"); while (sipsock_wait()<=0) { /* got no input, here by timeout. do aging */ register_agemap(); /* TCP log: check for a connection */ log_tcp_connect(); /* dump memory stats if requested to do so */ if (dmalloc_dump) { dmalloc_dump=0; #ifdef DMALLOC INFO("SIGUSR2 - DMALLOC statistics is dumped"); dmalloc_log_stats(); dmalloc_log_unfreed(); #else INFO("SIGUSR2 - DMALLOC support is not compiled in"); #endif } if (exit_program) goto exit_prg; } /* * got input, process */ DEBUGC(DBCLASS_BABBLE,"back from sipsock_wait"); ticket.direction=0; buflen=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol); buff[buflen]='\0'; /* * evaluate the access lists (IP based filter) */ access=accesslist_check(ticket.from); if (access == 0) { DEBUGC(DBCLASS_ACCESS,"access for this packet was denied"); continue; /* there are no resources to free */ } /* * integrity checks */ sts=security_check_raw(buff, buflen); if (sts != STS_SUCCESS) { DEBUGC(DBCLASS_SIP,"security check (raw) failed"); continue; /* there are no resources to free */ } /* * init sip_msg */ sts=osip_message_init(&ticket.sipmsg); ticket.sipmsg->message=NULL; if (sts != 0) { ERROR("osip_message_init() failed... this is not good"); continue; /* skip, there are no resources to free */ } /* * RFC 3261, Section 16.3 step 1 * Proxy Behavior - Request Validation - Reasonable Syntax * (parse the received message) */ sts=sip_message_parse(ticket.sipmsg, buff, buflen); if (sts != 0) { ERROR("sip_message_parse() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * integrity checks - parsed buffer */ sts=security_check_sip(&ticket); if (sts != STS_SUCCESS) { ERROR("security_check_sip() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 2 * Proxy Behavior - Request Validation - URI scheme * (check request URI and refuse with 416 if not understood) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.3 step 3 * Proxy Behavior - Request Validation - Max-Forwards check * (check Max-Forwards header and refuse with 483 if too many hops) */ { osip_header_t *max_forwards; int forwards_count = DEFAULT_MAXFWD; osip_message_get_max_forwards(ticket.sipmsg, 0, &max_forwards); if (max_forwards && max_forwards->hvalue) { forwards_count = atoi(max_forwards->hvalue); } DEBUGC(DBCLASS_PROXY,"checking Max-Forwards (=%i)",forwards_count); if (forwards_count <= 0) { DEBUGC(DBCLASS_SIP, "Forward count reached 0 -> 483 response"); sip_gen_response(&ticket, 483 /*Too many hops*/); goto end_loop; /* skip and free resources */ } } /* * RFC 3261, Section 16.3 step 4 * Proxy Behavior - Request Validation - Loop Detection check * (check for loop and return 482 if a loop is detected) */ if (check_vialoop(&ticket) == STS_TRUE) { /* make sure we don't end up in endless loop when detecting * an loop in an "loop detected" message - brrr */ if (MSG_IS_RESPONSE(ticket.sipmsg) && MSG_TEST_CODE(ticket.sipmsg, 482)) { DEBUGC(DBCLASS_SIP,"loop in loop-response detected, ignoring"); } else { DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request"); sip_gen_response(&ticket, 482 /*Loop detected*/); } goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 5 * Proxy Behavior - Request Validation - Proxy-Require check * (check Proxy-Require header and return 420 if unsupported option) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.5 * Proxy Behavior - Determining Request Targets */ /* NOT IMPLEMENTED */ DEBUGC(DBCLASS_SIP,"received SIP type %s:%s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", (MSG_IS_REQUEST(ticket.sipmsg) ? ((ticket.sipmsg->sip_method)? ticket.sipmsg->sip_method : "NULL") : ((ticket.sipmsg->reason_phrase) ? ticket.sipmsg->reason_phrase : "NULL"))); /********************************* * The message did pass all the * tests above and is now ready * to be proxied. * Before we do so, we apply some * additional preprocessing *********************************/ /* Dial shortcuts */ if (configuration.pi_shortdial) { sts = plugin_shortdial(&ticket); if (sts == STS_SIP_SENT) goto end_loop; } /********************************* * finally proxy the message. * This includes the masquerading * of the local UA and starting/ * stopping the RTP proxy for this * call *********************************/ /* * if a REQ REGISTER, check if it is directed to myself, * or am I just the outbound proxy but no registrar. * - If I'm the registrar, register & generate answer * - If I'm just the outbound proxy, register, rewrite & forward */ if (MSG_IS_REGISTER(ticket.sipmsg) && MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_REG) { osip_uri_t *url; struct in_addr addr1, addr2, addr3; int dest_port; url = osip_message_get_uri(ticket.sipmsg); dest_port= (url->port)?atoi(url->port):SIP_PORT; if ( (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) && (get_interface_ip(IF_INBOUND,&addr2) == STS_SUCCESS) && (get_interface_ip(IF_OUTBOUND,&addr3) == STS_SUCCESS)) { if ((configuration.sip_listen_port == dest_port) && ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) || (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) { /* I'm the registrar, send response myself */ sts = register_client(&ticket, 0); sts = register_response(&ticket, sts); } else { /* I'm just the outbound proxy */ DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s", url->host); sts = register_client(&ticket, 1); if (sts == STS_SUCCESS) { sts = proxy_request(&ticket); } } } else { sip_gen_response(&ticket, 408 /*request timeout*/); } } else { WARN("non-authorized registration attempt from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * check if outbound interface is UP. * If not, send back error to UA and * skip any proxying attempt */ } else if (get_interface_ip(IF_OUTBOUND,NULL) != STS_SUCCESS) { DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface " "is down", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES"); if (MSG_IS_REQUEST(ticket.sipmsg)) sip_gen_response(&ticket, 408 /*request timeout*/); /* * MSG is a request, add current via entry, * do a lookup in the URLMAP table and * send to the final destination */ } else if (MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_request(&ticket); } else { INFO("non-authorized request received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * MSG is a response, remove current via and * send to the next VIA in chain */ } else if (MSG_IS_RESPONSE(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_response(&ticket); } else { INFO("non-authorized response received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * unsupported message */ } else { ERROR("received unsupported SIP type %s %s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", ticket.sipmsg->sip_method); } /********************************* * Done with proxying. Message * has been sent to its destination. *********************************/ /* * free the SIP message buffers */ end_loop: osip_message_free(ticket.sipmsg); } /* while TRUE */ exit_prg: /* save current known SIP registrations */ register_save(); INFO("properly terminating siproxd"); /* remove PID file */ if (pidfilename) { DEBUGC(DBCLASS_CONFIG,"deleting PID file [%s]", pidfilename); sts=unlink(pidfilename); if (sts != 0) { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* END */ return 0; } /* main */ /* * Signal handler * * this one is called asynchronously whevener a registered * signal is applied. Just set a flag and don't do any funny * things here. */ static void sighandler(int sig) { if (sig==SIGTERM) exit_program=1; if (sig==SIGINT) exit_program=1; if (sig==SIGUSR2) dmalloc_dump=1; return; }