/*- * 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); } }