#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; }