From 5d52864609b3750bfeb7cda411802900aa190fc3 Mon Sep 17 00:00:00 2001 From: David Troy Date: Sat, 1 Jul 2006 15:43:37 +0000 Subject: Cleanup 1.21pre into 1.21 (release) git-svn-id: http://svncommunity.digium.com/svn/astmanproxy/trunk@129 f02b47b9-160a-0410-81a6-dc3441afb0ec --- Makefile | 2 +- README | 54 +- TODO | 2 - VERSIONS | 4 +- src/astmanproxy.c | 1231 +++++++++++++++++++++++---------------------- src/common.c | 201 ++++---- src/config.c | 544 ++++++++++---------- src/config_perms.c | 198 ++++---- src/csv.c | 39 +- src/http.c | 397 +++++++-------- src/include/astmanproxy.h | 146 +++--- src/log.c | 92 ++-- src/poll.c | 76 +-- src/proxyfunc.c | 622 ++++++++++++----------- src/ssl.c | 272 +++++----- src/standard.c | 92 ++-- src/xml.c | 235 ++++----- 17 files changed, 2144 insertions(+), 2063 deletions(-) diff --git a/Makefile b/Makefile index df71864..7d19bfb 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ OSARCH=$(shell uname -s) OSREV=$(shell uname -r) -VERSION := 1.21pre +VERSION := 1.21 DESTDIR ?= CONFDIR:=/etc/asterisk CONFDIR_REAL := $(DESTDIR)/etc/asterisk diff --git a/README b/README index 719f784..b090332 100644 --- a/README +++ b/README @@ -24,9 +24,6 @@ Features include: - I/O Formats selectable on a per-client basis - Written in c/pthreads to be fast and robust -For example, you can use Astmanproxy as a single point of contact to -communicate with multiple Asterisk servers. - You can use Astmanproxy as the basis for a web-based application: send it data using HTTP POST or HTTP GET, and receive XML output. Or use HTTP POST and get Standard (text/plain) output back! @@ -98,6 +95,7 @@ OutputFormat: (standard|xml) ProxyAction: SetAutoFilter AutoFilter: (on|off) Sets the AutoFilter property on a per-client basis + (See autofiltering section below) ProxyAction: Logoff Logs client out of Proxy and leaves Asterisk alone. @@ -164,6 +162,52 @@ Blank Commands and load off of Asterisk. The proxy intercepts and ignores blank command blocks. +=================================================================== +AstManProxy Autofiltering Functionality + +One of the most powerful features of AstManProxy is its ability to +automatically filter output on a per-client basis. It can do this +with its Autofilter capability, which can be set 'on' in the config +file or enabled via the ProxyAction: SetAutoFilter function. + +With autofiltering enabled, each client only receives output containing +the "ActionID" parameter it has set most recently. This is useful +for single atomic requests into asterisk from a client, such as +when creating a simple UI to inject a command. + +For example, if a client sends this packet while autofiltering is +enabled: + +Action: Ping +ActionID: foo + +Then the autofilter ActionID for that client is set to foo, and no +output besides for responses containing "foo" will be returned +to that client, such as: + +Response: Pong +ActionID: foo + +Replace Ping with Originate and Pong with Success and you can see +how this same mechanism can be used to quickly query asterisk +box(es), initiate calls, etc, without your client having to worry +with filtering a lot of unrelated output. + +=================================================================== +On the astmanproxy.users output filtering functionality + +Users may now be defined in your astmanproxy.users configuration file. +This enables a traditional user/password based login mechanism +for Astmanproxy similar to what is found in Asterisk. Output may be +filtered on a per-user basis. + +"user" is the username, secret is the password, and the (optional) +channel setting causes filtering of events only for the specified +channel to be sent to this user. + +; user=secret,channel,out_context (to Asterisk),in_context (From Asterisk) +; steve=steve,SIP/snom190,local, + =================================================================== On the 'Action: Challenge' Authentication Mechanism @@ -280,7 +324,7 @@ Be sure to use the full URL path to the version you wish to check out; for example, do not checkout the 'branches' tree, but instead choose which branch to checkout, as in: -http://svncommunity.digium.com/view/astmanproxy/branches/1.2x +http://svncommunity.digium.com/svn/astmanproxy/branches/1.2x I will also try to post current tarballs here: http://www.popvox.com/astmanproxy @@ -342,4 +386,4 @@ and output format -- implemented as abstracted I/O handlers -- and these are configurable on a per-client basis. =================================================================== -(C) 2005 David C. Troy, dave@popvox.com +(C) 2005-2006 David C. Troy, dave@popvox.com diff --git a/TODO b/TODO index d819428..839aa55 100644 --- a/TODO +++ b/TODO @@ -5,9 +5,7 @@ clean up debugmsg instances to add if (debug) deal with http non-conformity better, and act on POST MIME-type inputs Check for module versions; do not run without modules installed - use a key? see loader.c in * State maintenance modules -code formatting tcpwrappers/access control/connect mask? libtool/autoconf/automake support SetInputFormat proxyaction? diff --git a/VERSIONS b/VERSIONS index 973a86d..1939e79 100644 --- a/VERSIONS +++ b/VERSIONS @@ -1,7 +1,9 @@ +1.21 Major code formatting cleanup and official release of 1.21pre (trunk) + 1.21pre Added URLDecode routine to http.c to deal with URL-encoded GET/POST data Fixed xml.c to better deal with cli/unparsed data Cleaned up Makefile for better support of Mac OS X 10.4 - Changed message to dynamically allocated in HandleAsterisk, solving bus error on Mac OS X 10.4 + Changed message to be dynamically allocated in HandleAsterisk; solved bus error on Mac OS X 10.4 1.20 Cleanup and official release of 1.20pre diff --git a/src/astmanproxy.c b/src/astmanproxy.c index bb17935..1b6421b 100644 --- a/src/astmanproxy.c +++ b/src/astmanproxy.c @@ -1,9 +1,12 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005-2006 David C. Troy - - This program is free software, distributed under the terms of - the GNU General Public License. - +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + astmanproxy.c + contains the proxy server core, initialization, thread launching, + loops, and exit routines */ #include "astmanproxy.h" @@ -35,683 +38,683 @@ FILE *proxylog; int debug = 0; void hup(int sig) { - if (proxylog) { - fflush(proxylog); - fclose(proxylog); - } - proxylog = OpenLogfile(); - logmsg("Received HUP -- reopened log"); - ReadPerms(); - logmsg("Received HUP -- reread permissions"); + if (proxylog) { + fflush(proxylog); + fclose(proxylog); + } + proxylog = OpenLogfile(); + logmsg("Received HUP -- reopened log"); + ReadPerms(); + logmsg("Received HUP -- reread permissions"); } void leave(int sig) { - struct mansession *c; - struct message sm, cm; - struct iohandler *io; - struct ast_server *srv; - char iabuf[INET_ADDRSTRLEN]; - - /* Message to send to servers */ - memset(&sm, 0, sizeof(struct message)); - AddHeader(&sm, "Action: Logoff"); - - /* Message to send to clients */ - memset(&cm, 0, sizeof(struct message)); - AddHeader(&cm, PROXY_SHUTDOWN); - - if (debug) - debugmsg("Notifying and closing sessions"); - pthread_mutex_lock (&sessionlock); - while (sessions) { - c = sessions; - sessions = sessions->next; - - if (c->server) { - if (debug) - debugmsg("asterisk@%s: closing session", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); - c->output->write(c, &sm); - logmsg("Shutdown, closed server %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); - } else { - if (debug) - debugmsg("client@%s: closing session", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); - c->output->write(c, &cm); - logmsg("Shutdown, closed client %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); - } - close_sock(c->fd); /* close tcp & ssl socket */ - pthread_mutex_destroy(&c->lock); - free(c); - } - pthread_mutex_unlock (&sessionlock); - - /* unload server list */ - while (pc.serverlist) { - srv = pc.serverlist; - pc.serverlist = srv->next; - if (debug) - debugmsg("asterisk@%s: forgetting", srv->ast_host); - free(srv); - } - - if (debug) - debugmsg("Closing listener socket"); - close_sock(asock); /* close tcp & ssl socket */ - - /* unload io handlers */ - while (iohandlers) { - io = iohandlers; - iohandlers = iohandlers->next; - if (debug) - debugmsg("unloading: %s", io->formatname); - dlclose(io->dlhandle); - free(io); - } - - if(debug) - debugmsg("Done!\n"); - logmsg("Proxy stopped; shutting down."); - - fclose(proxylog); - pthread_mutex_destroy(&sessionlock); - pthread_mutex_destroy(&loglock); - pthread_mutex_destroy(&debuglock); - exit(sig); + struct mansession *c; + struct message sm, cm; + struct iohandler *io; + struct ast_server *srv; + char iabuf[INET_ADDRSTRLEN]; + + /* Message to send to servers */ + memset(&sm, 0, sizeof(struct message)); + AddHeader(&sm, "Action: Logoff"); + + /* Message to send to clients */ + memset(&cm, 0, sizeof(struct message)); + AddHeader(&cm, PROXY_SHUTDOWN); + + if (debug) + debugmsg("Notifying and closing sessions"); + pthread_mutex_lock (&sessionlock); + while (sessions) { + c = sessions; + sessions = sessions->next; + + if (c->server) { + if (debug) + debugmsg("asterisk@%s: closing session", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); + c->output->write(c, &sm); + logmsg("Shutdown, closed server %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); + } else { + if (debug) + debugmsg("client@%s: closing session", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); + c->output->write(c, &cm); + logmsg("Shutdown, closed client %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); + } + close_sock(c->fd); /* close tcp & ssl socket */ + pthread_mutex_destroy(&c->lock); + free(c); + } + pthread_mutex_unlock (&sessionlock); + + /* unload server list */ + while (pc.serverlist) { + srv = pc.serverlist; + pc.serverlist = srv->next; + if (debug) + debugmsg("asterisk@%s: forgetting", srv->ast_host); + free(srv); + } + + if (debug) + debugmsg("Closing listener socket"); + close_sock(asock); /* close tcp & ssl socket */ + + /* unload io handlers */ + while (iohandlers) { + io = iohandlers; + iohandlers = iohandlers->next; + if (debug) + debugmsg("unloading: %s", io->formatname); + dlclose(io->dlhandle); + free(io); + } + + if(debug) + debugmsg("Done!\n"); + logmsg("Proxy stopped; shutting down."); + + fclose(proxylog); + pthread_mutex_destroy(&sessionlock); + pthread_mutex_destroy(&loglock); + pthread_mutex_destroy(&debuglock); + exit(sig); } void Version( void ) { - printf("astmanproxy: Version %s, (C) David C. Troy 2005-2006\n", PROXY_VERSION); - return; + printf("astmanproxy: Version %s, (C) David C. Troy 2005-2006\n", PROXY_VERSION); + return; } void Usage( void ) { - printf("Usage: astmanproxy [-d|-h|-v]\n"); - printf(" -d : Start in Debug Mode\n"); - printf(" -h : Displays this message\n"); - printf(" -v : Displays version information\n"); - printf("Start with no options to run as daemon\n"); - return; + printf("Usage: astmanproxy [-d|-h|-v]\n"); + printf(" -d : Start in Debug Mode\n"); + printf(" -h : Displays this message\n"); + printf(" -v : Displays version information\n"); + printf("Start with no options to run as daemon\n"); + return; } void destroy_session(struct mansession *s) { - struct mansession *cur, *prev = NULL; - char iabuf[INET_ADDRSTRLEN]; - - pthread_mutex_lock(&sessionlock); - cur = sessions; - while(cur) { - if (cur == s) - break; - prev = cur; - cur = cur->next; - } - if (cur) { - if (prev) - prev->next = cur->next; - else - sessions = cur->next; - debugmsg("Connection closed: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - close_sock(s->fd); /* close tcp/ssl socket */ - pthread_mutex_destroy(&s->lock); - free(s); - } else - debugmsg("Trying to delete non-existent session %p?\n", s); - pthread_mutex_unlock(&sessionlock); - - /* If there are no servers and no clients, why are we here? */ - if (!sessions) { - logmsg("Cannot connect to any servers! Leaving!"); - leave(0); - } + struct mansession *cur, *prev = NULL; + char iabuf[INET_ADDRSTRLEN]; + + pthread_mutex_lock(&sessionlock); + cur = sessions; + while(cur) { + if (cur == s) + break; + prev = cur; + cur = cur->next; + } + if (cur) { + if (prev) + prev->next = cur->next; + else + sessions = cur->next; + debugmsg("Connection closed: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + close_sock(s->fd); /* close tcp/ssl socket */ + pthread_mutex_destroy(&s->lock); + free(s); + } else if (debug) + debugmsg("Trying to delete non-existent session %p?\n", s); + pthread_mutex_unlock(&sessionlock); + + /* If there are no servers and no clients, why are we here? */ + if (!sessions) { + logmsg("Cannot connect to any servers! Leaving!"); + leave(0); + } } int WriteClients(struct message *m) { - struct mansession *c; - char *actionid; - - c = sessions; - while (c) { - if ( !c->server && m->hdrcount>1 && ValidateAction(m, c, 1) ) { - if (c->autofilter && c->actionid) { - actionid = astman_get_header(m, ACTION_ID); - if ( !strcmp(actionid, c->actionid) ) { - c->output->write(c, m); - } - } else - c->output->write(c, m); - if (c->inputcomplete) { - pthread_mutex_lock(&c->lock); - c->outputcomplete = 1; - pthread_mutex_unlock(&c->lock); - } - } - c = c->next; - } - return 1; + struct mansession *c; + char *actionid; + + c = sessions; + while (c) { + if ( !c->server && m->hdrcount>1 && ValidateAction(m, c, 1) ) { + if (c->autofilter && c->actionid) { + actionid = astman_get_header(m, ACTION_ID); + if ( !strcmp(actionid, c->actionid) ) + c->output->write(c, m); + } else + c->output->write(c, m); + + if (c->inputcomplete) { + pthread_mutex_lock(&c->lock); + c->outputcomplete = 1; + pthread_mutex_unlock(&c->lock); + } + } + c = c->next; + } + return 1; } int WriteAsterisk(struct message *m) { - int i; - char outstring[MAX_LEN], *dest; - struct mansession *s, *first; - - first = NULL; - dest = NULL; - - s = sessions; - - dest = astman_get_header(m, "Server"); - if (debug && *dest) debugmsg("set destination: %s", dest); - while ( s ) { - if ( s->server && (s->connected > 0) ) { - if ( !first ) - first = s; - if (*dest && !strcasecmp(dest, s->server->ast_host) ) - break; - } - s = s->next; - } - - if (!s) - s = first; - - /* Check for no servers and empty block -- Don't pester Asterisk if it is one*/ - if (!s || !s->server || (!m->hdrcount && !m->headers[0][0]) ) - return 1; - - debugmsg("writing block to %s", s->server->ast_host); - - pthread_mutex_lock(&s->lock); - for (i=0; ihdrcount; i++) { - if (strcasecmp(m->headers[i], "Server:") ) { - sprintf(outstring, "%s\r\n", m->headers[i]); - ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout ); - } - } - ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); - pthread_mutex_unlock(&s->lock); - return 1; + int i; + char outstring[MAX_LEN], *dest; + struct mansession *s, *first; + + first = NULL; + dest = NULL; + + s = sessions; + + dest = astman_get_header(m, "Server"); + if (debug && *dest) debugmsg("set destination: %s", dest); + while ( s ) { + if ( s->server && (s->connected > 0) ) { + if ( !first ) + first = s; + if (*dest && !strcasecmp(dest, s->server->ast_host) ) + break; + } + s = s->next; + } + + if (!s) + s = first; + + /* Check for no servers and empty block -- Don't pester Asterisk if it is one*/ + if (!s || !s->server || (!m->hdrcount && !m->headers[0][0]) ) + return 1; + + debugmsg("writing block to %s", s->server->ast_host); + + pthread_mutex_lock(&s->lock); + for (i=0; ihdrcount; i++) { + if (strcasecmp(m->headers[i], "Server:") ) { + sprintf(outstring, "%s\r\n", m->headers[i]); + ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout ); + } + } + ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); + pthread_mutex_unlock(&s->lock); + return 1; } void *setactionid(char *actionid, struct message *m, struct mansession *s) { - pthread_mutex_lock(&s->lock); - strncpy(s->actionid, actionid, MAX_LEN); - pthread_mutex_unlock(&s->lock); + pthread_mutex_lock(&s->lock); + strncpy(s->actionid, actionid, MAX_LEN); + pthread_mutex_unlock(&s->lock); - return 0; + return 0; } /* Handles proxy client sessions; closely based on session_do from asterisk's manager.c */ void *session_do(struct mansession *s) { - struct message m; - int res; - char *proxyaction, *actionid, *action, *key; - - if (s->input->onconnect) - s->input->onconnect(s, &m); - - for (;;) { - /* Get a complete message block from input handler */ - memset(&m, 0, sizeof(struct message) ); - if (debug > 3) - debugmsg("calling %s_read...", s->input->formatname); - res = s->input->read(s, &m); - if (debug > 3) - debugmsg("%s_read result = %d", s->input->formatname, res); - m.session = s; - - if (res > 0) { - /* Check for anything that requires proxy-side processing */ - if (pc.key[0] != '\0' && !s->authenticated) { - key = astman_get_header(&m, "ProxyKey"); - if (!strcmp(key, pc.key) ) { - pthread_mutex_lock(&s->lock); - s->authenticated = 1; - pthread_mutex_unlock(&s->lock); - } else - break; - } - - proxyaction = astman_get_header(&m, "ProxyAction"); - actionid = astman_get_header(&m, ACTION_ID); - action = astman_get_header(&m, "Action"); - if ( !strcasecmp(action, "Login") ) - if (!s->authenticated) - ProxyLogin(s, &m); - else + struct message m; + int res; + char *proxyaction, *actionid, *action, *key; + + if (s->input->onconnect) + s->input->onconnect(s, &m); + + for (;;) { + /* Get a complete message block from input handler */ + memset(&m, 0, sizeof(struct message) ); + if (debug > 3) + debugmsg("calling %s_read...", s->input->formatname); + res = s->input->read(s, &m); + if (debug > 3) + debugmsg("%s_read result = %d", s->input->formatname, res); + m.session = s; + + if (res > 0) { + /* Check for anything that requires proxy-side processing */ + if (pc.key[0] != '\0' && !s->authenticated) { + key = astman_get_header(&m, "ProxyKey"); + if (!strcmp(key, pc.key) ) { + pthread_mutex_lock(&s->lock); + s->authenticated = 1; + pthread_mutex_unlock(&s->lock); + } else + break; + } + + proxyaction = astman_get_header(&m, "ProxyAction"); + actionid = astman_get_header(&m, ACTION_ID); + action = astman_get_header(&m, "Action"); + if ( !strcasecmp(action, "Login") ) + if (!s->authenticated) + ProxyLogin(s, &m); + else + break; + else if ( !strcasecmp(action, "Logoff") ) + ProxyLogoff(s); + else if ( !strcasecmp(action, "Challenge") ) + ProxyChallenge(s, &m); + else if ( !(*proxyaction == '\0') ) + proxyaction_do(proxyaction, &m, s); + else if ( ValidateAction(&m, s, 0) ) { + if ( !(*actionid == '\0') ) + setactionid(actionid, &m, s); + if ( !WriteAsterisk(&m) ) + break; + } else { + SendError(s, "Action Filtered"); + } + } else if (res < 0) break; - else if ( !strcasecmp(action, "Logoff") ) - ProxyLogoff(s); - else if ( !strcasecmp(action, "Challenge") ) - ProxyChallenge(s, &m); - else if ( !(*proxyaction == '\0') ) - proxyaction_do(proxyaction, &m, s); - else if ( ValidateAction(&m, s, 0) ) { - if ( !(*actionid == '\0') ) - setactionid(actionid, &m, s); - if ( !WriteAsterisk(&m) ) - break; - } else { - SendError(s, "Action Filtered"); - } - } else if (res < 0) - break; - } - - destroy_session(s); - if (debug) - debugmsg("--- exiting session_do thread ---"); - pthread_exit(NULL); - return NULL; + } + + destroy_session(s); + if (debug) + debugmsg("--- exiting session_do thread ---"); + pthread_exit(NULL); + return NULL; } void *HandleAsterisk(struct mansession *s) { - struct message *m; - int res,i; - char iabuf[INET_ADDRSTRLEN]; - - if (ConnectAsterisk(s)) - goto leave; - if (! (m = malloc(sizeof(struct message))) ) - goto leave; - - for (;;) { - - debugmsg("asterisk@%s: attempting read...", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - memset(&m, 0, sizeof(struct message) ); - res = s->input->read(s, m); - m->session = s; - - if (res > 0) { - if (debug) { - for(i=0; ihdrcount; i++) { - debugmsg("asterisk@%s got: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), m->headers[i]); - } - } - - if (!s->connected) { - if ( !strcmp("Authentication accepted", astman_get_header(m, "Message")) ) { - s->connected = 1; - if (debug) - debugmsg("asterisk@%s: connected successfully!", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr) ); - } - if ( !strcmp("Authentication failed", astman_get_header(m, "Message")) ) { - s->connected = -1; - } - } - - m->session = s; - AddHeader(m, "Server: %s", m->session->server->ast_host); - - if (!WriteClients(m)) - break; - } else if (res < 0) { - /* TODO: do we need to do more than this here? or something different? */ - if ( debug ) - debugmsg("asterisk@%s: Not connected", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - if ( ConnectAsterisk(s) ) - break; - } - } - free(m); + struct message *m; + int res,i; + char iabuf[INET_ADDRSTRLEN]; + + if (ConnectAsterisk(s)) + goto leave; + if (! (m = malloc(sizeof(struct message))) ) + goto leave; + + for (;;) { + if (debug) + debugmsg("asterisk@%s: attempting read...", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + memset(&m, 0, sizeof(struct message) ); + res = s->input->read(s, m); + m->session = s; + + if (res > 0) { + if (debug) { + for(i=0; ihdrcount; i++) { + debugmsg("asterisk@%s got: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), m->headers[i]); + } + } + + if (!s->connected) { + if ( !strcmp("Authentication accepted", astman_get_header(m, "Message")) ) { + s->connected = 1; + if (debug) + debugmsg("asterisk@%s: connected successfully!", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr) ); + } + if ( !strcmp("Authentication failed", astman_get_header(m, "Message")) ) { + s->connected = -1; + } + } + + m->session = s; + AddHeader(m, "Server: %s", m->session->server->ast_host); + + if (!WriteClients(m)) + break; + } else if (res < 0) { + /* TODO: do we need to do more than this here? or something different? */ + if ( debug ) + debugmsg("asterisk@%s: Not connected", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + if ( ConnectAsterisk(s) ) + break; + } + } + free(m); leave: - if (debug) - debugmsg("asterisk@%s: Giving up and exiting thread", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr) ); - destroy_session(s); - pthread_exit(NULL); - return NULL; + if (debug) + debugmsg("asterisk@%s: Giving up and exiting thread", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr) ); + destroy_session(s); + pthread_exit(NULL); + return NULL; } int ConnectAsterisk(struct mansession *s) { - char iabuf[INET_ADDRSTRLEN]; - int r = 1, res = 0; - struct message m; - - /* Don't try to do this if auth has already failed! */ - if (s->connected < 0 ) - return 1; - else - s->connected = 0; - - if (debug) - debugmsg("asterisk@%s: Connecting (u=%s, p=%s, ssl=%s)", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), - s->server->ast_user, s->server->ast_pass, s->server->use_ssl ? "on" : "off"); - - /* Construct auth message just once */ - memset( &m, 0, sizeof(struct message) ); - AddHeader(&m, "Action: Login"); - AddHeader(&m, "Username: %s", s->server->ast_user); - AddHeader(&m, "Secret: %s", s->server->ast_pass); - AddHeader(&m, "Events: %s", s->server->ast_events); - - for ( ;; ) { - if ( ast_connect(s) == -1 ) { - if (debug) - debugmsg("asterisk@%s: Connect failed, Retrying (%d) %s [%d]", - ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), r, strerror(errno), errno ); - if (pc.maxretries && (++r>pc.maxretries) ) { - res = 1; - break; - } else - sleep(pc.retryinterval); - } else { - /* Send login */ - s->output->write(s, &m); - res = 0; - break; - } - } - - return res; + char iabuf[INET_ADDRSTRLEN]; + int r = 1, res = 0; + struct message m; + + /* Don't try to do this if auth has already failed! */ + if (s->connected < 0 ) + return 1; + else + s->connected = 0; + + if (debug) + debugmsg("asterisk@%s: Connecting (u=%s, p=%s, ssl=%s)", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), + s->server->ast_user, s->server->ast_pass, s->server->use_ssl ? "on" : "off"); + + /* Construct auth message just once */ + memset( &m, 0, sizeof(struct message) ); + AddHeader(&m, "Action: Login"); + AddHeader(&m, "Username: %s", s->server->ast_user); + AddHeader(&m, "Secret: %s", s->server->ast_pass); + AddHeader(&m, "Events: %s", s->server->ast_events); + + for ( ;; ) { + if ( ast_connect(s) == -1 ) { + if (debug) + debugmsg("asterisk@%s: Connect failed, Retrying (%d) %s [%d]", + ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), r, strerror(errno), errno ); + if (pc.maxretries && (++r>pc.maxretries) ) { + res = 1; + break; + } else + sleep(pc.retryinterval); + } else { + /* Send login */ + s->output->write(s, &m); + res = 0; + break; + } + } + + return res; } int StartServer(struct ast_server *srv) { - struct mansession *s; - struct hostent *ast_hostent; - - char iabuf[INET_ADDRSTRLEN]; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - ast_hostent = gethostbyname(srv->ast_host); - if (!ast_hostent) { - logmsg("Cannot resolve host %s, cannot add!", srv->ast_host); - debugmsg("Cannot resolve host %s, cannot add!", srv->ast_host); - return 1; - } - - s = malloc(sizeof(struct mansession)); - if ( !s ) { - logmsg("Failed to allocate server session: %s\n", strerror(errno)); - debugmsg("Failed to allocate server session: %s\n", strerror(errno)); - return 1; - } - - memset(s, 0, sizeof(struct mansession)); - SetIOHandlers(s, "standard", "standard"); - s->server = srv; - - bzero((char *) &s->sin,sizeof(s->sin)); - s->sin.sin_family = AF_INET; - memcpy( &s->sin.sin_addr.s_addr, ast_hostent->h_addr, ast_hostent->h_length ); - s->sin.sin_port = htons(atoi(s->server->ast_port)); - s->fd = socket(AF_INET, SOCK_STREAM, 0); - - pthread_mutex_lock(&sessionlock); - s->next = sessions; - sessions = s; - pthread_mutex_unlock(&sessionlock); - - logmsg("Allocated Asterisk server session for %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - if (debug) { - debugmsg("asterisk@%s: Allocated server session", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - debugmsg("Set %s input format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->input->formatname); - debugmsg("Set %s output format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->output->formatname); - } - - if (pthread_create(&s->t, &attr, (void *)HandleAsterisk, s)) - destroy_session(s); - else - debugmsg("launched ast %s thread!", s->server->ast_host); - - pthread_attr_destroy(&attr); - return 0; + struct mansession *s; + struct hostent *ast_hostent; + + char iabuf[INET_ADDRSTRLEN]; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + ast_hostent = gethostbyname(srv->ast_host); + if (!ast_hostent) { + logmsg("Cannot resolve host %s, cannot add!", srv->ast_host); + debugmsg("Cannot resolve host %s, cannot add!", srv->ast_host); + return 1; + } + + s = malloc(sizeof(struct mansession)); + if ( !s ) { + logmsg("Failed to allocate server session: %s\n", strerror(errno)); + debugmsg("Failed to allocate server session: %s\n", strerror(errno)); + return 1; + } + + memset(s, 0, sizeof(struct mansession)); + SetIOHandlers(s, "standard", "standard"); + s->server = srv; + + bzero((char *) &s->sin,sizeof(s->sin)); + s->sin.sin_family = AF_INET; + memcpy( &s->sin.sin_addr.s_addr, ast_hostent->h_addr, ast_hostent->h_length ); + s->sin.sin_port = htons(atoi(s->server->ast_port)); + s->fd = socket(AF_INET, SOCK_STREAM, 0); + + pthread_mutex_lock(&sessionlock); + s->next = sessions; + sessions = s; + pthread_mutex_unlock(&sessionlock); + + logmsg("Allocated Asterisk server session for %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + if (debug) { + debugmsg("asterisk@%s: Allocated server session", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + debugmsg("Set %s input format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->input->formatname); + debugmsg("Set %s output format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->output->formatname); + } + + if (pthread_create(&s->t, &attr, (void *)HandleAsterisk, s)) + destroy_session(s); + else + debugmsg("launched ast %s thread!", s->server->ast_host); + + pthread_attr_destroy(&attr); + return 0; } int LaunchAsteriskThreads() { - struct ast_server *srv; + struct ast_server *srv; - srv = pc.serverlist; - while (srv) { - StartServer(srv); - srv = srv->next; - } - return 0; + srv = pc.serverlist; + while (srv) { + StartServer(srv); + srv = srv->next; + } + return 0; } int SetIOHandlers(struct mansession *s, char *ifmt, char *ofmt) { - int res = 0; - struct iohandler *io; - - io = iohandlers; - pthread_mutex_lock(&s->lock); - while (io) { - if ( !strcasecmp(io->formatname, ifmt) ) - s->input = io; - - if ( !strcasecmp(io->formatname, ofmt) ) - s->output = io; - - io = io->next; - } - - /* set default handlers if non match was found */ - if (!s->output) { - s->output = iohandlers; - res = 1; - } - - if (!s->input) { - s->input = iohandlers; - res = 1; - } - pthread_mutex_unlock(&s->lock); - - return res; + int res = 0; + struct iohandler *io; + + io = iohandlers; + pthread_mutex_lock(&s->lock); + while (io) { + if ( !strcasecmp(io->formatname, ifmt) ) + s->input = io; + + if ( !strcasecmp(io->formatname, ofmt) ) + s->output = io; + + io = io->next; + } + + /* set default handlers if non match was found */ + if (!s->output) { + s->output = iohandlers; + res = 1; + } + + if (!s->input) { + s->input = iohandlers; + res = 1; + } + pthread_mutex_unlock(&s->lock); + + return res; } static void *accept_thread() { - int as; - struct sockaddr_in sin; - socklen_t sinlen; - struct mansession *s; - struct protoent *p; - int arg = 1; - int flags; - pthread_attr_t attr; - char iabuf[INET_ADDRSTRLEN]; - int is_encrypted; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - for (;;) { - sinlen = sizeof(sin); - as = accept(asock, (struct sockaddr *)&sin, &sinlen); - if (as < 0) { - logmsg("Accept returned -1: %s\n", strerror(errno)); - continue; - } - p = (struct protoent *)getprotobyname("tcp"); - if( p ) { - if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { - logmsg("Failed to set listener tcp connection to TCP_NODELAY mode: %s\n", strerror(errno)); - } - } + int as; + struct sockaddr_in sin; + socklen_t sinlen; + struct mansession *s; + struct protoent *p; + int arg = 1; + int flags; + pthread_attr_t attr; + char iabuf[INET_ADDRSTRLEN]; + int is_encrypted; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + for (;;) { + sinlen = sizeof(sin); + as = accept(asock, (struct sockaddr *)&sin, &sinlen); + if (as < 0) { + logmsg("Accept returned -1: %s\n", strerror(errno)); + continue; + } + p = (struct protoent *)getprotobyname("tcp"); + if( p ) { + if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { + logmsg("Failed to set listener tcp connection to TCP_NODELAY mode: %s\n", strerror(errno)); + } + } /* SSL stuff below */ - is_encrypted = is_encrypt_request(pc.sslclhellotimeout, as); + is_encrypted = is_encrypt_request(pc.sslclhellotimeout, as); debugmsg("is_encrypted: %d", is_encrypted); - if (is_encrypted > 0) { - if (!pc.acceptencryptedconnection) { - if( debug ) + if (is_encrypted > 0) { + if (!pc.acceptencryptedconnection) { + if( debug ) debugmsg("Accepting encrypted connection disabled, closing the connection \n"); - close_sock(as); - continue; - } else { - if((as = saccept(as)) >= 0 ) { + close_sock(as); + continue; + } else { + if((as = saccept(as)) >= 0 ) { if( debug ) - debugmsg("Can't accept the ssl connection, since SSL init has failed for certificate reason\n"); - close_sock(as); - continue; - } - } - } else if (is_encrypted == -1) { - logmsg("SSL version 2 is unsecure, we don't support it\n"); - close_sock(as); - continue; - } - if ( (! pc.acceptunencryptedconnection) && (as >= 0)) { - logmsg("Unencrypted connections are not accepted and we received an unencrypted connection request\n"); - close_sock(as); - continue; - } + debugmsg("Can't accept the ssl connection, since SSL init has failed for certificate reason\n"); + close_sock(as); + continue; + } + } + } else if (is_encrypted == -1) { + logmsg("SSL version 2 is unsecure, we don't support it\n"); + close_sock(as); + continue; + } + if ( (! pc.acceptunencryptedconnection) && (as >= 0)) { + logmsg("Unencrypted connections are not accepted and we received an unencrypted connection request\n"); + close_sock(as); + continue; + } /* SSL stuff end */ - s = malloc(sizeof(struct mansession)); - if ( !s ) { - logmsg("Failed to allocate listener session: %s\n", strerror(errno)); - continue; - } - memset(s, 0, sizeof(struct mansession)); - memcpy(&s->sin, &sin, sizeof(sin)); + s = malloc(sizeof(struct mansession)); + if ( !s ) { + logmsg("Failed to allocate listener session: %s\n", strerror(errno)); + continue; + } + memset(s, 0, sizeof(struct mansession)); + memcpy(&s->sin, &sin, sizeof(sin)); - /* For safety, make sure socket is non-blocking */ - flags = fcntl(get_real_fd(as), F_GETFL); + /* For safety, make sure socket is non-blocking */ + flags = fcntl(get_real_fd(as), F_GETFL); fcntl(get_real_fd(as), F_SETFL, flags | O_NONBLOCK); - pthread_mutex_init(&s->lock, NULL); - s->fd = as; - SetIOHandlers(s, pc.inputformat, pc.outputformat); - s->autofilter = pc.autofilter; - s->server = NULL; - - pthread_mutex_lock(&sessionlock); - s->next = sessions; - sessions = s; - pthread_mutex_unlock(&sessionlock); - - logmsg("Connection received from %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - if (debug) { - debugmsg("Connection received from %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); - debugmsg("Set %s input format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->input->formatname); - debugmsg("Set %s output format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->output->formatname); - } - - if (pthread_create(&s->t, &attr, (void *)session_do, s)) - destroy_session(s); - } - pthread_attr_destroy(&attr); - return NULL; + pthread_mutex_init(&s->lock, NULL); + s->fd = as; + SetIOHandlers(s, pc.inputformat, pc.outputformat); + s->autofilter = pc.autofilter; + s->server = NULL; + + pthread_mutex_lock(&sessionlock); + s->next = sessions; + sessions = s; + pthread_mutex_unlock(&sessionlock); + + logmsg("Connection received from %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + if (debug) { + debugmsg("Connection received from %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); + debugmsg("Set %s input format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->input->formatname); + debugmsg("Set %s output format to %s", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->output->formatname); + } + + if (pthread_create(&s->t, &attr, (void *)session_do, s)) + destroy_session(s); + } + pthread_attr_destroy(&attr); + return NULL; } int main(int argc, char *argv[]) { - struct sockaddr_in serv_sock_addr, client_sock_addr; - int cli_addrlen; - struct linger lingerstruct; /* for socket reuse */ - int flag; /* for socket reuse */ - pid_t pid; - char i; - - /* Figure out if we are in debug mode, handle other switches */ - while (( i = getopt( argc, argv, "dhv" ) ) != EOF ) - { - switch( i ) { - case 'd': - debug++; - break; - case 'h': - Usage(); - exit(0); - case 'v': - Version(); - exit(0); - case '?': - Usage(); - exit(1); - } - } - - - ReadConfig(); - proxylog = OpenLogfile(); - debugmsg("loading handlers"); - LoadHandlers(); - debugmsg("loaded handlers"); - - if (SetProcUID()) { - fprintf(stderr,"Cannot set user/group! Check proc_user and proc_group config setting!\n"); - exit(1); - } - - /* If we are not in debug mode, then fork to background */ - if (!debug) { - if ( (pid = fork()) < 0) - exit( 1 ); - else if ( pid > 0) - exit( 0 ); - } - - /* Setup signal handlers */ - (void) signal(SIGINT,leave); - (void) signal(SIGHUP,hup); - (void) signal(SIGTERM,leave); - (void) signal(SIGPIPE, SIG_IGN); - - /* Initialize global mutexes */ - pthread_mutex_init(&sessionlock, NULL); - pthread_mutex_init(&userslock, NULL); - pthread_mutex_init(&loglock, NULL); - pthread_mutex_init(&debuglock, NULL); - - /* Read initial state for user permissions */ - ReadPerms(); - - /* Initialize SSL Client-Side Context */ - client_init_secure(); - - /* Initialize global client/server list */ - sessions = NULL; - LaunchAsteriskThreads(); - - /* Setup listener socket to setup new sessions... */ - if ((asock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr,"Cannot create listener socket!\n"); - exit(1); - } - bzero((char *) &serv_sock_addr, sizeof serv_sock_addr ); - serv_sock_addr.sin_family = AF_INET; - - if ( !strcmp(pc.listen_addr,"*") ) - serv_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); - else - serv_sock_addr.sin_addr.s_addr = inet_addr( pc.listen_addr); - serv_sock_addr.sin_port = htons((short)pc.listen_port); - - /* Set listener socket re-use options */ - setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag)); - lingerstruct.l_onoff = 1; - lingerstruct.l_linger = 5; - setsockopt(asock, SOL_SOCKET, SO_LINGER, (void *)&lingerstruct, sizeof(lingerstruct)); - - if (bind(asock, (struct sockaddr *) &serv_sock_addr, sizeof serv_sock_addr ) < 0) { - fprintf(stderr,"Cannot bind to listener socket!\n"); - exit(1); - } - - listen(asock, 5); - cli_addrlen = sizeof(client_sock_addr); - if (debug) - debugmsg("Listening for connections"); - logmsg("Proxy Started: Listening for connections"); - - /* Launch listener thread */ - accept_thread(); - - pthread_exit(NULL); - exit(0); -} - + struct sockaddr_in serv_sock_addr, client_sock_addr; + int cli_addrlen; + struct linger lingerstruct; /* for socket reuse */ + int flag; /* for socket reuse */ + pid_t pid; + char i; + + /* Figure out if we are in debug mode, handle other switches */ + while (( i = getopt( argc, argv, "dhv" ) ) != EOF ) + { + switch( i ) { + case 'd': + debug++; + break; + case 'h': + Usage(); + exit(0); + case 'v': + Version(); + exit(0); + case '?': + Usage(); + exit(1); + } + } + + + ReadConfig(); + proxylog = OpenLogfile(); + debugmsg("loading handlers"); + LoadHandlers(); + debugmsg("loaded handlers"); + + if (SetProcUID()) { + fprintf(stderr,"Cannot set user/group! Check proc_user and proc_group config setting!\n"); + exit(1); + } + + /* If we are not in debug mode, then fork to background */ + if (!debug) { + if ( (pid = fork()) < 0) + exit( 1 ); + else if ( pid > 0) + exit( 0 ); + } + + /* Setup signal handlers */ + (void) signal(SIGINT,leave); + (void) signal(SIGHUP,hup); + (void) signal(SIGTERM,leave); + (void) signal(SIGPIPE, SIG_IGN); + + /* Initialize global mutexes */ + pthread_mutex_init(&sessionlock, NULL); + pthread_mutex_init(&userslock, NULL); + pthread_mutex_init(&loglock, NULL); + pthread_mutex_init(&debuglock, NULL); + + /* Read initial state for user permissions */ + ReadPerms(); + + /* Initialize SSL Client-Side Context */ + client_init_secure(); + + /* Initialize global client/server list */ + sessions = NULL; + LaunchAsteriskThreads(); + + /* Setup listener socket to setup new sessions... */ + if ((asock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr,"Cannot create listener socket!\n"); + exit(1); + } + bzero((char *) &serv_sock_addr, sizeof serv_sock_addr ); + serv_sock_addr.sin_family = AF_INET; + + if ( !strcmp(pc.listen_addr,"*") ) + serv_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else + serv_sock_addr.sin_addr.s_addr = inet_addr( pc.listen_addr); + + serv_sock_addr.sin_port = htons((short)pc.listen_port); + + /* Set listener socket re-use options */ + setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag)); + lingerstruct.l_onoff = 1; + lingerstruct.l_linger = 5; + setsockopt(asock, SOL_SOCKET, SO_LINGER, (void *)&lingerstruct, sizeof(lingerstruct)); + + if (bind(asock, (struct sockaddr *) &serv_sock_addr, sizeof serv_sock_addr ) < 0) { + fprintf(stderr,"Cannot bind to listener socket!\n"); + exit(1); + } + + listen(asock, 5); + cli_addrlen = sizeof(client_sock_addr); + if (debug) + debugmsg("Listening for connections"); + logmsg("Proxy Started: Listening for connections"); + + /* Launch listener thread */ + accept_thread(); + + pthread_exit(NULL); + exit(0); +} \ No newline at end of file diff --git a/src/common.c b/src/common.c index d6bea7a..b87d564 100644 --- a/src/common.c +++ b/src/common.c @@ -1,3 +1,14 @@ +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + common.c + contains common utililty functions used by both astmanproxy + core as well as (many) of the various I/O handlers +*/ + #include "astmanproxy.h" /* This routine based on get_input from Asterisk manager.c */ @@ -5,131 +16,131 @@ /* Used by standard.c and other input handlers */ int get_input(struct mansession *s, char *output) { - /* output must have at least sizeof(s->inbuf) space */ - int res; - int x; - struct pollfd fds[1]; - char iabuf[INET_ADDRSTRLEN]; - - /* Look for \r\n from the front, our preferred end of line */ - for (x=0;xinlen;x++) { - int xtra = 0; - if (s->inbuf[x] == '\n') { - if (x && s->inbuf[x-1] == '\r') { - xtra = 1; - } - /* Copy output data not including \r\n */ - memcpy(output, s->inbuf, x - xtra); - /* Add trailing \0 */ - output[x-xtra] = '\0'; - /* Move remaining data back to the front */ - memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x); - s->inlen -= (x + 1); - return 1; - } - } - - if (s->inlen >= sizeof(s->inbuf) - 1) { - if (debug) - debugmsg("Warning: Got long line with no end from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf); - s->inlen = 0; - } + /* output must have at least sizeof(s->inbuf) space */ + int res; + int x; + struct pollfd fds[1]; + char iabuf[INET_ADDRSTRLEN]; + + /* Look for \r\n from the front, our preferred end of line */ + for (x=0;xinlen;x++) { + int xtra = 0; + if (s->inbuf[x] == '\n') { + if (x && s->inbuf[x-1] == '\r') { + xtra = 1; + } + /* Copy output data not including \r\n */ + memcpy(output, s->inbuf, x - xtra); + /* Add trailing \0 */ + output[x-xtra] = '\0'; + /* Move remaining data back to the front */ + memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x); + s->inlen -= (x + 1); + return 1; + } + } + + if (s->inlen >= sizeof(s->inbuf) - 1) { + if (debug) + debugmsg("Warning: Got long line with no end from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf); + s->inlen = 0; + } /* get actual fd, even if a negative SSL fd */ - fds[0].fd = get_real_fd(s->fd); + fds[0].fd = get_real_fd(s->fd); - fds[0].events = POLLIN; - do { - res = poll(fds, 1, -1); + fds[0].events = POLLIN; + do { + res = poll(fds, 1, -1); if (res < 0) { - if (errno == EINTR) { - if (s->dead) - return -1; - continue; - } - if (debug) - debugmsg("Select returned error"); + if (errno == EINTR) { + if (s->dead) + return -1; + continue; + } + if (debug) + debugmsg("Select returned error"); return -1; - } else if (res > 0) { - pthread_mutex_lock(&s->lock); + } else if (res > 0) { + pthread_mutex_lock(&s->lock); /* read from socket; SSL or otherwise */ res = m_recv(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen, 0); - pthread_mutex_unlock(&s->lock); - if (res < 1) - return -1; + pthread_mutex_unlock(&s->lock); + if (res < 1) + return -1; break; - } + } } while(1); - /* We have some input, but it's not ready for processing */ - s->inlen += res; - s->inbuf[s->inlen] = '\0'; - return 0; + /* We have some input, but it's not ready for processing */ + s->inlen += res; + s->inbuf[s->inlen] = '\0'; + return 0; } char *astman_get_header(struct message *m, char *var) { - char cmp[80]; - int x; - snprintf(cmp, sizeof(cmp), "%s: ", var); - for (x=0;xhdrcount;x++) - if (!strncasecmp(cmp, m->headers[x], strlen(cmp))) - return m->headers[x] + strlen(cmp); - return ""; + char cmp[80]; + int x; + snprintf(cmp, sizeof(cmp), "%s: ", var); + for (x=0;xhdrcount;x++) + if (!strncasecmp(cmp, m->headers[x], strlen(cmp))) + return m->headers[x] + strlen(cmp); + return ""; } int AddHeader(struct message *m, const char *fmt, ...) { - va_list ap; + va_list ap; - int res; + int res; - if (m->hdrcount < MAX_HEADERS - 1) { - va_start(ap, fmt); - vsprintf(m->headers[m->hdrcount], fmt, ap); - va_end(ap); - m->hdrcount++; - res = 0; - } else - res = 1; + if (m->hdrcount < MAX_HEADERS - 1) { + va_start(ap, fmt); + vsprintf(m->headers[m->hdrcount], fmt, ap); + va_end(ap); + m->hdrcount++; + res = 0; + } else + res = 1; - return res; + return res; } /* Recursive thread safe replacement of inet_ntoa */ const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia) { - return inet_ntop(AF_INET, &ia, buf, bufsiz); + return inet_ntop(AF_INET, &ia, buf, bufsiz); } /*! If you are calling ast_carefulwrite, it is assumed that you are calling - it on a file descriptor that _DOES_ have NONBLOCK set. This way, - there is only one system call made to do a write, unless we actually - have a need to wait. This way, we get better performance. */ + it on a file descriptor that _DOES_ have NONBLOCK set. This way, + there is only one system call made to do a write, unless we actually + have a need to wait. This way, we get better performance. */ int ast_carefulwrite(int fd, char *s, int len, int timeoutms) { - /* Try to write string, but wait no more than ms milliseconds - before timing out */ - int res=0; - struct pollfd fds[1]; - while(len) { - res = m_send(fd, s, len); - if ((res < 0) && (errno != EAGAIN)) { - return -1; - } - if (res < 0) res = 0; - len -= res; - s += res; - res = 0; - if (len) { - fds[0].fd = get_real_fd(fd); - fds[0].events = POLLOUT; - /* Wait until writable again */ - res = poll(fds, 1, timeoutms); - if (res < 1) - return -1; - } - } - return res; + /* Try to write string, but wait no more than ms milliseconds + before timing out */ + int res=0; + struct pollfd fds[1]; + while(len) { + res = m_send(fd, s, len); + if ((res < 0) && (errno != EAGAIN)) { + return -1; + } + if (res < 0) res = 0; + len -= res; + s += res; + res = 0; + if (len) { + fds[0].fd = get_real_fd(fd); + fds[0].events = POLLOUT; + /* Wait until writable again */ + res = poll(fds, 1, timeoutms); + if (res < 1) + return -1; + } + } + return res; } diff --git a/src/config.c b/src/config.c index f642aa6..4a9ce2b 100644 --- a/src/config.c +++ b/src/config.c @@ -1,3 +1,14 @@ +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + config.c + routines to read and parse the configuration file and initialize + the internal configuration datastructures +*/ + #include #include #include "astmanproxy.h" @@ -6,300 +17,297 @@ extern struct iohandler *iohandlers; void *add_server(char *srvspec) { - int ccount = 0; - struct ast_server *srv; - char *s; - char usessl[10]; - - /* malloc ourselves a server credentials structure */ - srv = malloc(sizeof(struct ast_server)); - if ( !srv ) { - fprintf(stderr, "Failed to allocate server credentials: %s\n", strerror(errno)); - exit(1); - } - memset(srv, 0, sizeof (struct ast_server) ); - memset(usessl, 0, sizeof (usessl) ); - - s = srvspec; - do { - *s = tolower(*s); - if ( *s == ',' ) { - ccount++; - continue; - } - switch(ccount) { - case 0: - strncat(srv->ast_host, s, 1); - break; - case 1: - strncat(srv->ast_port, s, 1); - break; - case 2: - strncat(srv->ast_user, s, 1); - break; - case 3: - strncat(srv->ast_pass, s, 1); - break; - case 4: - strncat(srv->ast_events, s, 1); - break; - case 5: - strncat(usessl, s, 1); - break; - } - } while (*(s++)); - - - if (!*srv->ast_host || !*srv->ast_port || !*srv->ast_user || !*srv->ast_pass || !*srv->ast_events || !*usessl) { - fprintf(stderr, "Aborting: server spec incomplete: %s\n", srvspec); - free(srv); - exit(1); - } - - srv->use_ssl = (!strcmp(usessl,"on")); - srv->next = pc.serverlist; - pc.serverlist = srv; - - return 0; + int ccount = 0; + struct ast_server *srv; + char *s; + char usessl[10]; + + /* malloc ourselves a server credentials structure */ + srv = malloc(sizeof(struct ast_server)); + if ( !srv ) { + fprintf(stderr, "Failed to allocate server credentials: %s\n", strerror(errno)); + exit(1); + } + memset(srv, 0, sizeof (struct ast_server) ); + memset(usessl, 0, sizeof (usessl) ); + + s = srvspec; + do { + *s = tolower(*s); + if ( *s == ',' ) { + ccount++; + continue; + } + switch(ccount) { + case 0: + strncat(srv->ast_host, s, 1); + break; + case 1: + strncat(srv->ast_port, s, 1); + break; + case 2: + strncat(srv->ast_user, s, 1); + break; + case 3: + strncat(srv->ast_pass, s, 1); + break; + case 4: + strncat(srv->ast_events, s, 1); + break; + case 5: + strncat(usessl, s, 1); + break; + } + } while (*(s++)); + + + if (!*srv->ast_host || !*srv->ast_port || !*srv->ast_user || !*srv->ast_pass || !*srv->ast_events || !*usessl) { + fprintf(stderr, "Aborting: server spec incomplete: %s\n", srvspec); + free(srv); + exit(1); + } + + srv->use_ssl = (!strcmp(usessl,"on")); + srv->next = pc.serverlist; + pc.serverlist = srv; + + return 0; } void *processline(char *s) { - char name[80],value[80]; - int nvstate = 0; - - - memset (name,0,sizeof name); - memset (value,0,sizeof value); - - do { - *s = tolower(*s); - - if ( *s == ' ' || *s == '\t') - continue; - if ( *s == ';' || *s == '#' || *s == '\r' || *s == '\n' ) - break; - if ( *s == '=' ) { - nvstate = 1; - continue; - } - if (!nvstate) - strncat(name, s, 1); - else - strncat(value, s, 1); - } while (*(s++)); - - if (debug) - debugmsg("config: %s, %s", name, value); - - if ( !strcmp(name,"host") ) - add_server(value); - else if (!strcmp(name,"retryinterval") ) - pc.retryinterval = atoi(value); - else if (!strcmp(name,"maxretries") ) - pc.maxretries = atoi(value); - else if (!strcmp(name,"listenaddress") ) - strcpy(pc.listen_addr, value); - else if (!strcmp(name,"listenport") ) - pc.listen_port = atoi(value); - else if (!strcmp(name,"asteriskwritetimeout") ) - pc.asteriskwritetimeout = atoi(value); - else if (!strcmp(name,"clientwritetimeout") ) - pc.clientwritetimeout = atoi(value); - else if (!strcmp(name,"sslclienthellotimeout") ) - pc.sslclhellotimeout = atoi(value); - else if (!strcmp(name,"authrequired") ) - pc.authrequired = strcmp(value,"yes") ? 0 : 1; - else if (!strcmp(name,"acceptencryptedconnection") ) - pc.acceptencryptedconnection = strcmp(value,"yes") ? 0 : 1; - else if (!strcmp(name,"acceptunencryptedconnection") ) - pc.acceptunencryptedconnection = strcmp(value,"yes") ? 0 : 1; - else if (!strcmp(name,"certfile") ) - strcpy(pc.certfile, value); - else if (!strcmp(name,"proxykey") ) - strcpy(pc.key, value); - else if (!strcmp(name,"proc_user") ) - strcpy(pc.proc_user, value); - else if (!strcmp(name,"proc_group") ) - strcpy(pc.proc_group, value); - else if (!strcmp(name,"logfile") ) - strcpy(pc.logfile, value); - else if (!strcmp(name,"autofilter") ) - pc.autofilter = strcmp(value,"on") ? 0 : 1; - else if (!strcmp(name,"outputformat") ) - strcpy(pc.outputformat, value); - else if (!strcmp(name,"inputformat") ) - strcpy(pc.inputformat, value); - - return 0; + char name[80],value[80]; + int nvstate = 0; + + + memset (name,0,sizeof name); + memset (value,0,sizeof value); + + do { + *s = tolower(*s); + + if ( *s == ' ' || *s == '\t') + continue; + if ( *s == ';' || *s == '#' || *s == '\r' || *s == '\n' ) + break; + if ( *s == '=' ) { + nvstate = 1; + continue; + } + if (!nvstate) + strncat(name, s, 1); + else + strncat(value, s, 1); + } while (*(s++)); + + if (debug) + debugmsg("config: %s, %s", name, value); + + if ( !strcmp(name,"host") ) + add_server(value); + else if (!strcmp(name,"retryinterval") ) + pc.retryinterval = atoi(value); + else if (!strcmp(name,"maxretries") ) + pc.maxretries = atoi(value); + else if (!strcmp(name,"listenaddress") ) + strcpy(pc.listen_addr, value); + else if (!strcmp(name,"listenport") ) + pc.listen_port = atoi(value); + else if (!strcmp(name,"asteriskwritetimeout") ) + pc.asteriskwritetimeout = atoi(value); + else if (!strcmp(name,"clientwritetimeout") ) + pc.clientwritetimeout = atoi(value); + else if (!strcmp(name,"sslclienthellotimeout") ) + pc.sslclhellotimeout = atoi(value); + else if (!strcmp(name,"authrequired") ) + pc.authrequired = strcmp(value,"yes") ? 0 : 1; + else if (!strcmp(name,"acceptencryptedconnection") ) + pc.acceptencryptedconnection = strcmp(value,"yes") ? 0 : 1; + else if (!strcmp(name,"acceptunencryptedconnection") ) + pc.acceptunencryptedconnection = strcmp(value,"yes") ? 0 : 1; + else if (!strcmp(name,"certfile") ) + strcpy(pc.certfile, value); + else if (!strcmp(name,"proxykey") ) + strcpy(pc.key, value); + else if (!strcmp(name,"proc_user") ) + strcpy(pc.proc_user, value); + else if (!strcmp(name,"proc_group") ) + strcpy(pc.proc_group, value); + else if (!strcmp(name,"logfile") ) + strcpy(pc.logfile, value); + else if (!strcmp(name,"autofilter") ) + pc.autofilter = strcmp(value,"on") ? 0 : 1; + else if (!strcmp(name,"outputformat") ) + strcpy(pc.outputformat, value); + else if (!strcmp(name,"inputformat") ) + strcpy(pc.inputformat, value); + + return 0; } int LoadHandlers() { - void *dlhandle = NULL; - const char *error; - char fmt[20], moddir[80] = MDIR, modfile[80]; - DIR *mods; - struct dirent *d; - void *rh, *wh, *och; - struct iohandler *io = NULL; - - mods = opendir(moddir); - if (!mods) - exit(1); - - while((d = readdir(mods))) { - /* Must end in .so to load it. */ - if ( (strlen(d->d_name) > 3) && !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") ) { - - memset(fmt, 0, sizeof fmt); - strncpy(fmt, d->d_name, strlen(d->d_name) - 3); - - sprintf(modfile, "%s/%s", moddir, d->d_name); - if (debug) - debugmsg("loading: module %s (%s)", fmt, modfile); - - dlhandle = dlopen (modfile, RTLD_LAZY); - if (!dlhandle) { - fprintf(stderr, "dlopen failed: %s\n", dlerror()); - exit(1); - } - - rh = dlsym(dlhandle, "_read"); - if ((error = dlerror()) != NULL) { - if (debug) - debugmsg("loading: note, %s_read does not exist; ignoring", fmt); - } - - wh = dlsym(dlhandle, "_write"); - if ((error = dlerror()) != NULL) { - if (debug) - debugmsg("loading: note, %s_write does not exist; ignoring", fmt); - } - - och = dlsym(dlhandle, "_onconnect"); - if ((error = dlerror()) != NULL) { - if (debug) - debugmsg("loading: note, %s_onconnect does not exist; ignoring", fmt); - } - - if (rh || wh) { - io = malloc(sizeof(struct iohandler)); - memset(io, 0, sizeof(struct iohandler)); - strcpy(io->formatname, fmt); - if (rh) - io->read = rh; - if (wh) - io->write = wh; - if (och) - io->onconnect = och; - - io->dlhandle = dlhandle; - io->next = iohandlers; - iohandlers = io; - } else - dlclose(dlhandle); - - } - } - closedir(mods); - - if (!iohandlers) { - fprintf(stderr, "Unable to load *ANY* IO Handlers from %s!\n", MDIR); - exit(1); - } - - return 0; + void *dlhandle = NULL; + const char *error; + char fmt[20], moddir[80] = MDIR, modfile[80]; + DIR *mods; + struct dirent *d; + void *rh, *wh, *och; + struct iohandler *io = NULL; + + mods = opendir(moddir); + if (!mods) + exit(1); + + while((d = readdir(mods))) { + /* Must end in .so to load it. */ + if ( (strlen(d->d_name) > 3) && !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") ) { + + memset(fmt, 0, sizeof fmt); + strncpy(fmt, d->d_name, strlen(d->d_name) - 3); + + sprintf(modfile, "%s/%s", moddir, d->d_name); + if (debug) + debugmsg("loading: module %s (%s)", fmt, modfile); + + dlhandle = dlopen (modfile, RTLD_LAZY); + if (!dlhandle) { + fprintf(stderr, "dlopen failed: %s\n", dlerror()); + exit(1); + } + + rh = dlsym(dlhandle, "_read"); + if ((error = dlerror()) != NULL) { + if (debug) + debugmsg("loading: note, %s_read does not exist; ignoring", fmt); + } + + wh = dlsym(dlhandle, "_write"); + if ((error = dlerror()) != NULL) { + if (debug) + debugmsg("loading: note, %s_write does not exist; ignoring", fmt); + } + + och = dlsym(dlhandle, "_onconnect"); + if ((error = dlerror()) != NULL) { + if (debug) + debugmsg("loading: note, %s_onconnect does not exist; ignoring", fmt); + } + + if (rh || wh) { + io = malloc(sizeof(struct iohandler)); + memset(io, 0, sizeof(struct iohandler)); + strcpy(io->formatname, fmt); + if (rh) + io->read = rh; + if (wh) + io->write = wh; + if (och) + io->onconnect = och; + + io->dlhandle = dlhandle; + io->next = iohandlers; + iohandlers = io; + } else + dlclose(dlhandle); + } + } + closedir(mods); + + if (!iohandlers) { + fprintf(stderr, "Unable to load *ANY* IO Handlers from %s!\n", MDIR); + exit(1); + } + + return 0; } int ReadConfig() { - FILE *FP; - char buf[1024]; - char cfn[80]; + FILE *FP; + char buf[1024]; + char cfn[80]; - memset( &pc, 0, sizeof pc ); + memset( &pc, 0, sizeof pc ); - /* Set nonzero config defaults */ - pc.asteriskwritetimeout = 100; - pc.clientwritetimeout = 100; - pc.sslclhellotimeout = 500; + /* Set nonzero config defaults */ + pc.asteriskwritetimeout = 100; + pc.clientwritetimeout = 100; + pc.sslclhellotimeout = 500; - sprintf(cfn, "%s/%s", CDIR, CFILE); - FP = fopen( cfn, "r" ); + sprintf(cfn, "%s/%s", CDIR, CFILE); + FP = fopen( cfn, "r" ); - if ( !FP ) - { - fprintf(stderr, "Unable to open config file: %s/%s!\n", CDIR, CFILE); - exit( 1 ); - } + if ( !FP ) { + fprintf(stderr, "Unable to open config file: %s/%s!\n", CDIR, CFILE); + exit( 1 ); + } - if (debug) - debugmsg("config: parsing configuration file: %s", cfn); + if (debug) + debugmsg("config: parsing configuration file: %s", cfn); - while ( fgets( buf, sizeof buf, FP ) ) { - if (*buf == ';' || *buf == '\r' || *buf == '\n' || *buf == '#') continue; - processline(buf); - } + while ( fgets( buf, sizeof buf, FP ) ) { + if (*buf == ';' || *buf == '\r' || *buf == '\n' || *buf == '#') continue; + processline(buf); + } - fclose(FP); + fclose(FP); - /* initialize SSL layer with our server certfile */ - init_secure(pc.certfile); + /* initialize SSL layer with our server certfile */ + init_secure(pc.certfile); - return 0; + return 0; } FILE *OpenLogfile() { - FILE *FP; - FP = fopen( pc.logfile, "a" ); - if ( !FP ) { - fprintf(stderr, "Unable to open logfile: %s!\n", pc.logfile); - exit( 1 ); - } - - return FP; + FILE *FP; + FP = fopen( pc.logfile, "a" ); + if ( !FP ) { + fprintf(stderr, "Unable to open logfile: %s!\n", pc.logfile); + exit( 1 ); + } + + return FP; } int SetProcUID() { - struct passwd *pwent; - struct group *gp; - uid_t newuid = 0; - gid_t newgid = 0; - - if ((pwent = (struct passwd *)getpwnam( pc.proc_user )) == NULL) { - fprintf(stderr, "getpwnam(%s) failed.\n", pc.proc_user); - return(-1); - } else - newuid = pwent->pw_uid; - - if ( newuid == 0 ) { - fprintf(stderr, "getpwnam(%s) returned root user; aborting!\n", pc.proc_user); - return(-1); - } - - if ((gp = (struct group *)getgrnam( pc.proc_group )) == NULL) { - fprintf(stderr, "getgrnam(%s) failed.\n", pc.proc_group); - return(-1); - } else - newgid = gp->gr_gid; - - if ( chown( pc.logfile, newuid, newgid ) < 0 ) - { - fprintf(stderr, "chown(%d,%d) of %s failed!\n", newuid, newgid, pc.logfile); - return( -1 ); - } - - if (setgid(newgid) < 0) { - fprintf(stderr, "setgid(%d) failed.\n", newgid); - return(-1); - } - - if (setuid(newuid) < 0) { - fprintf(stderr, "setuid(%d) failed.\n", newuid); - return(-1); - } - - return 0; + struct passwd *pwent; + struct group *gp; + uid_t newuid = 0; + gid_t newgid = 0; + + if ((pwent = (struct passwd *)getpwnam( pc.proc_user )) == NULL) { + fprintf(stderr, "getpwnam(%s) failed.\n", pc.proc_user); + return(-1); + } else + newuid = pwent->pw_uid; + + if ( newuid == 0 ) { + fprintf(stderr, "getpwnam(%s) returned root user; aborting!\n", pc.proc_user); + return(-1); + } + + if ((gp = (struct group *)getgrnam( pc.proc_group )) == NULL) { + fprintf(stderr, "getgrnam(%s) failed.\n", pc.proc_group); + return(-1); + } else + newgid = gp->gr_gid; + + if ( chown( pc.logfile, newuid, newgid ) < 0 ) { + fprintf(stderr, "chown(%d,%d) of %s failed!\n", newuid, newgid, pc.logfile); + return( -1 ); + } + + if (setgid(newgid) < 0) { + fprintf(stderr, "setgid(%d) failed.\n", newgid); + return(-1); + } + + if (setuid(newuid) < 0) { + fprintf(stderr, "setuid(%d) failed.\n", newuid); + return(-1); + } + + return 0; } diff --git a/src/config_perms.c b/src/config_perms.c index 4dbeeb0..647e36b 100644 --- a/src/config_perms.c +++ b/src/config_perms.c @@ -1,125 +1,135 @@ +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + config_perms.c + routines to read and parse the astmanproxy.users file +*/ + #include "astmanproxy.h" extern pthread_mutex_t userslock; void *free_userperm(struct proxy_user *pu) { - struct proxy_user *next_pu; - - while( pu ) { - next_pu = pu->next; - free( pu ); - pu = next_pu; - } - return 0; + struct proxy_user *next_pu; + + while( pu ) { + next_pu = pu->next; + free( pu ); + pu = next_pu; + } + return 0; } void *add_userperm(char* username, char *userspec, struct proxy_user **pu) { - int ccount = 0; - struct proxy_user *user; - char *s; - - /* malloc ourselves a server credentials structure */ - user = malloc(sizeof(struct proxy_user)); - if ( !user ) { - fprintf(stderr, "Failed to allocate user credentials: %s\n", strerror(errno)); - exit(1); - } - memset(user, 0, sizeof (struct proxy_user) ); - - s = userspec; - strncpy(user->username, username, sizeof(user->username)-1 ); - do { - if ( *s == ',' ) { - ccount++; - continue; - } - switch(ccount) { - case 0: - strncat(user->secret, s, 1); - break; - case 1: - strncat(user->channel, s, 1); - break; - case 2: - strncat(user->ocontext, s, 1); - break; - case 3: - strncat(user->icontext, s, 1); - break; - } - } while (*(s++)); - - user->next = *pu; - *pu = user; - - return 0; + int ccount = 0; + struct proxy_user *user; + char *s; + + /* malloc ourselves a server credentials structure */ + user = malloc(sizeof(struct proxy_user)); + if ( !user ) { + fprintf(stderr, "Failed to allocate user credentials: %s\n", strerror(errno)); + exit(1); + } + memset(user, 0, sizeof (struct proxy_user) ); + + s = userspec; + strncpy(user->username, username, sizeof(user->username)-1 ); + do { + if ( *s == ',' ) { + ccount++; + continue; + } + switch(ccount) { + case 0: + strncat(user->secret, s, 1); + break; + case 1: + strncat(user->channel, s, 1); + break; + case 2: + strncat(user->ocontext, s, 1); + break; + case 3: + strncat(user->icontext, s, 1); + break; + } + } while (*(s++)); + + user->next = *pu; + *pu = user; + + return 0; } void *processperm(char *s, struct proxy_user **pu) { - char name[80],value[80]; - int nvstate = 0; + char name[80],value[80]; + int nvstate = 0; - memset (name,0,sizeof name); - memset (value,0,sizeof value); + memset (name,0,sizeof name); + memset (value,0,sizeof value); - do { - *s = tolower(*s); + do { + *s = tolower(*s); - if ( *s == ' ' || *s == '\t') - continue; - if ( *s == ';' || *s == '#' || *s == '\r' || *s == '\n' ) - break; - if ( *s == '=' ) { - nvstate = 1; - continue; - } - if (!nvstate) - strncat(name, s, 1); - else - strncat(value, s, 1); - } while (*(s++)); + if ( *s == ' ' || *s == '\t') + continue; + if ( *s == ';' || *s == '#' || *s == '\r' || *s == '\n' ) + break; + if ( *s == '=' ) { + nvstate = 1; + continue; + } + if (!nvstate) + strncat(name, s, 1); + else + strncat(value, s, 1); + } while (*(s++)); - if (debug) - debugmsg("perm: %s, %s", name, value); + if (debug) + debugmsg("perm: %s, %s", name, value); - add_userperm(name,value,pu); + add_userperm(name,value,pu); - return 0; + return 0; } int ReadPerms() { - FILE *FP; - char buf[1024]; - char cfn[80]; - struct proxy_user *pu; + FILE *FP; + char buf[1024]; + char cfn[80]; + struct proxy_user *pu; - pu=0; - sprintf(cfn, "%s/%s", PDIR, PFILE); - FP = fopen( cfn, "r" ); + pu=0; + sprintf(cfn, "%s/%s", PDIR, PFILE); + FP = fopen( cfn, "r" ); - if ( !FP ) - { - fprintf(stderr, "Unable to open permissions file: %s/%s!\n", PDIR, PFILE); - exit( 1 ); - } + if ( !FP ) + { + fprintf(stderr, "Unable to open permissions file: %s/%s!\n", PDIR, PFILE); + exit( 1 ); + } - if (debug) - debugmsg("config: parsing configuration file: %s", cfn); + if (debug) + debugmsg("config: parsing configuration file: %s", cfn); - while ( fgets( buf, sizeof buf, FP ) ) { - if (*buf == ';' || *buf == '\r' || *buf == '\n' || *buf == '#') continue; - processperm(buf,&pu); - } + while ( fgets( buf, sizeof buf, FP ) ) { + if (*buf == ';' || *buf == '\r' || *buf == '\n' || *buf == '#') continue; + processperm(buf,&pu); + } - fclose(FP); + fclose(FP); - pthread_mutex_lock(&userslock); - free_userperm(pc.userlist); - pc.userlist=pu; - pthread_mutex_unlock(&userslock); + pthread_mutex_lock(&userslock); + free_userperm(pc.userlist); + pc.userlist=pu; + pthread_mutex_unlock(&userslock); - return 0; + return 0; } diff --git a/src/csv.c b/src/csv.c index 94d9a00..bcd9a88 100644 --- a/src/csv.c +++ b/src/csv.c @@ -1,10 +1,11 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005 David C. Troy +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy - This program is free software, distributed under the terms of - the GNU General Public License. + This program is free software, distributed under the terms of + the GNU General Public License. - CSV I/O Handler + csv.c + CSV I/O Handler */ #include "astmanproxy.h" @@ -12,19 +13,19 @@ /* TODO: catch and expand/handle commas in output */ int _write(struct mansession *s, struct message *m) { - int i; - char outstring[MAX_LEN]; - - pthread_mutex_lock(&s->lock); - for (i=0; ihdrcount; i++) { - sprintf(outstring, "\"%s\"", m->headers[i]); - if (ihdrcount-1) - strcat(outstring, ", "); - ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout); - } - ast_carefulwrite(s->fd, "\r\n\r\n", 4, s->writetimeout); - pthread_mutex_unlock(&s->lock); - - return 0; + int i; + char outstring[MAX_LEN]; + + pthread_mutex_lock(&s->lock); + for (i=0; ihdrcount; i++) { + sprintf(outstring, "\"%s\"", m->headers[i]); + if (ihdrcount-1) + strcat(outstring, ", "); + ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout); + } + ast_carefulwrite(s->fd, "\r\n\r\n", 4, s->writetimeout); + pthread_mutex_unlock(&s->lock); + + return 0; } diff --git a/src/http.c b/src/http.c index a21a7ed..3dc874f 100644 --- a/src/http.c +++ b/src/http.c @@ -1,61 +1,62 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005 David C. Troy +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy - This program is free software, distributed under the terms of - the GNU General Public License. + This program is free software, distributed under the terms of + the GNU General Public License. - HTTP Input Handler + http.c + HTTP Input Handler */ #include "astmanproxy.h" -// SwapChar: This routine swaps one character for another +// SwapChar: This routine swaps one character for another void SwapChar(char *pOriginal, char cBad, char cGood) { - int i; // generic counter variable + int i; // generic counter variable - // Loop through the input string (cOriginal), character by - // character, replacing each instance of cBad with cGood + // Loop through the input string (cOriginal), character by + // character, replacing each instance of cBad with cGood - i = 0; - while (pOriginal[i]) { - if (pOriginal[i] == cBad) pOriginal[i] = cGood; - i++; - } + i = 0; + while (pOriginal[i]) { + if (pOriginal[i] == cBad) pOriginal[i] = cGood; + i++; + } } -// IntFromHex: A subroutine to unescape escaped characters. +// IntFromHex: A subroutine to unescape escaped characters. static int IntFromHex(char *pChars) { - int Hi; // holds high byte - int Lo; // holds low byte - int Result; // holds result - - // Get the value of the first byte to Hi - - Hi = pChars[0]; - if ('0' <= Hi && Hi <= '9') { - Hi -= '0'; - } else - if ('a' <= Hi && Hi <= 'f') { - Hi -= ('a'-10); - } else - if ('A' <= Hi && Hi <= 'F') { - Hi -= ('A'-10); - } - - // Get the value of the second byte to Lo - - Lo = pChars[1]; - if ('0' <= Lo && Lo <= '9') { - Lo -= '0'; - } else - if ('a' <= Lo && Lo <= 'f') { - Lo -= ('a'-10); - } else - if ('A' <= Lo && Lo <= 'F') { - Lo -= ('A'-10); - } - Result = Lo + (16 * Hi); - return (Result); + int Hi; // holds high byte + int Lo; // holds low byte + int Result; // holds result + + // Get the value of the first byte to Hi + + Hi = pChars[0]; + if ('0' <= Hi && Hi <= '9') { + Hi -= '0'; + } else + if ('a' <= Hi && Hi <= 'f') { + Hi -= ('a'-10); + } else + if ('A' <= Hi && Hi <= 'F') { + Hi -= ('A'-10); + } + + // Get the value of the second byte to Lo + + Lo = pChars[1]; + if ('0' <= Lo && Lo <= '9') { + Lo -= '0'; + } else + if ('a' <= Lo && Lo <= 'f') { + Lo -= ('a'-10); + } else + if ('A' <= Lo && Lo <= 'F') { + Lo -= ('A'-10); + } + Result = Lo + (16 * Hi); + return (Result); } // URLDecode: This routine loops through the string pEncoded @@ -65,173 +66,173 @@ static int IntFromHex(char *pChars) { // above in this listing, IntFromHex() and SwapChar(). void URLDecode(char *pEncoded) { - char *pDecoded; // generic pointer - - // First, change those pesky plusses to spaces - SwapChar (pEncoded, '+', ' '); - - // Now, loop through looking for escapes - pDecoded = pEncoded; - while (*pEncoded) { - if (*pEncoded=='%') { - // A percent sign followed by two hex digits means - // that the digits represent an escaped character. We - // must decode it. - - pEncoded++; - if (isxdigit(pEncoded[0]) && isxdigit(pEncoded[1])) { - *pDecoded++ = (char) IntFromHex(pEncoded); - pEncoded += 2; - } - } else { - *pDecoded ++ = *pEncoded++; - } - } - *pDecoded = '\0'; + char *pDecoded; // generic pointer + + // First, change those pesky plusses to spaces + SwapChar (pEncoded, '+', ' '); + + // Now, loop through looking for escapes + pDecoded = pEncoded; + while (*pEncoded) { + if (*pEncoded=='%') { + // A percent sign followed by two hex digits means + // that the digits represent an escaped character. We + // must decode it. + + pEncoded++; + if (isxdigit(pEncoded[0]) && isxdigit(pEncoded[1])) { + *pDecoded++ = (char) IntFromHex(pEncoded); + pEncoded += 2; + } + } else { + *pDecoded ++ = *pEncoded++; + } + } + *pDecoded = '\0'; } int ParseHTTPInput(char *buf, struct message *m) { - char *n, *v; - - n = buf; - while ( (v = strstr(n, "=")) ) { - v += 1; - debugmsg("n: %s, v: %s", n, v); - strncat(m->headers[m->hdrcount], n, v-n-1); - strcat(m->headers[m->hdrcount], ": "); - - if ( (n = strstr(v, "&")) ) { - n += 1; - } else { - n = (v + strlen(v) + 1); - } - strncat(m->headers[m->hdrcount], v, n-v-1); - debugmsg("got hdr: %s", m->headers[m->hdrcount]); - m->hdrcount++; - } - - return (m->hdrcount > 0); + char *n, *v; + + n = buf; + while ( (v = strstr(n, "=")) ) { + v += 1; + debugmsg("n: %s, v: %s", n, v); + strncat(m->headers[m->hdrcount], n, v-n-1); + strcat(m->headers[m->hdrcount], ": "); + + if ( (n = strstr(v, "&")) ) { + n += 1; + } else { + n = (v + strlen(v) + 1); + } + strncat(m->headers[m->hdrcount], v, n-v-1); + debugmsg("got hdr: %s", m->headers[m->hdrcount]); + m->hdrcount++; + } + + return (m->hdrcount > 0); } int HTTPHeader(struct mansession *s, char *status) { - time_t t; - struct tm tm; - char date[80]; - char ctype[15], hdr[MAX_LEN]; - - time(&t); - localtime_r(&t, &tm); - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); - - if ( !strcasecmp("xml", s->output->formatname) ) - sprintf(ctype, "text/xml"); - else - sprintf(ctype, "text/plain"); - - if (!strcmp("200 OK", status) ) - sprintf(hdr, - "HTTP/1.1 %s\r\n" - "Date: %s\r\n" - "Content-Type: %s\r\n" - "Connection: close\r\n" - "Server: %s/%s\r\n\r\n", status, - date, ctype, PROXY_BANNER, PROXY_VERSION); - else - sprintf(hdr, - "HTTP/1.1 %s\r\n" - "Date: %s\r\n" - "Status: %s\r\n" - "Server: %s/%s\r\n\r\n", status, date, status, PROXY_BANNER, PROXY_VERSION); - - pthread_mutex_lock(&s->lock); - s->inputcomplete = 1; - ast_carefulwrite(s->fd, hdr, strlen(hdr), s->writetimeout); - pthread_mutex_unlock(&s->lock); - debugmsg("http header: %s", hdr); - - return 0; + time_t t; + struct tm tm; + char date[80]; + char ctype[15], hdr[MAX_LEN]; + + time(&t); + localtime_r(&t, &tm); + strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); + + if ( !strcasecmp("xml", s->output->formatname) ) + sprintf(ctype, "text/xml"); + else + sprintf(ctype, "text/plain"); + + if (!strcmp("200 OK", status) ) + sprintf(hdr, + "HTTP/1.1 %s\r\n" + "Date: %s\r\n" + "Content-Type: %s\r\n" + "Connection: close\r\n" + "Server: %s/%s\r\n\r\n", status, + date, ctype, PROXY_BANNER, PROXY_VERSION); + else + sprintf(hdr, + "HTTP/1.1 %s\r\n" + "Date: %s\r\n" + "Status: %s\r\n" + "Server: %s/%s\r\n\r\n", status, date, status, PROXY_BANNER, PROXY_VERSION); + + pthread_mutex_lock(&s->lock); + s->inputcomplete = 1; + ast_carefulwrite(s->fd, hdr, strlen(hdr), s->writetimeout); + pthread_mutex_unlock(&s->lock); + debugmsg("http header: %s", hdr); + + return 0; } int _read(struct mansession *s, struct message *m) { - /* Note: No single line may be longer than MAX_LEN/s->inbuf, as per get_input */ - /* No HTTP Input may be longer than BUFSIZE */ - - char line[MAX_LEN], method[10], formdata[MAX_LEN], status[15]; - int res, clength = 0; - - memset(method, 0, sizeof method); - memset(formdata, 0, sizeof formdata); - memset(status, 0, sizeof status); - - /* for http, don't do get_input forever */ - for (;;) { - - if (s->inputcomplete && !s->outputcomplete) - continue; - else if (s->inputcomplete && s->outputcomplete) - return -1; - - memset(line, 0, sizeof line); - res = get_input(s, line); - debugmsg("res=%d, line: %s",res, line); - - if (res > 0) { - debugmsg("Got http: %s", line); - - if ( !clength && !strncasecmp(line, "Content-Length: ", 16) ) - clength = atoi(line+16); - - if (!*method) { - if ( !strncmp(line,"POST",4) ) { - strncpy(method, line, 4); - } else if ( !strncmp(line,"GET",3)) { - if ( strlen(line) > 14 ) { - /* GET / HTTP/1.1 ---- this is bad */ - /* GET /?Action=Ping&ActionID=Foo HTTP/1.1 */ - strncpy(method, line, 3); - memcpy(formdata, line+6, strstr(line, " HTTP")-line-6); - sprintf(status, "200 OK"); - } else - sprintf(status, "501 Not Implemented"); - } + /* Note: No single line may be longer than MAX_LEN/s->inbuf, as per get_input */ + /* No HTTP Input may be longer than BUFSIZE */ + + char line[MAX_LEN], method[10], formdata[MAX_LEN], status[15]; + int res, clength = 0; + + memset(method, 0, sizeof method); + memset(formdata, 0, sizeof formdata); + memset(status, 0, sizeof status); + + /* for http, don't do get_input forever */ + for (;;) { + + if (s->inputcomplete && !s->outputcomplete) + continue; + else if (s->inputcomplete && s->outputcomplete) + return -1; + + memset(line, 0, sizeof line); + res = get_input(s, line); + debugmsg("res=%d, line: %s",res, line); + + if (res > 0) { + debugmsg("Got http: %s", line); + + if ( !clength && !strncasecmp(line, "Content-Length: ", 16) ) + clength = atoi(line+16); + + if (!*method) { + if ( !strncmp(line,"POST",4) ) { + strncpy(method, line, 4); + } else if ( !strncmp(line,"GET",3)) { + if ( strlen(line) > 14 ) { + /* GET / HTTP/1.1 ---- this is bad */ + /* GET /?Action=Ping&ActionID=Foo HTTP/1.1 */ + strncpy(method, line, 3); + memcpy(formdata, line+6, strstr(line, " HTTP")-line-6); + sprintf(status, "200 OK"); + } else + sprintf(status, "501 Not Implemented"); + } + } + } else if (res == 0) { + /* x-www-form-urlencoded handler */ + /* Content-Type: application/x-www-form-urlencoded */ + if (*method && !*formdata) { + if ( !strcasecmp(method, "POST") && clength && s->inlen==clength) { + pthread_mutex_lock(&s->lock); + strncpy(formdata, s->inbuf, clength); + s->inlen = 0; + pthread_mutex_unlock(&s->lock); + sprintf(status, "200 OK"); + } + } } - } else if (res == 0) { - /* x-www-form-urlencoded handler */ - /* Content-Type: application/x-www-form-urlencoded */ - if (*method && !*formdata) { - if ( !strcasecmp(method, "POST") && clength && s->inlen==clength) { - pthread_mutex_lock(&s->lock); - strncpy(formdata, s->inbuf, clength); - s->inlen = 0; - pthread_mutex_unlock(&s->lock); - sprintf(status, "200 OK"); - } - } - } - - if (res < 0) - break; - - if (*status) { - HTTPHeader(s, status); - - /* now, let's transform and copy into a standard message block */ - if (!strcmp("200 OK", status) ) { - URLDecode(formdata); - res = ParseHTTPInput(formdata, m); - return res; - } else { - pthread_mutex_lock(&s->lock); - s->outputcomplete = 1; - pthread_mutex_unlock(&s->lock); - return 0; + + if (res < 0) + break; + + if (*status) { + HTTPHeader(s, status); + + /* now, let's transform and copy into a standard message block */ + if (!strcmp("200 OK", status) ) { + URLDecode(formdata); + res = ParseHTTPInput(formdata, m); + return res; + } else { + pthread_mutex_lock(&s->lock); + s->outputcomplete = 1; + pthread_mutex_unlock(&s->lock); + return 0; + } } } - } - return -1; + return -1; } /* We do not define a _write or _onconnect method */ diff --git a/src/include/astmanproxy.h b/src/include/astmanproxy.h index 9d8ed89..b7d1629 100644 --- a/src/include/astmanproxy.h +++ b/src/include/astmanproxy.h @@ -19,101 +19,101 @@ #include #include #ifdef __APPLE__ - #include "poll-compat.h" + #include "poll-compat.h" #else - #include + #include #endif -#define BUFSIZE 1024 -#define MAX_HEADERS 256 -#define MAX_LEN 1024 +#define BUFSIZE 1024 +#define MAX_HEADERS 256 +#define MAX_LEN 1024 -#define PROXY_BANNER "Asterisk Call Manager Proxy" +#define PROXY_BANNER "Asterisk Call Manager Proxy" #define PROXY_SHUTDOWN "ProxyMessage: Proxy Shutting Down" -#define ACTION_ID "ActionID" +#define ACTION_ID "ActionID" struct ast_server { - char nickname[80]; - char ast_host[40]; - char ast_port[10]; - char ast_user[80]; - char ast_pass[80]; - char ast_events[10]; - int use_ssl; /* Use SSL when Connecting to Server? */ - int status; /* TODO: have this mean something */ - struct ast_server *next; + char nickname[80]; + char ast_host[40]; + char ast_port[10]; + char ast_user[80]; + char ast_pass[80]; + char ast_events[10]; + int use_ssl; /* Use SSL when Connecting to Server? */ + int status; /* TODO: have this mean something */ + struct ast_server *next; }; struct proxy_user { - char username[80]; - char secret[80]; - char channel[80]; - char icontext[80]; - char ocontext[80]; - struct proxy_user *next; + char username[80]; + char secret[80]; + char channel[80]; + char icontext[80]; + char ocontext[80]; + struct proxy_user *next; }; struct proxyconfig { - struct ast_server *serverlist; - struct proxy_user *userlist; - char listen_addr[INET_ADDRSTRLEN]; - int listen_port; - char inputformat[80]; - char outputformat[80]; - int autofilter; /* enable autofiltering? */ - int authrequired; /* is authentication required? */ - char key[80]; - char proc_user[40]; - char proc_group[40]; - char logfile[256]; - int retryinterval; - int maxretries; - int asteriskwritetimeout; /* ms to wait when writing to asteriskfor ast_carefulwrite */ - int clientwritetimeout; /* ms to wait when writing to client ast_carefulwrite */ - int sslclhellotimeout; /* ssl client hello timeout -- how long to wait before assuming not ssl */ - int acceptencryptedconnection; /* accept encrypted connections? */ - int acceptunencryptedconnection; /* accept unencrypted connections? */ - char certfile[256]; /* our SERVER-side SSL certificate file */ + struct ast_server *serverlist; + struct proxy_user *userlist; + char listen_addr[INET_ADDRSTRLEN]; + int listen_port; + char inputformat[80]; + char outputformat[80]; + int autofilter; /* enable autofiltering? */ + int authrequired; /* is authentication required? */ + char key[80]; + char proc_user[40]; + char proc_group[40]; + char logfile[256]; + int retryinterval; + int maxretries; + int asteriskwritetimeout; /* ms to wait when writing to asteriskfor ast_carefulwrite */ + int clientwritetimeout; /* ms to wait when writing to client ast_carefulwrite */ + int sslclhellotimeout; /* ssl client hello timeout -- how long to wait before assuming not ssl */ + int acceptencryptedconnection; /* accept encrypted connections? */ + int acceptunencryptedconnection; /* accept unencrypted connections? */ + char certfile[256]; /* our SERVER-side SSL certificate file */ }; struct iohandler { - int (*read) (); - int (*write) (); - int (*onconnect) (); - char formatname[80]; - void *dlhandle; - struct iohandler *next; + int (*read) (); + int (*write) (); + int (*onconnect) (); + char formatname[80]; + void *dlhandle; + struct iohandler *next; }; struct mansession { - pthread_t t; - pthread_mutex_t lock; - struct sockaddr_in sin; - int fd; - char inbuf[MAX_LEN]; - int inlen; - struct iohandler *input; - struct iohandler *output; - int autofilter; - int authenticated; - int connected; - int dead; /* Whether we are dead */ - int busy; /* Whether we are busy */ - int inputcomplete; /* Whether we want any more input from this session (http) */ - int outputcomplete; /* Whether output to this session is done (http) */ - struct ast_server *server; - struct proxy_user user; - char actionid[MAX_LEN]; - char challenge[10]; /*! Authentication challenge */ - int writetimeout; /* Timeout for ast_carefulwrite() */ - struct mansession *next; + pthread_t t; + pthread_mutex_t lock; + struct sockaddr_in sin; + int fd; + char inbuf[MAX_LEN]; + int inlen; + struct iohandler *input; + struct iohandler *output; + int autofilter; + int authenticated; + int connected; + int dead; /* Whether we are dead */ + int busy; /* Whether we are busy */ + int inputcomplete; /* Whether we want any more input from this session (http) */ + int outputcomplete; /* Whether output to this session is done (http) */ + struct ast_server *server; + struct proxy_user user; + char actionid[MAX_LEN]; + char challenge[10]; /*! Authentication challenge */ + int writetimeout; /* Timeout for ast_carefulwrite() */ + struct mansession *next; }; struct message { - int hdrcount; - char headers[MAX_HEADERS][MAX_LEN]; - int in_command; - struct mansession *session; + int hdrcount; + char headers[MAX_HEADERS][MAX_LEN]; + int in_command; + struct mansession *session; }; struct proxyconfig pc; diff --git a/src/log.c b/src/log.c index d3f8d15..fc86643 100644 --- a/src/log.c +++ b/src/log.c @@ -1,6 +1,16 @@ +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + log.c + Log & debug routines +*/ + #include "astmanproxy.h" -#define DATEFORMAT "%b %e %T" +#define DATEFORMAT "%b %e %T" extern FILE *proxylog; extern int debug; @@ -9,49 +19,49 @@ extern pthread_mutex_t debuglock; void debugmsg (const char *fmt, ...) { - va_list ap; - - time_t t; - struct tm tm; - char date[80]; - - if (!debug) - return; - - time(&t); - localtime_r(&t, &tm); - strftime(date, sizeof(date), DATEFORMAT, &tm); - - pthread_mutex_lock(&debuglock); - va_start(ap, fmt); - printf("%s: ", date); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - pthread_mutex_unlock(&debuglock); + va_list ap; + + time_t t; + struct tm tm; + char date[80]; + + if (!debug) + return; + + time(&t); + localtime_r(&t, &tm); + strftime(date, sizeof(date), DATEFORMAT, &tm); + + pthread_mutex_lock(&debuglock); + va_start(ap, fmt); + printf("%s: ", date); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); + pthread_mutex_unlock(&debuglock); } void logmsg (const char *fmt, ...) { - va_list ap; - - time_t t; - struct tm tm; - char date[80]; - - time(&t); - localtime_r(&t, &tm); - strftime(date, sizeof(date), DATEFORMAT, &tm); - - if (proxylog) { - pthread_mutex_lock(&loglock); - va_start(ap, fmt); - fprintf(proxylog, "%s: ", date); - vfprintf(proxylog, fmt, ap); - fprintf(proxylog, "\n"); - va_end(ap); - fflush(proxylog); - pthread_mutex_unlock(&loglock); - } + va_list ap; + + time_t t; + struct tm tm; + char date[80]; + + time(&t); + localtime_r(&t, &tm); + strftime(date, sizeof(date), DATEFORMAT, &tm); + + if (proxylog) { + pthread_mutex_lock(&loglock); + va_start(ap, fmt); + fprintf(proxylog, "%s: ", date); + vfprintf(proxylog, fmt, ap); + fprintf(proxylog, "\n"); + va_end(ap); + fflush(proxylog); + pthread_mutex_unlock(&loglock); + } } diff --git a/src/poll.c b/src/poll.c index a36539a..4e7cda3 100644 --- a/src/poll.c +++ b/src/poll.c @@ -72,12 +72,12 @@ \*---------------------------------------------------------------------------*/ #include /* standard Unix definitions */ -#include /* system types */ -#include /* time definitions */ -#include /* assertion macros */ -#include /* string functions */ +#include /* system types */ +#include /* time definitions */ +#include /* assertion macros */ +#include /* string functions */ -#include "poll-compat.h" /* this package */ +#include "poll-compat.h" /* this package */ /*---------------------------------------------------------------------------*\ Macros @@ -96,21 +96,21 @@ static int map_poll_spec #if __STDC__ > 0 (struct pollfd *pArray, unsigned long n_fds, - fd_set *pReadSet, - fd_set *pWriteSet, - fd_set *pExceptSet) + fd_set *pReadSet, + fd_set *pWriteSet, + fd_set *pExceptSet) #else (pArray, n_fds, pReadSet, pWriteSet, pExceptSet) struct pollfd *pArray; unsigned long n_fds; - fd_set *pReadSet; - fd_set *pWriteSet; - fd_set *pExceptSet; + fd_set *pReadSet; + fd_set *pWriteSet; + fd_set *pExceptSet; #endif { - register unsigned long i; /* loop control */ - register struct pollfd *pCur; /* current array element */ - register int max_fd = -1; /* return value */ + register unsigned long i; /* loop control */ + register struct pollfd *pCur; /* current array element */ + register int max_fd = -1; /* return value */ /* Map the poll() structures into the file descriptor sets required @@ -118,10 +118,10 @@ static int map_poll_spec */ for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { - /* Skip any bad FDs in the array. */ + /* Skip any bad FDs in the array. */ - if (pCur->fd < 0) - continue; + if (pCur->fd < 0) + continue; if (pCur->events & POLLIN) { @@ -155,7 +155,7 @@ static struct timeval *map_timeout (int poll_timeout, struct timeval *pSelTimeout) #else (poll_timeout, pSelTimeout) - int poll_timeout; + int poll_timeout; struct timeval *pSelTimeout; #endif { @@ -168,7 +168,7 @@ static struct timeval *map_timeout VALUE MEANING -1 wait indefinitely (until signal occurs) - 0 return immediately, don't block + 0 return immediately, don't block >0 wait specified number of milliseconds select() uses a "struct timeval", which specifies the timeout in @@ -200,7 +200,7 @@ static struct timeval *map_timeout default: /* Wait the specified number of milliseconds. */ pSelTimeout->tv_sec = poll_timeout / 1000; /* get seconds */ - poll_timeout %= 1000; /* remove seconds */ + poll_timeout %= 1000; /* remove seconds */ pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */ pResult = pSelTimeout; break; @@ -214,27 +214,27 @@ static void map_select_results #if __STDC__ > 0 (struct pollfd *pArray, unsigned long n_fds, - fd_set *pReadSet, - fd_set *pWriteSet, - fd_set *pExceptSet) + fd_set *pReadSet, + fd_set *pWriteSet, + fd_set *pExceptSet) #else (pArray, n_fds, pReadSet, pWriteSet, pExceptSet) struct pollfd *pArray; unsigned long n_fds; - fd_set *pReadSet; - fd_set *pWriteSet; - fd_set *pExceptSet; + fd_set *pReadSet; + fd_set *pWriteSet; + fd_set *pExceptSet; #endif { - register unsigned long i; /* loop control */ - register struct pollfd *pCur; /* current array element */ + register unsigned long i; /* loop control */ + register struct pollfd *pCur; /* current array element */ for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { - /* Skip any bad FDs in the array. */ + /* Skip any bad FDs in the array. */ - if (pCur->fd < 0) - continue; + if (pCur->fd < 0) + continue; /* Exception events take priority over input events. */ @@ -268,13 +268,13 @@ int poll #endif { - fd_set read_descs; /* input file descs */ - fd_set write_descs; /* output file descs */ - fd_set except_descs; /* exception descs */ - struct timeval stime; /* select() timeout value */ - int ready_descriptors; /* function result */ - int max_fd; /* maximum fd value */ - struct timeval *pTimeout; /* actually passed */ + fd_set read_descs; /* input file descs */ + fd_set write_descs; /* output file descs */ + fd_set except_descs; /* exception descs */ + struct timeval stime; /* select() timeout value */ + int ready_descriptors; /* function result */ + int max_fd; /* maximum fd value */ + struct timeval *pTimeout; /* actually passed */ FD_ZERO (&read_descs); FD_ZERO (&write_descs); diff --git a/src/proxyfunc.c b/src/proxyfunc.c index 434baff..484da78 100644 --- a/src/proxyfunc.c +++ b/src/proxyfunc.c @@ -1,3 +1,13 @@ +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy + + This program is free software, distributed under the terms of + the GNU General Public License. + + proxyfunc.c + Functions specific to the manager proxy, not found in standard Asterisk AMI +*/ + #include "astmanproxy.h" #include "md5.h" @@ -7,384 +17,382 @@ extern pthread_mutex_t serverlock; extern pthread_mutex_t userslock; void *ProxyListIOHandlers(struct mansession *s) { - struct message m; - struct iohandler *i; - - memset(&m, 0, sizeof(struct message)); - AddHeader(&m, "ProxyResponse: Success"); - - i = iohandlers; - while (i && (m.hdrcount < MAX_HEADERS - 1) ) { - if (i->read) - AddHeader(&m, "InputHandler: %s", i->formatname); - if (i->write) - AddHeader(&m, "OutputHandler: %s", i->formatname); - i = i->next; - } - - s->output->write(s, &m); - return 0; + struct message m; + struct iohandler *i; + + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "ProxyResponse: Success"); + + i = iohandlers; + while (i && (m.hdrcount < MAX_HEADERS - 1) ) { + if (i->read) + AddHeader(&m, "InputHandler: %s", i->formatname); + if (i->write) + AddHeader(&m, "OutputHandler: %s", i->formatname); + i = i->next; + } + + s->output->write(s, &m); + return 0; } void *ProxyListSessions(struct mansession *s) { - struct message m; - struct mansession *c; - char iabuf[INET_ADDRSTRLEN]; - - memset(&m, 0, sizeof(struct message)); - AddHeader(&m, "ProxyResponse: Success"); - - c = sessions; - while (c && (m.hdrcount < MAX_HEADERS - 1) ) { - if (!c->server) { - AddHeader(&m, "ProxyClientSession: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr), c->actionid); - AddHeader(&m, "ProxyClientInputHandler: %s", c->input->formatname); - AddHeader(&m, "ProxyClientOutputHandler: %s", c->output->formatname); - } else - AddHeader(&m, "ProxyServerSession: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); - c = c->next; - } - s->output->write(s, &m); - return 0; + struct message m; + struct mansession *c; + char iabuf[INET_ADDRSTRLEN]; + + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "ProxyResponse: Success"); + + c = sessions; + while (c && (m.hdrcount < MAX_HEADERS - 1) ) { + if (!c->server) { + AddHeader(&m, "ProxyClientSession: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr), c->actionid); + AddHeader(&m, "ProxyClientInputHandler: %s", c->input->formatname); + AddHeader(&m, "ProxyClientOutputHandler: %s", c->output->formatname); + } else + AddHeader(&m, "ProxyServerSession: %s", ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr)); + c = c->next; + } + s->output->write(s, &m); + return 0; } void *ProxySetOutputFormat(struct mansession *s, struct message *m) { - struct message mo; - char *value; + struct message mo; + char *value; - value = astman_get_header(m, "OutputFormat"); - SetIOHandlers(s, s->input->formatname, value); + value = astman_get_header(m, "OutputFormat"); + SetIOHandlers(s, s->input->formatname, value); - memset(&mo, 0, sizeof(struct message)); - AddHeader(&mo, "ProxyResponse: Success"); - AddHeader(&mo, "OutputFormat: %s", s->output->formatname ); + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "ProxyResponse: Success"); + AddHeader(&mo, "OutputFormat: %s", s->output->formatname ); - s->output->write(s, &mo); + s->output->write(s, &mo); - return 0; + return 0; } int ProxyChallenge(struct mansession *s, struct message *m) { - struct message mo; + struct message mo; - if ( strcasecmp("MD5", astman_get_header(m, "AuthType")) ) { - SendError(s, "Must specify AuthType"); - return 1; - } + if ( strcasecmp("MD5", astman_get_header(m, "AuthType")) ) { + SendError(s, "Must specify AuthType"); + return 1; + } - if (!*s->challenge) - snprintf(s->challenge, sizeof(s->challenge), "%d", rand()); + if (!*s->challenge) + snprintf(s->challenge, sizeof(s->challenge), "%d", rand()); - memset(&mo, 0, sizeof(struct message)); - AddHeader(&mo, "Response: Success"); - AddHeader(&mo, "Challenge: %s", s->challenge); + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "Response: Success"); + AddHeader(&mo, "Challenge: %s", s->challenge); - s->output->write(s, &mo); - return 0; + s->output->write(s, &mo); + return 0; } void *ProxySetAutoFilter(struct mansession *s, struct message *m) { - struct message mo; - char *value; - int i; - - value = astman_get_header(m, "AutoFilter"); - if ( !strcasecmp(value, "on") ) - i = 1; - else - i = 0; - pthread_mutex_lock(&s->lock); - s->autofilter = i; - pthread_mutex_unlock(&s->lock); - - memset(&mo, 0, sizeof(struct message)); - AddHeader(&mo, "ProxyResponse: Success"); - AddHeader(&mo, "AutoFilter: %d", s->autofilter); - - s->output->write(s, &mo); - - return 0; + struct message mo; + char *value; + int i; + + value = astman_get_header(m, "AutoFilter"); + if ( !strcasecmp(value, "on") ) + i = 1; + else + i = 0; + pthread_mutex_lock(&s->lock); + s->autofilter = i; + pthread_mutex_unlock(&s->lock); + + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "ProxyResponse: Success"); + AddHeader(&mo, "AutoFilter: %d", s->autofilter); + + s->output->write(s, &mo); + + return 0; } int AuthMD5(char *key, char *challenge, char *password) { - int x; - int len=0; - char md5key[256] = ""; - struct MD5Context md5; - unsigned char digest[16]; + int x; + int len=0; + char md5key[256] = ""; + struct MD5Context md5; + unsigned char digest[16]; - if (!*key || !*challenge || !*password ) + if (!*key || !*challenge || !*password ) return 1; - if (debug) - debugmsg("MD5 password=%s, challenge=%s", password, challenge); - - MD5Init(&md5); - MD5Update(&md5, (unsigned char *) challenge, strlen(challenge)); - MD5Update(&md5, (unsigned char *) password, strlen(password)); - MD5Final(digest, &md5); - for (x=0;x<16;x++) - len += sprintf(md5key + len, "%2.2x", digest[x]); - if( debug ) { - debugmsg("MD5 computed=%s, received=%s", md5key, key); - } - if (!strcmp(md5key, key)) + if (debug) + debugmsg("MD5 password=%s, challenge=%s", password, challenge); + + MD5Init(&md5); + MD5Update(&md5, (unsigned char *) challenge, strlen(challenge)); + MD5Update(&md5, (unsigned char *) password, strlen(password)); + MD5Final(digest, &md5); + for (x=0;x<16;x++) + len += sprintf(md5key + len, "%2.2x", digest[x]); + if( debug ) { + debugmsg("MD5 computed=%s, received=%s", md5key, key); + } + if (!strcmp(md5key, key)) return 0; - else + else return 1; } void *ProxyLogin(struct mansession *s, struct message *m) { - struct message mo; - struct proxy_user *pu; - char *user, *secret, *key; + struct message mo; + struct proxy_user *pu; + char *user, *secret, *key; - user = astman_get_header(m, "Username"); - secret = astman_get_header(m, "Secret"); - key = astman_get_header(m, "Key"); + user = astman_get_header(m, "Username"); + secret = astman_get_header(m, "Secret"); + key = astman_get_header(m, "Key"); - memset(&mo, 0, sizeof(struct message)); - if( debug ) - debugmsg("Login attempt as: %s/%s", user, secret); + memset(&mo, 0, sizeof(struct message)); + if( debug ) + debugmsg("Login attempt as: %s/%s", user, secret); - pthread_mutex_lock(&userslock); - pu = pc.userlist; - while( pu ) { + pthread_mutex_lock(&userslock); + pu = pc.userlist; + while( pu ) { if ( !strcmp(user, pu->username) ) { - if (!AuthMD5(key, s->challenge, pu->secret) || - !strcmp(secret, pu->secret) ) { - AddHeader(&mo, "Response: Success"); - AddHeader(&mo, "Message: Authentication accepted"); - s->output->write(s, &mo); - pthread_mutex_lock(&s->lock); - s->authenticated = 1; - strcpy(s->user.channel, pu->channel); - strcpy(s->user.icontext, pu->icontext); - strcpy(s->user.ocontext, pu->ocontext); - pthread_mutex_unlock(&s->lock); - if( debug ) - debugmsg("Login as: %s", user); - break; - } - } - pu = pu->next; - } - pthread_mutex_unlock(&userslock); - - if( !pu ) { - SendError(s, "Authentication failed"); - pthread_mutex_lock(&s->lock); - s->authenticated = 0; - pthread_mutex_unlock(&s->lock); - if( debug ) - debugmsg("Login failed as: %s/%s", user, secret); - } - - - return 0; + if (!AuthMD5(key, s->challenge, pu->secret) || !strcmp(secret, pu->secret) ) { + AddHeader(&mo, "Response: Success"); + AddHeader(&mo, "Message: Authentication accepted"); + s->output->write(s, &mo); + pthread_mutex_lock(&s->lock); + s->authenticated = 1; + strcpy(s->user.channel, pu->channel); + strcpy(s->user.icontext, pu->icontext); + strcpy(s->user.ocontext, pu->ocontext); + pthread_mutex_unlock(&s->lock); + if( debug ) + debugmsg("Login as: %s", user); + break; + } + } + pu = pu->next; + } + pthread_mutex_unlock(&userslock); + + if( !pu ) { + SendError(s, "Authentication failed"); + pthread_mutex_lock(&s->lock); + s->authenticated = 0; + pthread_mutex_unlock(&s->lock); + if( debug ) + debugmsg("Login failed as: %s/%s", user, secret); + } + + return 0; } void *ProxyLogoff(struct mansession *s) { - struct message m; + struct message m; - memset(&m, 0, sizeof(struct message)); - AddHeader(&m, "Goodbye: Y'all come back now, y'hear?"); + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "Goodbye: Y'all come back now, y'hear?"); - s->output->write(s, &m); + s->output->write(s, &m); - destroy_session(s); - if (debug) - debugmsg("Client logged off - exiting thread"); - pthread_exit(NULL); - return 0; + destroy_session(s); + if (debug) + debugmsg("Client logged off - exiting thread"); + pthread_exit(NULL); + return 0; } int ProxyAddServer(struct mansession *s, struct message *m) { - struct message mo; - struct ast_server *srv; - int res = 0; - - /* malloc ourselves a server credentials structure */ - srv = malloc(sizeof(struct ast_server)); - if ( !srv ) { - fprintf(stderr, "Failed to allocate server credentials: %s\n", strerror(errno)); - exit(1); - } - - memset(srv, 0, sizeof(struct ast_server) ); - memset(&mo, 0, sizeof(struct message)); - strcpy(srv->ast_host, astman_get_header(m, "Server")); - strcpy(srv->ast_user, astman_get_header(m, "Username")); - strcpy(srv->ast_pass, astman_get_header(m, "Secret")); - strcpy(srv->ast_port, astman_get_header(m, "Port")); - strcpy(srv->ast_events, astman_get_header(m, "Events")); - - if (*srv->ast_host && *srv->ast_user && *srv->ast_pass && *srv->ast_port && *srv->ast_events) { - pthread_mutex_lock(&serverlock); - srv->next = pc.serverlist; - pc.serverlist = srv; - pthread_mutex_unlock(&serverlock); - res = StartServer(srv); - } else - res = 1; - - if (res) { - AddHeader(&mo, "ProxyResponse: Failure"); - AddHeader(&mo, "Message: Could not add %s", srv->ast_host); - } else { - AddHeader(&mo, "ProxyResponse: Success"); - AddHeader(&mo, "Message: Added %s", srv->ast_host); - } - - s->output->write(s, &mo); - return 0; + struct message mo; + struct ast_server *srv; + int res = 0; + + /* malloc ourselves a server credentials structure */ + srv = malloc(sizeof(struct ast_server)); + if ( !srv ) { + fprintf(stderr, "Failed to allocate server credentials: %s\n", strerror(errno)); + exit(1); + } + + memset(srv, 0, sizeof(struct ast_server) ); + memset(&mo, 0, sizeof(struct message)); + strcpy(srv->ast_host, astman_get_header(m, "Server")); + strcpy(srv->ast_user, astman_get_header(m, "Username")); + strcpy(srv->ast_pass, astman_get_header(m, "Secret")); + strcpy(srv->ast_port, astman_get_header(m, "Port")); + strcpy(srv->ast_events, astman_get_header(m, "Events")); + + if (*srv->ast_host && *srv->ast_user && *srv->ast_pass && *srv->ast_port && *srv->ast_events) { + pthread_mutex_lock(&serverlock); + srv->next = pc.serverlist; + pc.serverlist = srv; + pthread_mutex_unlock(&serverlock); + res = StartServer(srv); + } else + res = 1; + + if (res) { + AddHeader(&mo, "ProxyResponse: Failure"); + AddHeader(&mo, "Message: Could not add %s", srv->ast_host); + } else { + AddHeader(&mo, "ProxyResponse: Success"); + AddHeader(&mo, "Message: Added %s", srv->ast_host); + } + + s->output->write(s, &mo); + return 0; } int ProxyDropServer(struct mansession *s, struct message *m) { - struct message mo; - struct mansession *srv; - char *value; - int res; - - memset(&mo, 0, sizeof(struct message)); - value = astman_get_header(m, "Server"); - srv = sessions; - while (*value && srv) { - if (srv->server && !strcmp(srv->server->ast_host, value)) - break; - srv = srv->next; - } - - if (srv) { - destroy_session(srv); - debugmsg("Dropping Server %s", value); - AddHeader(&mo, "ProxyResponse: Success"); - AddHeader(&mo, "Message: Dropped %s", value); - res = 0; - } else { - debugmsg("Failed to Drop Server %s -- not found", value); - AddHeader(&mo, "ProxyResponse: Failure"); - AddHeader(&mo, "Message: Cannot Drop Server %s, Does Not Exist", value); - res = 1; - } - - s->output->write(s, &mo); - return res; + struct message mo; + struct mansession *srv; + char *value; + int res; + + memset(&mo, 0, sizeof(struct message)); + value = astman_get_header(m, "Server"); + srv = sessions; + while (*value && srv) { + if (srv->server && !strcmp(srv->server->ast_host, value)) + break; + srv = srv->next; + } + + if (srv) { + destroy_session(srv); + debugmsg("Dropping Server %s", value); + AddHeader(&mo, "ProxyResponse: Success"); + AddHeader(&mo, "Message: Dropped %s", value); + res = 0; + } else { + debugmsg("Failed to Drop Server %s -- not found", value); + AddHeader(&mo, "ProxyResponse: Failure"); + AddHeader(&mo, "Message: Cannot Drop Server %s, Does Not Exist", value); + res = 1; + } + + s->output->write(s, &mo); + return res; } void *ProxyListServers(struct mansession *s) { - struct message m; - struct mansession *c; - char iabuf[INET_ADDRSTRLEN]; - - memset(&m, 0, sizeof(struct message)); - AddHeader(&m, "ProxyResponse: Success"); - - c = sessions; - while (c) { - if (c->server) { - AddHeader(&m, "ProxyListServer I: %s H: %s U: %s P: %s E: %s ", - ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr), - c->server->ast_host, c->server->ast_user, - c->server->ast_port, c->server->ast_events); - } - - c = c->next; - } - s->output->write(s, &m); - return 0; + struct message m; + struct mansession *c; + char iabuf[INET_ADDRSTRLEN]; + + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "ProxyResponse: Success"); + + c = sessions; + while (c) { + if (c->server) { + AddHeader(&m, "ProxyListServer I: %s H: %s U: %s P: %s E: %s ", + ast_inet_ntoa(iabuf, sizeof(iabuf), c->sin.sin_addr), + c->server->ast_host, c->server->ast_user, + c->server->ast_port, c->server->ast_events); + } + + c = c->next; + } + s->output->write(s, &m); + return 0; } void *proxyaction_do(char *proxyaction, struct message *m, struct mansession *s) { - if (!strcasecmp(proxyaction,"SetOutputFormat")) - ProxySetOutputFormat(s, m); - else if (!strcasecmp(proxyaction,"SetAutoFilter")) - ProxySetAutoFilter(s, m); - else if (!strcasecmp(proxyaction,"ListSessions")) - ProxyListSessions(s); - else if (!strcasecmp(proxyaction,"AddServer")) - ProxyAddServer(s, m); - else if (!strcasecmp(proxyaction,"DropServer")) - ProxyDropServer(s, m); - else if (!strcasecmp(proxyaction,"ListServers")) - ProxyListServers(s); - else if (!strcasecmp(proxyaction,"ListIOHandlers")) - ProxyListIOHandlers(s); - else if (!strcasecmp(proxyaction,"Logoff")) - ProxyLogoff(s); - else + if (!strcasecmp(proxyaction,"SetOutputFormat")) + ProxySetOutputFormat(s, m); + else if (!strcasecmp(proxyaction,"SetAutoFilter")) + ProxySetAutoFilter(s, m); + else if (!strcasecmp(proxyaction,"ListSessions")) + ProxyListSessions(s); + else if (!strcasecmp(proxyaction,"AddServer")) + ProxyAddServer(s, m); + else if (!strcasecmp(proxyaction,"DropServer")) + ProxyDropServer(s, m); + else if (!strcasecmp(proxyaction,"ListServers")) + ProxyListServers(s); + else if (!strcasecmp(proxyaction,"ListIOHandlers")) + ProxyListIOHandlers(s); + else if (!strcasecmp(proxyaction,"Logoff")) + ProxyLogoff(s); + else proxyerror_do(s, "Invalid Proxy Action"); - return 0; + return 0; } int proxyerror_do(struct mansession *s, char *err) { - struct message mo; + struct message mo; - memset(&mo, 0, sizeof(struct message)); - AddHeader(&mo, "ProxyResponse: Error"); - AddHeader(&mo, "Message: %s", err); + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "ProxyResponse: Error"); + AddHeader(&mo, "Message: %s", err); - s->output->write(s, &mo); + s->output->write(s, &mo); - return 0; + return 0; } int ValidateAction(struct message *m, struct mansession *s, int inbound) { - char *channel, *channel1, *channel2; - char *context; - char *uchannel; - char *ucontext; - - if( pc.authrequired && !s->authenticated ) - return 0; - - if( inbound ) - ucontext = s->user.icontext; - else - ucontext = s->user.ocontext; - uchannel = s->user.channel; - - channel = astman_get_header(m, "Channel"); - if( channel[0] != '\0' && uchannel[0] != '\0' ) - if( strncasecmp( channel, uchannel, strlen(uchannel) ) ) { - if( debug ) - debugmsg("Message filtered (chan): %s != %s", channel, uchannel); - return 0; - } - - channel1 = astman_get_header(m, "Channel1"); - channel2 = astman_get_header(m, "Channel2"); - if( (channel1[0] != '\0' || channel2[0] != '\0') && uchannel[0] != '\0' ) - if( !(strncasecmp( channel1, uchannel, strlen(uchannel) ) == 0 || - strncasecmp( channel2, uchannel, strlen(uchannel) ) == 0) ) { - if( debug ) - debugmsg("Message filtered (chan): %s/%s != %s", channel1, channel2, uchannel); - return 0; - } - - context = astman_get_header(m, "Context"); - if( context[0] != '\0' && ucontext[0] != '\0' ) - if( strcasecmp( context, ucontext ) ) { - if( debug ) - debugmsg("Message filtered (ctxt): %s != %s", context, ucontext); - return 0; - } - - return 1; + char *channel, *channel1, *channel2; + char *context; + char *uchannel; + char *ucontext; + + if( pc.authrequired && !s->authenticated ) + return 0; + + if( inbound ) + ucontext = s->user.icontext; + else + ucontext = s->user.ocontext; + uchannel = s->user.channel; + + channel = astman_get_header(m, "Channel"); + if( channel[0] != '\0' && uchannel[0] != '\0' ) + if( strncasecmp( channel, uchannel, strlen(uchannel) ) ) { + if( debug ) + debugmsg("Message filtered (chan): %s != %s", channel, uchannel); + return 0; + } + + channel1 = astman_get_header(m, "Channel1"); + channel2 = astman_get_header(m, "Channel2"); + if( (channel1[0] != '\0' || channel2[0] != '\0') && uchannel[0] != '\0' ) + if( !(strncasecmp( channel1, uchannel, strlen(uchannel) ) == 0 || + strncasecmp( channel2, uchannel, strlen(uchannel) ) == 0) ) { + if( debug ) + debugmsg("Message filtered (chan): %s/%s != %s", channel1, channel2, uchannel); + return 0; + } + + context = astman_get_header(m, "Context"); + if( context[0] != '\0' && ucontext[0] != '\0' ) + if( strcasecmp( context, ucontext ) ) { + if( debug ) + debugmsg("Message filtered (ctxt): %s != %s", context, ucontext); + return 0; + } + + return 1; } void *SendError(struct mansession *s, char *errmsg) { - struct message m; + struct message m; - memset(&m, 0, sizeof(struct message)); - AddHeader(&m, "Response: Error"); - AddHeader(&m, "Message: %s", errmsg); + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "Response: Error"); + AddHeader(&m, "Message: %s", errmsg); - s->output->write(s, &m); + s->output->write(s, &m); - return 0; + return 0; } diff --git a/src/ssl.c b/src/ssl.c index 19b9828..40115b1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -14,24 +14,8 @@ * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. - */ -/*! \file - * - * \brief SSL for The Asterisk Management Interface - AMI - * - * Channel Management and more - * - * \author Remco Treffkorn(Architect) and Mahesh Karoshi(Senior Software Developer) - * \ref amiconf - */ - -/*! \addtogroup Group_AMI AMI functions -*/ -/*! @{ - Doxygen group */ - -/*! \note We use negative file descriptors for secure channels. The file descriptor + We use negative file descriptors for secure channels. The file descriptor -1 is reseved for errors. -2 to -... are secure file descriptors. 0 to ... are regular file descriptors. @@ -66,7 +50,7 @@ static int ssl_initialized; Initializes all the ssl related stuff here. */ int init_secure(char *certfile) { - SSL_METHOD *meth; + SSL_METHOD *meth; SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); @@ -95,23 +79,23 @@ int init_secure(char *certfile) } -/* Initializes all the client-side ssl related stuff here. +/* Initializes all the client-side ssl related stuff here. */ int client_init_secure(void) { - SSL_METHOD *meth; + SSL_METHOD *meth; - /* client init */ - SSLeay_add_ssl_algorithms(); - meth = SSLv23_client_method(); - SSL_load_error_strings(); - cctx = SSL_CTX_new (meth); + /* client init */ + SSLeay_add_ssl_algorithms(); + meth = SSLv23_client_method(); + SSL_load_error_strings(); + cctx = SSL_CTX_new (meth); - if (!cctx) - debugmsg("Failed to create a client ssl context!"); + if (!cctx) + debugmsg("Failed to create a client ssl context!"); else debugmsg("Client SSL Context Initialized"); - return 0; + return 0; } /*! \brief Takes the negative ssl fd and returns the positive fd recieved from the os. @@ -122,16 +106,16 @@ int get_real_fd(int fd) if (fd<-1) { fd = -fd - 2; if (fd>=0 && fd 0) { - /* check for sslv3 or tls*/ - if ((buf[0x00] == 0x16) && (buf[0x01] == 0x03) && + fd_set listeners; + struct timeval tv; + char buf[1024]; + int ready_fdescriptors; + int ret; + + tv.tv_sec = 0; + tv.tv_usec = sslclhellotimeout * 1000; + + FD_ZERO(&listeners); + FD_SET(fd, &listeners); + + ready_fdescriptors = select (fd + 1, &listeners, NULL, NULL, &tv); + + if (ready_fdescriptors < 0 ) { + debugmsg("is_encrypt_request: select returned error, This should not happen:"); + return 0; + } else if (ready_fdescriptors == 0) { + return 0; + } + ret = recv(fd, buf, 100, MSG_PEEK); + if(ret > 0) { + /* check for sslv3 or tls*/ + if ((buf[0x00] == 0x16) && (buf[0x01] == 0x03) && /* for tls buf[0x02] = 0x01 and ssl v3 buf[0x02] = 0x02 */ ((buf[0x02] == 0x00) || (buf[0x02] == 0x01))) { if (debug) - debugmsg("Received a SSL request"); + debugmsg("Received a SSL request"); return 1; /* check for sslv23_client_method */ } else if ((buf[0x02] == 0x01) && (buf[0x03] == 0x03) && (buf[0x04] == 0x01)) { if (debug) - debugmsg("Received a SSL request for SSLv23_client_method()"); + debugmsg("Received a SSL request for SSLv23_client_method()"); return 1; } /* check for sslv2 and return -1 */ else if ((buf[0x02] == 0x01) && (buf[0x03] == 0x00) && (buf[0x04] == 0x02)) { if (debug) - debugmsg("Received a SSLv2 request()"); - return -1; + debugmsg("Received a SSLv2 request()"); + return -1; } - } - return 0; + } + return 0; } /* Connects to an asterisk server either plain or SSL as appropriate */ int ast_connect(struct mansession *a) { - int s, err=-1, fd; - SSL* ssl; - - fd = connect_nonb(a); - if ( fd < 0 ) - return -1; - - if (a->server->use_ssl) { - debugmsg("initiating ssl connection"); - if ((s=sec_getslot())!=-1) { /* find a slot for the ssl handle */ - sec_channel[s].fd = fd; /* remember the real fd */ - - if((ssl=SSL_new(cctx))) { /* get a new ssl */ - sec_channel[s].ssl = ssl; - SSL_set_fd(ssl, fd); /* and attach the real fd */ - err = SSL_connect(ssl); /* now try and connect */ - } else + int s, err=-1, fd; + SSL* ssl; + + fd = connect_nonb(a); + if ( fd < 0 ) + return -1; + + if (a->server->use_ssl) { + debugmsg("initiating ssl connection"); + if ((s=sec_getslot())!=-1) { /* find a slot for the ssl handle */ + sec_channel[s].fd = fd; /* remember the real fd */ + + if((ssl=SSL_new(cctx))) { /* get a new ssl */ + sec_channel[s].ssl = ssl; + SSL_set_fd(ssl, fd); /* and attach the real fd */ + err = SSL_connect(ssl); /* now try and connect */ + } else debugmsg("couldn't create ssl client context"); - fd = -(s+2); /* offset by two and negate */ - /* this tells us it is a ssl fd */ - } else + fd = -(s+2); /* offset by two and negate */ + /* this tells us it is a ssl fd */ + } else debugmsg("couldn't get SSL slot!"); - if (err==-1) { - close_sock(fd); /* that frees the ssl too */ - fd = -1; - } - } + if (err==-1) { + close_sock(fd); /* that frees the ssl too */ + fd = -1; + } + } - debugmsg("returning ast_connect with %d", fd); - pthread_mutex_lock(&a->lock); - a->fd = fd; - pthread_mutex_unlock(&a->lock); + debugmsg("returning ast_connect with %d", fd); + pthread_mutex_lock(&a->lock); + a->fd = fd; + pthread_mutex_unlock(&a->lock); - return fd; + return fd; } int connect_nonb(struct mansession *a) { - int flags, n, error; - socklen_t len; - fd_set rset, wset; - struct timeval tval; + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; int nsec = 1, sockfd; sockfd = get_real_fd(a->fd); - flags = fcntl(sockfd, F_GETFL, 0); - fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - error = 0; - if ( (n = connect(sockfd, (struct sockaddr *) &a->sin, sizeof(a->sin)) ) < 0 ) { + error = 0; + if ( (n = connect(sockfd, (struct sockaddr *) &a->sin, sizeof(a->sin)) ) < 0 ) { /* TODO: This seems like the nine pound hammer to me... */ /* perhaps something a bit more elegant; errno seems to change too */ if (errno == EISCONN || errno == 103 || errno==111) { @@ -394,45 +378,45 @@ int connect_nonb(struct mansession *a) pthread_mutex_unlock(&a->lock); return(-1); } - if (errno != EINPROGRESS) - return(-1); + if (errno != EINPROGRESS) + return(-1); } - /* Do whatever we want while the connect is taking place. */ - - if (n == 0) - goto done; /* connect completed immediately */ - - FD_ZERO(&rset); - FD_SET(sockfd, &rset); - wset = rset; - tval.tv_sec = nsec; - tval.tv_usec = 0; - - if ( (n = select(sockfd+1, &rset, &wset, NULL, - nsec ? &tval : NULL)) == 0) { - /*close(sockfd);*/ /* we want to retry */ - errno = ETIMEDOUT; - return(-1); - } - - if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { - len = sizeof(error); - if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) - return(-1); /* Solaris pending error */ - } else { - /*err_quit("select error: sockfd not set");*/ - logmsg("select error: sockfd not set"); - return(-1); - } + /* Do whatever we want while the connect is taking place. */ + + if (n == 0) + goto done; /* connect completed immediately */ + + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + wset = rset; + tval.tv_sec = nsec; + tval.tv_usec = 0; + + if ( (n = select(sockfd+1, &rset, &wset, NULL, + nsec ? &tval : NULL)) == 0) { + /*close(sockfd);*/ /* we want to retry */ + errno = ETIMEDOUT; + return(-1); + } + + if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + len = sizeof(error); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) + return(-1); /* Solaris pending error */ + } else { + /*err_quit("select error: sockfd not set");*/ + logmsg("select error: sockfd not set"); + return(-1); + } done: - fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ - - if (error) { - /* close(sockfd); */ /* disable for now, we want to retry... */ - errno = error; - return(-1); - } - return(sockfd); + fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ + + if (error) { + /* close(sockfd); */ /* disable for now, we want to retry... */ + errno = error; + return(-1); + } + return(sockfd); } diff --git a/src/standard.c b/src/standard.c index 9e8f200..f377bec 100644 --- a/src/standard.c +++ b/src/standard.c @@ -1,10 +1,11 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005 David C. Troy +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy - This program is free software, distributed under the terms of - the GNU General Public License. + This program is free software, distributed under the terms of + the GNU General Public License. - Standard I/O Handler + standard.c + Standard I/O Handler */ #include "astmanproxy.h" @@ -13,58 +14,57 @@ extern struct mansession *sessions; /* Return a fully formed message block to session_do for processing */ int _read(struct mansession *s, struct message *m) { - int res; - - for (;;) { - res = get_input(s, m->headers[m->hdrcount]); - - /*fprintf(stderr, "-------> %s\n", m->headers[m->hdrcount]);*/ - if (strstr(m->headers[m->hdrcount], "--END COMMAND--")) { - if (debug) debugmsg("Found END COMMAND"); - m->in_command = 0; - } - if (strstr(m->headers[m->hdrcount], "Response: Follows")) { - if (debug) debugmsg("Found Response Follows"); - m->in_command = 1; - } - if (res > 0) { - if (!m->in_command && *(m->headers[m->hdrcount]) == '\0' ) { - break; - } else if (m->hdrcount < MAX_HEADERS - 1) { - m->hdrcount++; - } else { - m->in_command = 0; // reset when block full - } - } else if (res < 0) - break; - } - - return res; + int res; + + for (;;) { + res = get_input(s, m->headers[m->hdrcount]); + + if (strstr(m->headers[m->hdrcount], "--END COMMAND--")) { + if (debug) debugmsg("Found END COMMAND"); + m->in_command = 0; + } + if (strstr(m->headers[m->hdrcount], "Response: Follows")) { + if (debug) debugmsg("Found Response Follows"); + m->in_command = 1; + } + if (res > 0) { + if (!m->in_command && *(m->headers[m->hdrcount]) == '\0' ) { + break; + } else if (m->hdrcount < MAX_HEADERS - 1) { + m->hdrcount++; + } else { + m->in_command = 0; // reset when block full + } + } else if (res < 0) + break; + } + + return res; } int _write(struct mansession *s, struct message *m) { - int i; + int i; - pthread_mutex_lock(&s->lock); - for (i=0; ihdrcount; i++) { + pthread_mutex_lock(&s->lock); + for (i=0; ihdrcount; i++) { ast_carefulwrite(s->fd, m->headers[i], strlen(m->headers[i]) , s->writetimeout); - ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); - } - ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); - pthread_mutex_unlock(&s->lock); + ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); + } + ast_carefulwrite(s->fd, "\r\n", 2, s->writetimeout); + pthread_mutex_unlock(&s->lock); - return 0; + return 0; } int _onconnect(struct mansession *s, struct message *m) { - char banner[100]; + char banner[100]; - sprintf(banner, "%s/%s\r\n", PROXY_BANNER, PROXY_VERSION); - pthread_mutex_lock(&s->lock); - ast_carefulwrite(s->fd, banner, strlen(banner), s->writetimeout); - pthread_mutex_unlock(&s->lock); + sprintf(banner, "%s/%s\r\n", PROXY_BANNER, PROXY_VERSION); + pthread_mutex_lock(&s->lock); + ast_carefulwrite(s->fd, banner, strlen(banner), s->writetimeout); + pthread_mutex_unlock(&s->lock); - return 0; + return 0; } diff --git a/src/xml.c b/src/xml.c index b5865f0..f068b73 100644 --- a/src/xml.c +++ b/src/xml.c @@ -1,10 +1,11 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005 David C. Troy +/* Asterisk Manager Proxy + Copyright (c) 2005-2006 David C. Troy - This program is free software, distributed under the terms of - the GNU General Public License. + This program is free software, distributed under the terms of + the GNU General Public License. - XML I/O Handler + xml.c + XML I/O Handler */ #include "astmanproxy.h" @@ -21,138 +22,138 @@ int ParseXMLInput(char *xb, struct message *m); int _read(struct mansession *s, struct message *m) { - /* Note: No single line may be longer than MAX_LEN/s->inbuf, as per get_input */ - /* No XML Input may be longer than BUFSIZE */ + /* Note: No single line may be longer than MAX_LEN/s->inbuf, as per get_input */ + /* No XML Input may be longer than BUFSIZE */ - char line[MAX_LEN], xmlbuf[BUFSIZE]; - int res; + char line[MAX_LEN], xmlbuf[BUFSIZE]; + int res; - /* first let's read the whole xml block into our buffer */ - memset(xmlbuf, 0, sizeof xmlbuf); - for (;;) { - memset(line, 0, sizeof line); - res = get_input(s, line); + /* first let's read the whole xml block into our buffer */ + memset(xmlbuf, 0, sizeof xmlbuf); + for (;;) { + memset(line, 0, sizeof line); + res = get_input(s, line); - if (res > 0) { - if (*line == '\0' ) { - break; - } else if (strlen(xmlbuf) < (BUFSIZE - strlen(line)) ) - strcat(xmlbuf, line); - } else if (res < 0) - return res; - } + if (res > 0) { + if (*line == '\0' ) { + break; + } else if (strlen(xmlbuf) < (BUFSIZE - strlen(line)) ) + strcat(xmlbuf, line); + } else if (res < 0) + return res; + } - /* now, let's transform and copy into a standard message block */ - debugmsg("Got xml: %s", xmlbuf); - res = ParseXMLInput(xmlbuf, m); + /* now, let's transform and copy into a standard message block */ + debugmsg("Got xml: %s", xmlbuf); + res = ParseXMLInput(xmlbuf, m); - if (res < 0) - proxyerror_do(s, "Invalid XML Input"); + if (res < 0) + proxyerror_do(s, "Invalid XML Input"); - /* Return res>0 to process block, return res<0 to kill client, res=0, continue */ - return res; + /* Return res>0 to process block, return res<0 to kill client, res=0, continue */ + return res; } void *setdoctag(char *tag, struct mansession *s) { - /* if message came from a server, say so; otherwise it must be from proxy */ - /* right now there is no such thing as client<->client comms */ - if (s && s->server) - strcpy(tag, XML_SERVERTAG); - else - strcpy(tag, XML_PROXYTAG); + /* if message came from a server, say so; otherwise it must be from proxy */ + /* right now there is no such thing as client<->client comms */ + if (s && s->server) + strcpy(tag, XML_SERVERTAG); + else + strcpy(tag, XML_PROXYTAG); - return 0; + return 0; } int _write(struct mansession *s, struct message *m) { - int i; - char buf[BUFSIZE], outstring[MAX_LEN*3], xmlescaped[MAX_LEN*3], xmldoctag[MAX_LEN]; - char *dpos, *lpos; - - setdoctag(xmldoctag, m->session); - sprintf(buf, "<%s>\r\n", xmldoctag); - - pthread_mutex_lock(&s->lock); - ast_carefulwrite(s->fd, buf, strlen(buf), s->writetimeout); - - for (i=0; ihdrcount; i++) { - memset(xmlescaped, 0, sizeof xmlescaped); - xml_quote_string(m->headers[i], xmlescaped); - lpos = xmlescaped; - dpos = strstr(lpos, ": "); - if (dpos && *(lpos)!= ' ' && strlen(xmlescaped)<30 ) { - strcpy(outstring, " <"); - strncat(outstring, lpos, dpos-lpos); - strcat(outstring, " Value=\""); - strncat(outstring, dpos+2, strlen(dpos)-2); - strcat(outstring, "\"/>\r\n"); - } else - sprintf(outstring, " <%s Value=\"%s\"/>\r\n", XML_UNPARSED, lpos); - ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout); - } - sprintf(buf, "\r\n\r\n", xmldoctag); - ast_carefulwrite(s->fd, buf, strlen(buf), s->writetimeout); - pthread_mutex_unlock(&s->lock); - - return 0; + int i; + char buf[BUFSIZE], outstring[MAX_LEN*3], xmlescaped[MAX_LEN*3], xmldoctag[MAX_LEN]; + char *dpos, *lpos; + + setdoctag(xmldoctag, m->session); + sprintf(buf, "<%s>\r\n", xmldoctag); + + pthread_mutex_lock(&s->lock); + ast_carefulwrite(s->fd, buf, strlen(buf), s->writetimeout); + + for (i=0; ihdrcount; i++) { + memset(xmlescaped, 0, sizeof xmlescaped); + xml_quote_string(m->headers[i], xmlescaped); + lpos = xmlescaped; + dpos = strstr(lpos, ": "); + if (dpos && *(lpos)!= ' ' && strlen(xmlescaped)<30 ) { + strcpy(outstring, " <"); + strncat(outstring, lpos, dpos-lpos); + strcat(outstring, " Value=\""); + strncat(outstring, dpos+2, strlen(dpos)-2); + strcat(outstring, "\"/>\r\n"); + } else + sprintf(outstring, " <%s Value=\"%s\"/>\r\n", XML_UNPARSED, lpos); + ast_carefulwrite(s->fd, outstring, strlen(outstring), s->writetimeout); + } + sprintf(buf, "\r\n\r\n", xmldoctag); + ast_carefulwrite(s->fd, buf, strlen(buf), s->writetimeout); + pthread_mutex_unlock(&s->lock); + + return 0; } /* Takes a single manager header line and converts xml entities */ void xml_quote_string(char *s, char *o) { - char *c; - c = s; - - do { - if (*c == '<') - strcat(o, "<"); - else if (*c == '>') - strcat(o, ">"); - else if (*c == '&') - strcat(o, "&"); - else if (*c == '"') - strcat(o, """); - else if (*c == '\n') - strcat(o, " "); - else - strncat(o, c, 1); - } while (*(c++)); - - return; + char *c; + c = s; + + do { + if (*c == '<') + strcat(o, "<"); + else if (*c == '>') + strcat(o, ">"); + else if (*c == '&') + strcat(o, "&"); + else if (*c == '"') + strcat(o, """); + else if (*c == '\n') + strcat(o, " "); + else + strncat(o, c, 1); + } while (*(c++)); + + return; } int ParseXMLInput(char *xb, struct message *m) { - char *b, *e, *bt, *et, tag[MAX_LEN], *i; - int res = 0; - - /* just an empty block; go home */ - if ( !(*xb) ) - return 0; - - /* initialize message block */ - memset(m, 0, sizeof(struct message) ); - - b = strstr(xb, XML_BEGIN_INPUT); - e = strstr(xb, XML_END_INPUT); - if (b && e) { - bt = strstr((char *)(b + strlen(XML_BEGIN_INPUT) + 1), "<"); - while (bt < e) { - et = strstr(bt+1, "<"); - memset(tag, 0, sizeof tag); - strncpy(tag, bt, (et-bt) ); - bt = et; - - strncpy( m->headers[m->hdrcount], tag+1, strstr(tag+1," ")-(tag+1) ); - strcat(m->headers[m->hdrcount], ": "); - i = strstr(tag+1, "\"") + 1; - strncat( m->headers[m->hdrcount], i, strstr(i, "\"") - i ); - debugmsg("parsed: %s", m->headers[m->hdrcount]); - m->hdrcount++; - } - res = 1; - } else - res = -1; - - return res; + char *b, *e, *bt, *et, tag[MAX_LEN], *i; + int res = 0; + + /* just an empty block; go home */ + if ( !(*xb) ) + return 0; + + /* initialize message block */ + memset(m, 0, sizeof(struct message) ); + + b = strstr(xb, XML_BEGIN_INPUT); + e = strstr(xb, XML_END_INPUT); + if (b && e) { + bt = strstr((char *)(b + strlen(XML_BEGIN_INPUT) + 1), "<"); + while (bt < e) { + et = strstr(bt+1, "<"); + memset(tag, 0, sizeof tag); + strncpy(tag, bt, (et-bt) ); + bt = et; + + strncpy( m->headers[m->hdrcount], tag+1, strstr(tag+1," ")-(tag+1) ); + strcat(m->headers[m->hdrcount], ": "); + i = strstr(tag+1, "\"") + 1; + strncat( m->headers[m->hdrcount], i, strstr(i, "\"") - i ); + debugmsg("parsed: %s", m->headers[m->hdrcount]); + m->hdrcount++; + } + res = 1; + } else + res = -1; + + return res; } -- cgit