/*-
* Copyright (c) 1998-2005 Joao Cabral
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* DHIS(c) Dynamic Host Information System Release 5.3
*/
#include "dhid.h"
extern struct conf_t *base;
int rport=DEF_ISPORT;
unsigned char pid_file[256];
unsigned char conf_file[256];
void cmd_fork(unsigned char *s) {
int pid;
int status;
if(*s=='\0') return;
switch(pid=fork()) {
case(-1): syslog(LOG_INFO,"Unable to fork for %s",s); break;
case(0):
system(s);
exit(0);
default: waitpid(pid,&status,0);
}
}
void sig_usr2() {
struct conf_t *cp;
cp=base;
while(cp!=NULL) {
if(cp->stage==ON_STAGE) {
offline_req_t msg;
msg.hdr.opcode=OFFLINE_REQ;
msg.hdr.hostid=cp->id;
msg.sid=cp->sid;
if(cp->cserver!=NULL)
net_write_message((msg_t *)&msg,cp->cserver->addr,cp->cserver->port);
}
cp->sid=0;
cp->stage=POLL_STAGE;
cp->cserver=NULL;
cp->timeout=60;
{
unsigned char linecmd[512];
struct in_addr sa;
sa.s_addr=cp->laddr;
snprintf(linecmd,sizeof(linecmd),"%s %d %s %s",cp->off_cmd,cp->id,
inet_ntoa((struct in_addr)sa)
,cp->off_cmdp);
cmd_fork(linecmd);
}
cp=cp->next;
}
syslog(LOG_INFO,"-> Offline (USR2)");
}
void sig_term() {
struct conf_t *cp;
cp=base;
while(cp!=NULL) {
if(cp->stage==ON_STAGE) {
offline_req_t msg;
msg.hdr.opcode=OFFLINE_REQ;
msg.hdr.hostid=cp->id;
msg.sid=cp->sid;
if(cp->cserver!=NULL)
net_write_message((msg_t *)&msg,cp->cserver->addr,cp->cserver->port);
}
cp->sid=0;
cp->stage=POLL_STAGE;
cp->cserver=NULL;
cp->timeout=60;
{
unsigned char linecmd[512];
struct in_addr sa;
sa.s_addr=cp->laddr;
snprintf(linecmd,sizeof(linecmd),"%s %d %s %s",cp->off_cmd,cp->id,
inet_ntoa((struct in_addr)sa)
,cp->off_cmdp);
cmd_fork(linecmd);
}
cp=cp->next;
}
free_conf();
syslog(LOG_INFO,"daemon exiting");
unlink(pid_file);
exit(0);
}
void usage(char *argv[]) {
printf("Syntax: %s [-h] [-p localport] [-P pid_file] [-f conf_file]\n",argv[0]);
exit(0);
}
void check_message(void) {
msg_t msg;
int from;
struct conf_t *cp;
cp=base;
if(!net_check_message()) return;
if(!net_read_message(&msg,&from)) return;
if(msg.hdr.opcode==ECHO_REQ) {
echo_ack_t m;
m.hdr.opcode=ECHO_ACK;
m.oserial=msg.hdr.serial;
m.hdr.hostid=msg.hdr.hostid;
net_write_message((msg_t *)&m,from,msg.hdr.rport);
return;
}
while(cp!=NULL) {
if(cp->id==msg.hdr.hostid) {
struct ser_t *sp=NULL;
sp=cp->servers;
while(sp!=NULL) {
if(sp->addr==from && sp->port==msg.hdr.rport) break;
sp=sp->next;
}
if(sp!=NULL) break;
}
cp=cp->next;
}
if(cp==NULL) {
syslog(LOG_INFO,"dhid: Packet recieved from an unknown server or server port! Ignoring ... ");
return;
}
if(msg.hdr.opcode==AUTH_DENY) {
syslog(LOG_ERR,"Authentication failed for %d, retrying ...",
msg.hdr.hostid);
cp->stage=POLL_STAGE;
cp->cserver=NULL;
cp->timeout=30;
return;
}
if(msg.hdr.opcode==AUTH_ACK) {
auth_ack_t *p2;
p2=(auth_ack_t *)&msg;
if(!cp->refresh)
cp->timeout=60*FAIL_ALLOW;
else
cp->timeout=cp->refresh*FAIL_ALLOW;
cp->stage=ON_STAGE;
syslog(LOG_INFO,"[%d] -> Online",msg.hdr.hostid);
cp->sid=p2->sid;
cp->laddr=p2->raddr;
if(cp->on_cmd[0]!='\0')
{
unsigned char linecmd[512];
struct in_addr sa;
sa.s_addr=cp->laddr;
snprintf(linecmd,sizeof(linecmd),"%s %d %s %s",cp->on_cmd,cp->id,
inet_ntoa((struct in_addr)sa)
,cp->on_cmdp);
cmd_fork(linecmd);
}
return;
}
if(msg.hdr.opcode==CHECK_REQ) {
check_req_t *p;
check_ack_t m;
if(cp->stage!=ON_STAGE) { cp->stage=POLL_STAGE; cp->cserver=NULL; return; }
p=(check_req_t *)&msg;
m.hdr.opcode=CHECK_ACK;
m.hdr.hostid=cp->id;
m.sid=cp->sid;
net_write_message((msg_t *)&m,from,msg.hdr.rport);
cp->timeout=FAIL_ALLOW*p->next_check;
return;
}
if(msg.hdr.opcode==ECHO_ACK) {
auth_req_t m;
struct ser_t *sp;
if(cp->cserver!=NULL) return;
sp=cp->servers;
while(sp!=NULL) {
if(sp->addr==from && sp->port==msg.hdr.rport) break;
sp=sp->next;
}
if(sp==NULL)
return;
cp->cserver=sp;
cp->stage=AUTH_STAGE;
if(cp->atype==APASS) strlcpy(m.pass,cp->pass,sizeof(m.pass));
else memset(m.pass,0,sizeof(m.pass));
m.hdr.opcode=AUTH_REQ;
m.hdr.hostid=cp->id;
m.refresh=cp->refresh;
net_write_message((msg_t *)&m,from,msg.hdr.rport);
cp->timeout=30;
return;
}
#ifdef QRC
if(msg.hdr.opcode==AUTH_SY) {
mpz_t x1,x2,y,x,n;
auth_sendx_t m;
auth_sendy_t *mp;
unsigned char buff[1024];
if(cp->atype!=AQRC) return;
mpz_init(x1);
mpz_init(x2);
mpz_init(y);
mpz_init(x);
mpz_init(n);
mp=(auth_sendy_t *)&msg;
memcpy(buff,mp->y,200);
buff[200]='\0';
mpz_set_str(y,buff,10);
qrc_sqrty(x1,y,cp->authp);
qrc_sqrty(x2,y,cp->authq);
qrc_crt(y,x1,x2,cp->authp,cp->authq);
mpz_clear(x1);
mpz_clear(x2);
mpz_mul(n,cp->authp,cp->authq);
mpz_mod(x,y,n);
mpz_clear(y);
mpz_clear(n);
m.hdr.opcode=AUTH_SX;
m.hdr.hostid=cp->id;
qrc_fill_str(x,m.x,200);
mpz_clear(x);
net_write_message((msg_t *)&m,from,msg.hdr.rport);
return;
}
#endif
return;
}
int main(int argc,char *argv[]) {
FILE *fp;
int c;
extern char *optarg;
strlcpy(conf_file,DHID_CONF,sizeof(conf_file));
strlcpy(pid_file,DHID_PID,sizeof(pid_file));
while((c=getopt(argc,argv,"hf:p:P:"))!=EOF)
switch(c) {
case('p'): rport=atoi(optarg); break;
case('P'): strlcpy(pid_file,optarg,sizeof(pid_file)); break;
case('f'): strlcpy(conf_file,optarg,sizeof(conf_file)); break;
case('h'): usage(argv);
default: usage(argv);
}
close(0);
close(1);
close(2);
setsid();
if(fork()) _exit(0); /* Run in background */
syslog(LOG_INFO,"daemon started");
read_conf(conf_file);
if(net_init(rport)) {
syslog(LOG_ERR,"failed to open incoming udp socket on port %d",
rport);
exit(255);
}
signal(SIGUSR1,SIG_IGN);
signal(SIGUSR2,sig_usr2);
signal(SIGTERM,sig_term);
unlink(pid_file);
fp=fopen(pid_file,"w");
if(fp!=NULL) {
fprintf(fp,"%d",(int)getpid());
fclose(fp);
}
for(;;) {
struct conf_t *cp;
check_message();
cp=base;
while(cp!=NULL) {
if(cp->stage==POLL_STAGE && cp->timeout<=0) {
struct ser_t *sp;
echo_req_t m; m.hdr.opcode=ECHO_REQ;
m.hdr.hostid=cp->id;
sp=cp->servers;
while(sp!=NULL) {
if(sp->addr==0) {
struct hostent *h;
if ( (h = gethostbyname(sp->hostname)) != NULL )
memcpy( &sp->addr, h->h_addr, 4 );
else {
sp=sp->next;
continue;
}
}
net_write_message((msg_t *)&m,sp->addr,sp->port);
sp=sp->next;
}
cp->timeout=30;
}
if(cp->timeout>0) cp->timeout--;
if(cp->timeout==0) {
if(cp->stage==ON_STAGE)
syslog(LOG_INFO,"[%d] -> Offline (timeout)",cp->id);
cp->stage=POLL_STAGE;
cp->cserver=NULL;
{
unsigned char linecmd[512];
struct in_addr sa;
sa.s_addr=cp->laddr;
snprintf(linecmd,sizeof(linecmd),"%s %d %s %s",cp->off_cmd,cp->id,
inet_ntoa((struct in_addr)sa)
,cp->off_cmdp);
cmd_fork(linecmd);
}
}
cp=cp->next;
}
sleep(1);
}
}
syntax highlighted by Code2HTML, v. 0.9.1