diff options
Diffstat (limited to 'src/proxyfunc.c')
-rw-r--r-- | src/proxyfunc.c | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/src/proxyfunc.c b/src/proxyfunc.c new file mode 100644 index 0000000..434baff --- /dev/null +++ b/src/proxyfunc.c @@ -0,0 +1,390 @@ +#include "astmanproxy.h" +#include "md5.h" + +extern struct mansession *sessions; +extern struct iohandler *iohandlers; +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; +} + +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; +} + +void *ProxySetOutputFormat(struct mansession *s, struct message *m) { + struct message mo; + char *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 ); + + s->output->write(s, &mo); + + return 0; +} + +int ProxyChallenge(struct mansession *s, struct message *m) { + struct message mo; + + 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()); + + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "Response: Success"); + AddHeader(&mo, "Challenge: %s", s->challenge); + + 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; +} + +int AuthMD5(char *key, char *challenge, char *password) { + int x; + int len=0; + char md5key[256] = ""; + struct MD5Context md5; + unsigned char digest[16]; + + 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)) + return 0; + else + return 1; +} + +void *ProxyLogin(struct mansession *s, struct message *m) { + 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"); + + 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 ) { + 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; +} + +void *ProxyLogoff(struct mansession *s) { + struct message m; + + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "Goodbye: Y'all come back now, y'hear?"); + + s->output->write(s, &m); + + 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; +} + +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; +} + +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; +} + + +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 + proxyerror_do(s, "Invalid Proxy Action"); + + return 0; +} + +int proxyerror_do(struct mansession *s, char *err) +{ + struct message mo; + + memset(&mo, 0, sizeof(struct message)); + AddHeader(&mo, "ProxyResponse: Error"); + AddHeader(&mo, "Message: %s", err); + + s->output->write(s, &mo); + + 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; +} + +void *SendError(struct mansession *s, char *errmsg) { + struct message m; + + memset(&m, 0, sizeof(struct message)); + AddHeader(&m, "Response: Error"); + AddHeader(&m, "Message: %s", errmsg); + + s->output->write(s, &m); + + return 0; +} |