diff --git a/ChangeLog b/ChangeLog index dadd7d2..541c798 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +0.2.2 +===== +- 12-Oct-2002: - '-d' commandline option supersedes condig file setting + of debug_level. + - reworked concept return status from functions - uses + now symbolic values + - added individual user passowrds for authentication + 0.2.1 ===== - 28-Sep-2002: - Released version 0.2.1 diff --git a/RELNOTES b/RELNOTES index 4a85798..170a00f 100644 --- a/RELNOTES +++ b/RELNOTES @@ -1,3 +1,37 @@ +Release Notes for siproxd-0.2.2 +=============================== + - SIP Proxy for SIP based softphones hidden behind a masquerading firewall + - Includes an RTP data stream proxy for *incomming* audio data + (outgoing RTP data should be handled by IP masquerading by the firewall) + - Port range to be used for incomming RTP traffic is configurable + (-> easy to set up apropriate firewall rules for incomming traffic) + - Multiple local users/hosts can be masqueraded simultaneously + - Supports running in a chroot jail (configurable) + - Supports changing user-ID after startup (if started as root) + - All configuration done via one simple ascii configuration file + - Proxy Authentication for registration of local clients (User Agents) + - Logging to syslog in Daemon mode + - Access control (IP based) for incomming traffic + - RPM support (spec file) + +Requirements: + - pthreads + - libosip 0.8.8 + +Currently tested on Linux 2.2.x (Redhat 6.0) and 2.4.x (Redhat 7.2), +should run on others Linux distributions as well. + +Interoperability (tested with softphones): + - Linphone (http://www.linphone.org) + - Kphone (http://www.wirlab.net/kphone/) + +----- +md5sum for siproxd-0.2.2.tar.gz: + +GnuPG signature for siproxd-0.2.2.tar.gz archive: + + + Release Notes for siproxd-0.2.1 =============================== - SIP Proxy for SIP based softphones hidden behind a masquerading firewall @@ -26,9 +60,16 @@ Interoperability (tested with softphones): - Kphone (http://www.wirlab.net/kphone/) ----- -md5sum for siproxd-0.2.1.tar.gz: +md5sum for siproxd-0.2.1.tar.gz: 3d0a46587494dd8c308c85f16d6f5555 GnuPG signature for siproxd-0.2.1.tar.gz archive: +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.5 (GNU/Linux) + +iEYEABECAAYFAj2U6d4ACgkQPOYHDi42pIq5ygCg3oavz9FHFTXNZT/R4YNECzEX +IX4AnAtYcNxJJhLXEKcj2ziKKvkectL9 +=A3tF +-----END PGP SIGNATURE----- diff --git a/TODO b/TODO index 80b2ad8..b0adff7 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,6 @@ TODOs, in random order: ======================= -- client authentication for registration - multiple user feature - -- redo return status (make then at least DEFINED constants) - - Documentation (yeah, yeah...) - general security issues @@ -18,5 +14,5 @@ TODOs, in random order: - portability to other platforms / operating systems first goal: other Unixes - +- security tests for received SIP messages (function securitycheck) diff --git a/configure.in b/configure.in index 986d4d8..e472dcd 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ dnl ****************************************************************** dnl SPD_MAJOR_VERSION=0 SPD_MINOR_VERSION=2 -SPD_MICRO_VERSION=1 +SPD_MICRO_VERSION=2 SPD_VERSION=$SPD_MAJOR_VERSION.$SPD_MINOR_VERSION.$SPD_MICRO_VERSION dnl ********************************************************************* diff --git a/doc/siproxd.conf.example b/doc/siproxd.conf.example index ae784b1..94a2514 100644 --- a/doc/siproxd.conf.example +++ b/doc/siproxd.conf.example @@ -93,6 +93,12 @@ rtp_timeout = 60 # registration is supported -> same for all local clients) # #proxy_auth_passwd = password +# +# or use individual per user passwords stored ia file +# +#proxy_auth_pwfile = doc/siproxd_passwd.cfg +# +# 'proxy_auth_pwfile' has precedence over 'proxy_auth_passwd' ###################################################################### # Debug level... (setting to -1 will enable everything) diff --git a/src/accessctl.c b/src/accessctl.c index 430a83e..3ad4b4a 100644 --- a/src/accessctl.c +++ b/src/accessctl.c @@ -47,7 +47,7 @@ int process_aclist (char *aclist, struct sockaddr_in from); * * returns a bitmask with ACCESSCTL_SIP, ACCESSCTL_REG */ -int check_accesslist (struct sockaddr_in from) { +int accesslist_check (struct sockaddr_in from) { int access = 0; DEBUGC(DBCLASS_ACCESS,"deny list (SIP):%s",configuration.hosts_deny_sip); @@ -60,7 +60,7 @@ int check_accesslist (struct sockaddr_in from) { if ( (configuration.hosts_deny_sip !=NULL) && (strcmp(configuration.hosts_deny_sip,"")!=0) ) { /* non-empty list -> check agains it */ - if (process_aclist(configuration.hosts_deny_sip, from)) { + if (process_aclist(configuration.hosts_deny_sip, from)== STS_SUCCESS) { /* yup - this one is blacklisted */ DEBUGC(DBCLASS_ACCESS,"caught by deny list"); return 0; @@ -73,7 +73,7 @@ int check_accesslist (struct sockaddr_in from) { if ( (configuration.hosts_allow_sip !=NULL) && (strcmp(configuration.hosts_allow_sip,"")!=0) ) { /* non-empty list -> check agains it */ - if (process_aclist(configuration.hosts_allow_sip, from)) { + if (process_aclist(configuration.hosts_allow_sip, from)==STS_SUCCESS) { /* SIP access granted */ DEBUGC(DBCLASS_ACCESS,"granted SIP access"); access |= ACCESSCTL_SIP; @@ -88,7 +88,7 @@ int check_accesslist (struct sockaddr_in from) { if ( (configuration.hosts_allow_reg !=NULL) && (strcmp(configuration.hosts_allow_reg,"")!=0) ) { /* non-empty list -> check agains it */ - if (process_aclist(configuration.hosts_allow_reg, from)) { + if (process_aclist(configuration.hosts_allow_reg, from)==STS_SUCCESS) { /* SIP registration access granted */ DEBUGC(DBCLASS_ACCESS,"granted REG/SIP access"); access |= ACCESSCTL_REG | ACCESSCTL_SIP; @@ -97,7 +97,7 @@ int check_accesslist (struct sockaddr_in from) { access |= ACCESSCTL_REG; } - return (access); + return access; } @@ -105,7 +105,9 @@ int check_accesslist (struct sockaddr_in from) { * checks for a match of the 'from' address with the supplies * access list. * - * return 1 for MATCH, 0 otherwise + * RETURNS + * STS_SUCCESS for a match + * STS_FAILURE for no match */ int process_aclist (char *aclist, struct sockaddr_in from) { int i; @@ -127,7 +129,7 @@ int process_aclist (char *aclist, struct sockaddr_in from) { p2=strchr(p1,'/'); if (!p2) { ERROR("CONFIG: hosts_deny_sip - no mask separator found"); - return 0; + return STS_FAILURE; } memset(address,0,sizeof(address)); memcpy(address,p1,p2-p1); @@ -159,8 +161,8 @@ int process_aclist (char *aclist, struct sockaddr_in from) { ntohl(from.sin_addr.s_addr) & bitmask); if ( (ntohl(inaddr.s_addr) & bitmask) == - (ntohl(from.sin_addr.s_addr) & bitmask) ) return 1; + (ntohl(from.sin_addr.s_addr) & bitmask) ) return STS_SUCCESS; } - return 0; + return STS_FAILURE; } diff --git a/src/auth.c b/src/auth.c index a36c8e1..d21c68c 100644 --- a/src/auth.c +++ b/src/auth.c @@ -21,6 +21,7 @@ #include "config.h" #include +#include #include #include @@ -46,42 +47,49 @@ extern struct siproxd_config configuration; /* local protorypes */ static char *auth_generate_nonce(void); static int auth_check(proxy_authorization_t *proxy_auth); +static char *auth_getpwd(char *username); /* * perform proxy authentication * - * sts = 0 : authentication ok / not needed - * sts = 1 : authentication failed - * sts = 2 : authentication needed + * RETURNS + * STS_SUCCESS : authentication ok / not needed + * STS_FAILURE : authentication failed + * STS_NEEDAUTH: authentication needed */ int authenticate_proxy(sip_t *request) { proxy_authorization_t *proxy_auth; - /* required by config ? (if not, return 0)*/ + /* required by config? */ if (configuration.proxy_auth_realm==NULL) { - return 0; + return STS_SUCCESS; } - /* supplied by UA? (if not, return 1)*/ + /* supplied by UA? */ msg_getproxy_authorization(request, 0, &proxy_auth); if (proxy_auth == NULL) { DEBUGC(DBCLASS_AUTH,"proxy-auth required, not supplied by UA"); - return 2; + return STS_NEED_AUTH; } /* verify supplied authentication */ if (auth_check(proxy_auth) == 0) { DEBUGC(DBCLASS_AUTH,"proxy-auth succeeded"); - return 0; + return STS_SUCCESS; } /* authentication failed */ DEBUGC(DBCLASS_AUTH,"proxy-auth failed"); - return 1; + return STS_FAILURE; } - +/* + * includes proxy authentication header in SIP message + * + * RETURNS + * STS_SUCCESS + */ int auth_include_authrq(sip_t *response) { int sts; char str[256]; @@ -103,12 +111,16 @@ int auth_include_authrq(sip_t *response) { sts = msg_setproxy_authenticate(response, str); - DEBUGC(DBCLASS_AUTH," msg_setproxy_authenticate sts=%i",sts); + DEBUGC(DBCLASS_AUTH,"msg_setproxy_authenticate sts=%i",sts); - return 0; + return STS_SUCCESS; } - +/* + * generates a nonce string + * + * RETURNS nonce string + */ static char *auth_generate_nonce() { static char nonce[40]; struct timeval tv; @@ -119,7 +131,7 @@ static char *auth_generate_nonce() { sprintf(nonce, "%8.8lx%8.8lx%8.8x%8.8x", tv.tv_sec, tv.tv_usec, rand(), rand() ); - DEBUGC(DBCLASS_AUTH," created nonce=\"%s\"",nonce); + DEBUGC(DBCLASS_AUTH,"created nonce=\"%s\"",nonce); return nonce; } @@ -127,8 +139,9 @@ static char *auth_generate_nonce() { /* * verify the supplied authentication information from UA * - * returns 0 if succeeded - * returns 1 if failed + * RETURNS + * STS_SUCCESS if succeeded + * STS_FAILURE if failed */ static int auth_check(proxy_authorization_t *proxy_auth) { char *password=NULL; @@ -172,11 +185,17 @@ static int auth_check(proxy_authorization_t *proxy_auth) { if (proxy_auth->response) Response=sgetcopy_unquoted_string(proxy_auth->response); - /* get password from configuration */ - if (configuration.proxy_auth_passwd) + /* get password */ + if (configuration.proxy_auth_pwfile) { + /* check in passwd file */ + password=auth_getpwd(Username); + } else if (configuration.proxy_auth_passwd) { + /* get password from configuration */ password=configuration.proxy_auth_passwd; - else - password=""; + } + + if (password == NULL) password=""; + DEBUGC(DBCLASS_BABBLE," username=\"%s\"",Username ); DEBUGC(DBCLASS_BABBLE," realm =\"%s\"",Realm ); @@ -192,14 +211,14 @@ static int auth_check(proxy_authorization_t *proxy_auth) { DigestCalcResponse(HA1, Nonce, NonceCount, CNonce, Qpop, "REGISTER", Uri, HA2, Lcl_Response); - DEBUGC(DBCLASS_BABBLE," calculated Response=\"%s\"", Lcl_Response); + DEBUGC(DBCLASS_BABBLE,"calculated Response=\"%s\"", Lcl_Response); if (strcmp(Lcl_Response, Response)==0) { - DEBUGC(DBCLASS_AUTH," Authentication succeeded"); - sts = 0; + DEBUGC(DBCLASS_AUTH,"Authentication succeeded"); + sts = STS_SUCCESS; } else { - DEBUGC(DBCLASS_AUTH," Authentication failed"); - sts = 1; + DEBUGC(DBCLASS_AUTH,"Authentication failed"); + sts = STS_FAILURE; } /* free allocated memory from above */ @@ -216,6 +235,90 @@ static int auth_check(proxy_authorization_t *proxy_auth) { } +/* + * lookup in the password file and return + * the user specific password for 'username' + * + * RETURNS + * password for user or NULL if not found + */ +static char *auth_getpwd(char *username) { + typedef struct { + char username[USERNAME_SIZE]; + char password[PASSWORD_SIZE]; + } auth_cache_t; + + FILE *pwdfile; + char buff[128]; + int i; + static auth_cache_t *auth_cache=NULL; + void *tmpptr; + static int auth_cache_size=0; + static int auth_cache_count=0; + + if (auth_cache==NULL) { + DEBUGC(DBCLASS_AUTH,"initialize password cache"); + pwdfile=fopen(configuration.proxy_auth_pwfile,"r"); + /* config file not found or unable to open for read */ + if (pwdfile==NULL) { + ERROR ("could not open password file: %s", strerror(errno)); + return NULL; + } + + while (fgets(buff,sizeof(buff),pwdfile) != NULL) { + /* life insurance */ + buff[sizeof(buff)-1]='\0'; + + /* strip newline if present */ + if (buff[strlen(buff)-1]=='\n') buff[strlen(buff)-1]='\0'; + + /* strip emty lines */ + if (strlen(buff) == 0) continue; + + /* strip comments and line with only whitespaces */ + for (i=0;i= auth_cache_size) { + auth_cache_size+=10; + tmpptr=realloc(auth_cache, auth_cache_size*sizeof(auth_cache_t)); + if (tmpptr != NULL) { + auth_cache= (auth_cache_t *)tmpptr; + } else { + ERROR("realloc failed! this is not good"); + auth_cache_size-=10; + return NULL; + } + } /* cnt > size */ + + i=sscanf(buff,"%s %s",auth_cache[auth_cache_count].username, + auth_cache[auth_cache_count].password); + /* if I got username & passwd, make it valid and increment counter */ + if (i == 2) auth_cache_count++; + } + + fclose(pwdfile); + + } /* initialize cache */ + + /* search cache for user */ + DEBUGC(DBCLASS_AUTH,"searching password entry for user %s",username); + for (i=0; i< auth_cache_count;i++) { + if (strcmp(username, auth_cache[i].username)==0) { + DEBUGC(DBCLASS_AUTH,"found password entry for user %s",username); + return auth_cache[i].password; + } + } + + DEBUGC(DBCLASS_AUTH,"no password entry found for user %s",username); + return NULL; +} + /*------------------------------------------------------------------------- ------------------------------------------------------------------------- diff --git a/src/proxy.c b/src/proxy.c index 0a8d7d1..0168f67 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -50,6 +50,9 @@ extern int sip_socket; /* sending SIP datagrams */ /* * PROXY_REQUEST * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int proxy_request (sip_t *request) { int i; @@ -68,9 +71,9 @@ int proxy_request (sip_t *request) { /* check for VIA loop, if yes, discard the request */ sts=check_vialoop(request); - if (sts !=0) { + if (sts == STS_TRUE) { DEBUGC(DBCLASS_PROXY,"via loop detected, ignoring request"); - return 1; + return STS_FAILURE; } type = 0; @@ -78,7 +81,7 @@ int proxy_request (sip_t *request) { if (urlmap[i].active == 0) continue; /* incomming request ('to' == 'masq') */ - if (compare_url(request->to->url, urlmap[i].masq_url)==0) { + if (compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) { type=REQTYP_INCOMMING; DEBUGC(DBCLASS_PROXY,"incomming request from %s@%s from outbound", request->from->url->username, @@ -87,7 +90,7 @@ int proxy_request (sip_t *request) { } /* outgoing request ('from' == 'masq') */ - if (compare_url(request->from->url, urlmap[i].masq_url)==0) { + if (compare_url(request->from->url, urlmap[i].masq_url)==STS_SUCCESS) { type=REQTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound", request->from->url->username, @@ -134,6 +137,9 @@ int proxy_request (sip_t *request) { /* add my Via header line (inbound interface)*/ sts = proxy_add_myvia(request, 1); + if (sts == STS_FAILURE) { + WARN("adding my inbound via failed!"); + } /* if this is CANCEL/BYE request, stop RTP proxying */ if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { @@ -157,7 +163,8 @@ int proxy_request (sip_t *request) { if (contact != NULL) { for (i=0;iurl, urlmap[i].true_url)==0) break; + if (compare_url(contact->url, urlmap[i].true_url)==STS_SUCCESS) + break; } /* found a mapping entry */ if (ifrom->url->host); /* some clients seem to run amok when passing back a negative response */ // proxy_gen_response(request, 403 /*forbidden*/); - return 1; + return STS_FAILURE; } @@ -231,7 +241,7 @@ int proxy_request (sip_t *request) { sts = msg_2char(request, &buffer); if (sts != 0) { ERROR("proxy_request: msg_2char failed"); - return 1; + return STS_FAILURE; } /* send to destination */ @@ -243,13 +253,16 @@ int proxy_request (sip_t *request) { sipsock_send_udp(&sip_socket, addr, port, buffer, strlen(buffer), 1); free (buffer); - return 0; + return STS_SUCCESS; } /* * PROXY_RESPONSE * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int proxy_response (sip_t *response) { int i; @@ -269,16 +282,16 @@ int proxy_response (sip_t *response) { /* check for VIA loop, if yes, discard the request */ sts=check_vialoop(response); - if (sts !=0) { + if (sts == STS_TRUE) { DEBUGC(DBCLASS_PROXY,"via loop detected, ignoring response"); - return 1; + return STS_FAILURE; } /* ALWAYS: remove my Via header line */ sts = proxy_del_myvia(response); - if (sts !=0) { + if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response"); - return 1; + return STS_FAILURE; } /* figure out if this is an request comming from the outside @@ -298,7 +311,7 @@ int proxy_response (sip_t *response) { /* incomming response ('from' == 'masq') */ - if (compare_url(response->from->url, urlmap[i].masq_url)==0) { + if (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS) { type=RESTYP_INCOMMING; DEBUGC(DBCLASS_PROXY,"incomming response for %s@%s from outbound", response->from->url->username, @@ -307,7 +320,7 @@ int proxy_response (sip_t *response) { } /* outgoing response ('to' == 'masq') */ - if (compare_url(response->to->url, urlmap[i].masq_url)==0) { + if (compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) { type=RESTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username, @@ -342,7 +355,8 @@ int proxy_response (sip_t *response) { if (contact != NULL) { for (i=0;iurl, urlmap[i].true_url)==0) break; + if (compare_url(contact->url, urlmap[i].true_url)==STS_SUCCESS) + break; } /* found a mapping entry */ if (i outbound interface, else inbound interface + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int proxy_add_myvia (sip_t *request, int interface) { struct in_addr addr; @@ -472,18 +493,21 @@ int proxy_add_myvia (sip_t *request, int interface) { DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp); sts = via_init(&via); - if (sts!=0) return -1; /* allocation failed */ + if (sts!=0) return STS_FAILURE; /* allocation failed */ sts = via_parse(via, tmp); - if (sts!=0) return -1; + if (sts!=0) return STS_FAILURE; list_add(request->vias,via,0); - return 0; + return STS_SUCCESS; } /* * PROXY_DEL_MYVIA * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int proxy_del_myvia (sip_t *response) { via_t *via; @@ -492,15 +516,15 @@ int proxy_del_myvia (sip_t *response) { DEBUGC(DBCLASS_PROXY,"deleting topmost VIA"); via = list_get (response->vias, 0); - if ( !is_via_local(via) ) { + if ( is_via_local(via) == STS_FALSE ) { ERROR("I'm trying to delete a VIA but it's not mine! host=%s",via->host); - return -1; + return STS_FAILURE; } sts = list_remove(response->vias, 0); via_free (via); free(via); - return 0; + return STS_SUCCESS; } @@ -509,6 +533,9 @@ int proxy_del_myvia (sip_t *response) { * * rewrites the outgoing INVITATION packet * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int proxy_rewrite_invitation_body(sip_t *mymsg){ body_t *body; @@ -523,7 +550,7 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ sts = msg_getbody(mymsg, 0, &body); if (sts != 0) { ERROR("rewrite_invitation_body: no body found in message"); - return 1; + return STS_FAILURE; } sts = body_2char(body, &oldbody); @@ -532,7 +559,7 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ sts = sdp_parse (sdp, oldbody); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sdp_parse body"); - return 1; + return STS_FAILURE; } { /* just dump the buffer */ @@ -583,13 +610,13 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ if (data_c == NULL) data_c = strstr (oldbody, "\rc="); if (data_c == NULL) { ERROR("did not find a c= line in the body"); - return 1; + return STS_FAILURE; } data_c += 3; /* can only rewrite IPV4 addresses by now */ if (strncmp(data_c,"IN IP4 ",7)!=0) { ERROR("c= does not contain an IN IP4 address"); - return 1; + return STS_FAILURE; } data_c += 7; /* PTR to start of IP address */ /* find the end of the IP address -> end of line */ @@ -597,7 +624,7 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ if (data2_c == NULL) data2_c = strstr (oldbody, "\r"); if (data2_c == NULL) { ERROR("did not find a CR/LF after c= line"); - return 1; + return STS_FAILURE; } /* @@ -607,20 +634,20 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ if (data_m == NULL) data_m = strstr (oldbody, "\rm="); if (data_m == NULL) { ERROR("did not find a m= line in the body"); - return 1; + return STS_FAILURE; } data_m += 3; /* check for audio media */ if (strncmp(data_m,"audio ",6)!=0) { ERROR("m= does not contain audio"); - return 1; + return STS_FAILURE; } data_m += 6; /* PTR to start of port number */ /* find the end of the IP address -> end of line */ data2_m = strstr (data_m, " RTP/"); if (data2_m == NULL) { ERROR("did not find RTP/ on m= line"); - return 1; + return STS_FAILURE; } /* @@ -702,5 +729,5 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ free(tmp2); } free(oldbody); - return 0; + return STS_SUCCESS; } diff --git a/src/readconf.c b/src/readconf.c index dca90cd..94136e2 100644 --- a/src/readconf.c +++ b/src/readconf.c @@ -42,12 +42,16 @@ static int parse_config (FILE *configfile); /* try to open (witchever found first): - - $HOME/.rc - /etc/.conf - /usr/etc/.conf - /usr/local/etc/.conf -*/ + * + * $HOME/.rc + * /etc/.conf + * /usr/etc/.conf + * /usr/local/etc/.conf + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error + */ int read_config(char *name, int search) { int sts; FILE *configfile=NULL; @@ -89,7 +93,7 @@ int read_config(char *name, int search) { /* config file not found or unable to open for read */ if (configfile==NULL) { ERROR ("could not open config file: %s", strerror(errno)); - return 1; + return STS_FAILURE; } sts = parse_config(configfile); @@ -98,7 +102,13 @@ int read_config(char *name, int search) { } - +/* + * parse configuration file + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error + */ static int parse_config (FILE *configfile) { char buff[128]; char *ptr; @@ -128,11 +138,15 @@ static int parse_config (FILE *configfile) { { "hosts_deny_sip", TYP_STRING, &configuration.hosts_deny_sip }, { "proxy_auth_realm", TYP_STRING, &configuration.proxy_auth_realm }, { "proxy_auth_passwd", TYP_STRING, &configuration.proxy_auth_passwd }, + { "proxy_auth_pwfile", TYP_STRING, &configuration.proxy_auth_pwfile }, {0, 0, 0} }; while (fgets(buff,sizeof(buff),configfile) != NULL) { + /* life insurance */ + buff[sizeof(buff)-1]='\0'; + /* strip newline if present */ if (buff[strlen(buff)-1]=='\n') buff[strlen(buff)-1]='\0'; @@ -191,5 +205,5 @@ static int parse_config (FILE *configfile) { } } - return 0; + return STS_SUCCESS; } diff --git a/src/register.c b/src/register.c index c6ac232..ad94701 100644 --- a/src/register.c +++ b/src/register.c @@ -52,9 +52,11 @@ void register_init(void) { /* * handles register requests and updates the URL mapping table - * sts = 0 : successfully registered - * sts = 1 : registration failed - * sts = 2 : authentication needed + * + * RETURNS: + * STS_SUCCESS : successfully registered + * STS_FAILURE : registration failed + * STS_NEED_AUTH : authentication needed */ int register_client(sip_t *my_msg) { int i, j, sts; @@ -64,20 +66,18 @@ int register_client(sip_t *my_msg) { url_t *url2_to, *url2_contact; header_t *expires_hdr; -/* - do proxy authentication -*/ + /* check for proxy authentication */ sts = authenticate_proxy(my_msg); - if (sts == 1) { + if (sts == STS_FAILURE) { /* failed */ WARN("proxy authentication failed for %s@%s", my_msg->to->url->username,my_msg->to->url->host); - return (1); - } else if (sts == 2) { + return STS_FAILURE; + } else if (sts == STS_NEED_AUTH) { /* needed */ DEBUGC(DBCLASS_REG,"proxy authentication needed for %s@%s", my_msg->to->url->username,my_msg->to->url->host); - return (2); + return STS_NEED_AUTH; } /* @@ -126,7 +126,7 @@ int register_client(sip_t *my_msg) { url2_to=urlmap[i].masq_url; url2_contact=urlmap[i].true_url; - if ( (compare_url(url1_to, url2_to)==0) && + if ( (compare_url(url1_to, url2_to)==STS_SUCCESS) && (strcmp(url1_contact->username, url2_contact->username)==0) && (strcmp(url1_contact->host, url2_contact->host )==0) ) { DEBUGC(DBCLASS_REG, "found entry for %s@%s at slot=%i, exp=%li", @@ -139,7 +139,7 @@ int register_client(sip_t *my_msg) { if ( (j < 0) && (i >= URLMAP_SIZE) ) { /* oops, no free entries left... */ ERROR("URLMAP is full - registration failed"); - return 1; + return STS_FAILURE; } if (i >= URLMAP_SIZE) { @@ -164,7 +164,7 @@ int register_client(sip_t *my_msg) { /* update registration timeout */ urlmap[i].expires=time_now+expires; - return 0; + return STS_SUCCESS; } @@ -198,9 +198,13 @@ void register_agemap(void) { /* * send answer to a registration request. - * flag = 0 -> positive answer (200) - * flag = 1 -> negative answer (503) - * flag = 2 -> proxy authentication needed (407) + * flag = STS_SUCCESS -> positive answer (200) + * flag = STS_FAILURE -> negative answer (503) + * flag = STS_NEED_AUTH -> proxy authentication needed (407) + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int register_response(sip_t *request, int flag) { sip_t *response; @@ -214,13 +218,13 @@ int register_response(sip_t *request, int flag) { /* ok -> 200, fail -> 503 */ switch (flag) { - case 0: + case STS_SUCCESS: code = 200; /* OK */ break; - case 1: + case STS_FAILURE: code = 503; /* failed */ break; - case 2: + case STS_NEED_AUTH: code = 407; /* proxy authentication needed */ break; default: @@ -231,7 +235,7 @@ int register_response(sip_t *request, int flag) { /* create the response template */ if ((response=msg_make_template_reply(request, code))==NULL) { ERROR("register_response: error in msg_make_template_reply"); - return 1; + return STS_FAILURE; } /* insert the expiration header */ @@ -250,7 +254,7 @@ int register_response(sip_t *request, int flag) { msg_getvia (response, 0, &via); if (via == NULL) { ERROR("register_response: Cannot send response - no via field"); - return 1; + return STS_FAILURE; } /* name resolution needed? */ @@ -262,7 +266,7 @@ int register_response(sip_t *request, int flag) { sts = msg_2char(response, &buffer); if (sts != 0) { ERROR("register_response: msg_2char failed"); - return 1; + return STS_FAILURE; } /* send answer back */ @@ -278,6 +282,6 @@ int register_response(sip_t *request, int flag) { msg_free(response); free(response); free(buffer); - return 0; + return STS_SUCCESS; } diff --git a/src/rtpproxy.c b/src/rtpproxy.c index 61795e7..efdd576 100644 --- a/src/rtpproxy.c +++ b/src/rtpproxy.c @@ -72,6 +72,9 @@ void sighdl_alm(int sig) {/* do nothing, just wake up from select() */}; /* * initialize and create rtp_proxy thread + * + * RETURNS + * STS_SUCCESS on success */ int rtpproxy_init( void ) { int sts; @@ -101,7 +104,7 @@ int rtpproxy_init( void ) { DEBUGC(DBCLASS_RTP,"detached, sts=%i", sts); #endif - return 0; + return STS_SUCCESS; } /* @@ -197,12 +200,16 @@ DEBUGC(DBCLASS_RTP,"got data on sock=%i",rtp_proxytable[i].sock); -/* +/****** * helper routines to control the RTP proxy thread - */ + ******/ /* * start an rtp stream on the proxy + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int rtp_start_fwd (call_id_t *callid, struct in_addr outbound_ipaddr, int *outboundport, @@ -210,13 +217,13 @@ int rtp_start_fwd (call_id_t *callid, int i, j; int sock, port; int freeidx; - int sts=0; + int sts=STS_SUCCESS; - if (configuration.rtp_proxy_enable == 0) return 0; + if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; if (callid == NULL) { ERROR("rtp_start_fwd: callid is NULL!"); - return 1; + return STS_FAILURE; } DEBUGC(DBCLASS_RTP,"starting RTP proxy stream for: %s@%s", @@ -247,7 +254,7 @@ int rtp_start_fwd (call_id_t *callid, DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i)", rtp_proxytable[j].outboundport); *outboundport=rtp_proxytable[j].outboundport; - sts = 0; + sts = STS_SUCCESS; goto unlock_and_exit; } } @@ -279,7 +286,7 @@ int rtp_start_fwd (call_id_t *callid, DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i)", rtp_proxytable[j].outboundport); *outboundport=rtp_proxytable[j].outboundport; - sts = 0; + sts = STS_SUCCESS; goto unlock_and_exit; } @@ -312,21 +319,21 @@ int rtp_start_fwd (call_id_t *callid, /* found an unused port? No -> RTP port pool fully allocated */ if (port == 0) { ERROR("rtp_start_fwd: no RTP port available. Check rtp_port_* config!"); - sts = 1; + sts = STS_FAILURE; goto unlock_and_exit; } /* could bind to desired port? */ if (sock == 0) { ERROR("rtp_start_fwd: unable to allocate outbound port!"); - sts = 1; + sts = STS_FAILURE; goto unlock_and_exit; } /* rtp_proxytable port pool full? */ if (freeidx == -1) { ERROR("rtp_start_fwd: rtp_proxytable is full!"); - sts = 1; + sts = STS_FAILURE; goto unlock_and_exit; } @@ -362,16 +369,20 @@ unlock_and_exit: /* * stop a rtp stream on the proxy + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int rtp_stop_fwd (call_id_t *callid) { int i; - int sts=0; + int sts=STS_SUCCESS; - if (configuration.rtp_proxy_enable == 0) return 0; + if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; if (callid == NULL) { ERROR("rtp_stop_fwd: callid is NULL!"); - return 1; + return STS_FAILURE; } DEBUGC(DBCLASS_RTP,"stopping RTP proxy stream for: %s@%s", @@ -402,7 +413,7 @@ int rtp_stop_fwd (call_id_t *callid) { if (i>= RTPPROXY_SIZE) { DEBUGC(DBCLASS_RTP,"rtp_stop_fwd: can't find active stream for %s@%s", callid->number, callid->host); - sts = 1; + sts = STS_FAILURE; goto unlock_and_exit; } @@ -432,6 +443,9 @@ unlock_and_exit: /* * some sockets have been newly created or removed - * recreate the FD set for next select operation + * + * RETURNS + * STS_SUCCESS on success (always) */ int rtp_recreate_fdset(void) { int i; @@ -446,6 +460,6 @@ int rtp_recreate_fdset(void) { } } } /* for i */ - return 0; + return STS_SUCCESS; } diff --git a/src/security.c b/src/security.c index 60fa185..18f47c1 100644 --- a/src/security.c +++ b/src/security.c @@ -36,11 +36,12 @@ /* * do security and integrity checks on the received packet * - * returns >0 if ok - * 0 if the packed did not pass the checks + * RETURNS + * STS_SUCCESS if ok + * STS_FAILURE if the packed did not pass the checks */ -int securitycheck(char *sip_buffer, int size){ +int security_check(char *sip_buffer, int size){ /* TODO: still way to go here ... */ - return 1; + return STS_SUCCESS; } diff --git a/src/siproxd.c b/src/siproxd.c index bae1606..196b0e3 100644 --- a/src/siproxd.c +++ b/src/siproxd.c @@ -51,7 +51,7 @@ PACKAGE"-"VERSION"-"BUILDSTR" (c) 2002 Thomas Ries\n" \ "\nUsage: siproxd [options]\n\n" \ "options:\n" \ " --help (-h) help\n" \ -" --debug (-d) set initial debug-pattern\n" \ +" --debug (-d) set debug-pattern\n" \ " --config (-c) use the specified config file\n"\ ""; @@ -71,6 +71,7 @@ int main (int argc, char *argv[]) char configfile[64]="siproxd"; /* basename of configfile */ int config_search=1; /* search the config file */ + int cmdline_debuglevel=0; /* * prepare default configuration @@ -110,8 +111,8 @@ int main (int argc, char *argv[]) case 'd': /* set debug level */ DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg); - configuration.debuglevel=atoi(optarg); - log_set_pattern(configuration.debuglevel); + cmdline_debuglevel=atoi(optarg); + log_set_pattern(cmdline_debuglevel); break; default: @@ -120,13 +121,20 @@ int main (int argc, char *argv[]) } } } - + /* * Init stuff */ - if (read_config(configfile, config_search) != 0) exit(1); - /* if a debug_level statement was in the config file, make sure - the debug pattern is set after reading the config */ + /* 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; + } + + /* set debug level as desired */ log_set_pattern(configuration.debuglevel); /* change user and group IDs */ @@ -140,7 +148,7 @@ int main (int argc, char *argv[]) /* listen for incomming messages */ sts=sipsock_listen(); - if (sts != 0) { + if (sts == STS_FAILURE) { /* failure to allocate SIP socket... */ ERROR("unable to bind to SIP listening socket - aborting"); return 0; @@ -182,13 +190,13 @@ int main (int argc, char *argv[]) i=sipsock_read(&buff, sizeof(buff), &from); - /* evaluate the access lists */ - access=check_accesslist(from); + /* evaluate the access lists (IP based filter)*/ + access=accesslist_check(from); if (access == 0) continue; /* there are no resources to free */ /* integrity checks */ - sts=securitycheck(buff, i); - if (sts == 0) continue; /* there are no resources to free */ + sts=security_check(buff, i); + if (sts != 0) continue; /* there are no resources to free */ /* parse the received message */ sts=msg_init(&my_msg); @@ -214,7 +222,7 @@ int main (int argc, char *argv[]) sts = register_response(my_msg, sts); } else { WARN("non-authorized registration attempt from %s", - inet_ntoa(from.sin_addr)); + inet_ntoa(from.sin_addr)); } /* MSG is a request, add current via entry, diff --git a/src/siproxd.h b/src/siproxd.h index 2735298..c4c6971 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -18,57 +18,57 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - +/* function returns STS_* status values vvv */ /* sock.c */ -int sipsock_listen (void); +int sipsock_listen (void); // * int sipsock_wait(void); int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from); -int sipsock_send_udp(int *sock, struct in_addr addr, int port, +int sipsock_send_udp(int *sock, struct in_addr addr, int port, // * char *buffer, int size, int allowdump); int sockbind(struct in_addr ipaddr, int localport); /* register.c */ void register_init(void); -int register_client(sip_t *request); +int register_client(sip_t *request); // * void register_agemap(void); -int register_response(sip_t *request, int flag); +int register_response(sip_t *request, int flag); // * /* proxy.c */ -int proxy_request (sip_t *request); -int proxy_response (sip_t *response); -int proxy_gen_response(sip_t *request, int code); -int proxy_add_myvia (sip_t *request, int interface); -int proxy_del_myvia (sip_t *response); -int proxy_rewrite_invitation_body(sip_t *mymsg); +int proxy_request (sip_t *request); // * +int proxy_response (sip_t *response); // * +int proxy_gen_response(sip_t *request, int code); // * +int proxy_add_myvia (sip_t *request, int interface); // * +int proxy_del_myvia (sip_t *response); // * +int proxy_rewrite_invitation_body(sip_t *mymsg); // * /* utils.c */ sip_t * msg_make_template_reply (sip_t * request, int code); -int check_vialoop (sip_t *my_msg); -int is_via_local (via_t *via); -int get_ip_by_host(char *hostname, struct in_addr *addr); -int compare_url(url_t *url1, url_t *url2); +int check_vialoop (sip_t *my_msg); // * +int is_via_local (via_t *via); // * +int get_ip_by_host(char *hostname, struct in_addr *addr); // * +int compare_url(url_t *url1, url_t *url2); // * void secure_enviroment (void); /* readconf.c */ -int read_config(char *name, int search); +int read_config(char *name, int search); // * /* rtpproxy.c */ -int rtpproxy_init( void ); -int rtp_start_fwd (call_id_t *callid, +int rtpproxy_init( void ); // * +int rtp_start_fwd (call_id_t *callid, // * struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport); -int rtp_stop_fwd (call_id_t *callid); +int rtp_stop_fwd (call_id_t *callid); // * /* accessctl.c */ -int check_accesslist (struct sockaddr_in from); +int accesslist_check(struct sockaddr_in from); /* security.c */ -int securitycheck(char *sip_buffer, int size); +int security_check(char *sip_buffer, int size); // * /* auth.c */ -int authenticate_proxy(sip_t *request); -int auth_include_authrq(sip_t *response); +int authenticate_proxy(sip_t *request); // * +int auth_include_authrq(sip_t *response); // * @@ -104,6 +104,7 @@ struct siproxd_config { char *hosts_deny_sip; char *proxy_auth_realm; char *proxy_auth_passwd; + char *proxy_auth_pwfile; }; @@ -122,11 +123,20 @@ struct siproxd_config { #define DNS_CACHE_SIZE 32 // number of entries in internal DNS cache #define DNS_MAX_AGE 60 // maximum age of an cache entry (sec) #define HOSTNAME_SIZE 32 // max string length of a hostname +#define USERNAME_SIZE 32 // max string length of a username (auth) +#define PASSWORD_SIZE 32 // max string length of a password (auth) #define ACCESSCTL_SIP 1 // for access control - SIP allowed #define ACCESSCTL_REG 2 // --"-- - registrations allowed +/* symbolic return status */ + +#define STS_SUCCESS 0 // SUCCESS +#define STS_TRUE 0 // TRUE +#define STS_FAILURE 1 // FAILURE +#define STS_FALSE 1 // FALSE +#define STS_NEED_AUTH 1001 // need authentication /* * optional hacks diff --git a/src/sock.c b/src/sock.c index 189358b..3ac0350 100644 --- a/src/sock.c +++ b/src/sock.c @@ -49,20 +49,27 @@ static int listen_socket=0; /* * binds to SIP UDP socket for listening to incomming packets * - * returns 0 on success + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int sipsock_listen (void) { struct in_addr ipaddr; memset(&ipaddr, 0, sizeof(struct in_addr)); listen_socket=sockbind(ipaddr, configuration.sip_listen_port); - if (listen_socket==0) return 1; /* failure*/ + if (listen_socket==0) return STS_FAILURE; /* failure*/ DEBUGC(DBCLASS_NET,"bound listen socket %i",listen_socket); - return 0; + return STS_SUCCESS; } - +/* + * Wait for incomming SIP message. After a 5 sec timeout + * this function returns with sts=0 + * + * RETURNS >0 if data received, =0 if nothing received /T/O), -1 on error + */ int sipsock_wait(void) { int sts; fd_set fdset; @@ -78,6 +85,12 @@ int sipsock_wait(void) { return sts; } +/* + * read a message from SIP listen socket (UDP datagram) + * + * RETURNS number of bytes read + * from is modified to return the sockaddr_in of the sender + */ int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from) { int count; socklen_t fromlen; @@ -94,6 +107,10 @@ int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from) { /* * sends an UDP datagram to the specified destination + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error */ int sipsock_send_udp(int *sock, struct in_addr addr, int port, char *buffer, int size, int allowdump) { @@ -105,7 +122,7 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, *sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sock == 0) { ERROR("socket() call failed:%s",strerror(errno)); - return 1; + return STS_FAILURE; } DEBUGC(DBCLASS_NET,"allocated send socket %i",*sock); } @@ -126,12 +143,12 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, if (sts == -1) { if (errno != ECONNREFUSED) { ERROR("sendto() call failed:%s",strerror(errno)); - return 1; + return STS_FAILURE; } DEBUGC(DBCLASS_BABBLE,"sendto() call failed:%s",strerror(errno)); } - return 0; + return STS_SUCCESS; } @@ -140,7 +157,7 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, * generic routine to allocate and bind a socket to a specified * local address and port (UDP) * - * returns socket number on success, zero on failure + * RETURNS socket number on success, zero on failure */ int sockbind(struct in_addr ipaddr, int localport) { struct sockaddr_in my_addr; diff --git a/src/utils.c b/src/utils.c index 930d325..d9535a9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -48,6 +48,8 @@ extern int h_errno; /* * create a reply template from an given SIP request + * + * RETURNS a pointer to sip_t */ sip_t *msg_make_template_reply (sip_t * request, int code) { sip_t *response; @@ -88,6 +90,10 @@ sip_t *msg_make_template_reply (sip_t * request, int code) { * check for a via loop. * It checks for the presense of a via entry that holds one of * my IP addresses and is *not* the topmost via. + * + * RETURNS + * STS_TRUE if loop detected + * STS_FALSE if no loop */ int check_vialoop (sip_t *my_msg) { int sts; @@ -104,13 +110,17 @@ int check_vialoop (sip_t *my_msg) { if (sts == 1) found_own_via=1; pos++; } - return found_own_via; + return (found_own_via)? STS_TRUE : STS_FALSE; } /* * check if a given via_t is local. I.e. its address is owned * by my inbound or outbound interface + * + * RETURNS + * STS_TRUE if the given VIA is one of my interfaces + * STS_FALSE otherwise */ int is_via_local (via_t *via) { int sts; @@ -146,13 +156,17 @@ int is_via_local (via_t *via) { } } - return sts; + return (sts)? STS_TRUE : STS_FALSE; } /* * resolve a hostname and return in_addr * handles its own little DNS cache. + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on failure */ int get_ip_by_host(char *hostname, struct in_addr *addr) { int i, j; @@ -165,7 +179,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { } dns_cache[DNS_CACHE_SIZE]; static int cache_initialized=0; - if (hostname == NULL) return 1; + if (hostname == NULL) return STS_FAILURE; /* first time: initialize DNS cache */ if (cache_initialized == 0) { @@ -193,7 +207,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { memcpy(addr, &dns_cache[i].addr, sizeof(struct in_addr)); DEBUGC(DBCLASS_DNS, "DNS lookup - from cache: %s -> %s", hostname, inet_ntoa(*addr)); - return 0; + return STS_SUCCESS; } } @@ -202,7 +216,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { if (hostentry==NULL) { ERROR("gethostbyname(%s) failed: %s",hostname,hstrerror(h_errno)); - return 1; + return STS_FAILURE; } memcpy(addr, hostentry->h_addr, sizeof(struct in_addr)); @@ -232,27 +246,30 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { time(&dns_cache[i].timestamp); memcpy(&dns_cache[i].addr, addr, sizeof(struct in_addr)); - return 0; + return STS_SUCCESS; } /* * compares two URLs - * returns 0 if equal, <0 if non equal, >0 if error * (by now, only hostname and username are compared) + * + * RETURNS + * STS_SUCCESS if equal + * STS_FAILURE if non equal or error */ int compare_url(url_t *url1, url_t *url2) { int sts; - if ((url1 == NULL) || (url2 == NULL)) return 1; + if ((url1 == NULL) || (url2 == NULL)) return STS_FAILURE; /* comparison of hosts should be based on IP addresses, no? */ DEBUGC(DBCLASS_BABBLE, "comparng urls: %s@%s -> %s@%s", url1->username, url1->host, url2->username, url2->host); if ((strcmp(url1->username, url2->username)==0) && (strcmp(url1->host, url2->host)==0)) { - sts = 0; + sts = STS_SUCCESS; } else { - sts = -1; + sts = STS_FAILURE; } return sts; @@ -261,7 +278,8 @@ int compare_url(url_t *url1, url_t *url2) { /* * Secure enviroment: - * If running as root,change UID/GID to user as requested in config + * If running as root, put myself into a chroot jail and + * change UID/GID to user as requested in config file */ void secure_enviroment (void) { int sts;