dhisd-5.3000755 000000 000764 00000000000 10737721701 012345 5ustar00rootdhis000000 000000 dhisd-5.3/engines000755 000000 000764 00000000000 10341074120 013760 5ustar00rootdhis000000 000000 dhisd-5.3/COPYRIGHT000644 000000 000764 00000002525 10341071755 013721 0ustar00rootdhis000000 000000 - 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 dhisd-5.3/INSTALL000644 000000 000764 00000013617 10737700013 013456 0ustar00rootdhis000000 000000 Install instructions for DHIS server rel5.3 =========================================== dhisd is the DHIS server, meant to permit updating external databases with dynamically assiged IP addresses to clients. In order to build the dhisd server the following requirements must be met: The machine must be permanently connected to the internet with a static IP address. The machine which will act as a server should be running a distribution of UNIX or similar system. A C compiler is needed. The GNU Multi Precision library is required (see section 0 below). 0. GMP ====== Before starting to compile DHISD, the GNU MultiPrecision library gmp must be installed. It may be downloaded from: ftp://ftp.dhis.org/pub/dhis/gmp-4.1.tar.gz Decompressed. Building should require: ./configure make make install 1. Compile Stage ---------------- If your system is System V based, edit the Makefile and add -lsocket -lnsl to the LIBS section. These are required for TCP/IP operation. Being in the source directory type "make". It should build the dhisd binary. 2. Install stage ---------------- In this installation we will use /etc/dhis as the default base directory for the server. Another directory may be used in which case file location command line options must be given to dhisd when executing. Create the directories: /etc/dhis /etc/dhis/bin /etc/dhis/pid /etc/dhis/db /etc/dhis/log You may wish to create /etc/dhis/src and put dhisd-5.3 under this directory. Copy dhisd to /etc/dhis/bin . This is the server binary. Create the database file which will hold information for current dynamic hosts: Change directory to /etc/dhis/db Create a text file named dhis.db with a text editor. Each dynamic host in the database file is represented by a record in the following form: ID { authentication keys } Example: 3 hosts, 2 with password authentication and 1 with QRC authentication. dhis.db: -------- 1000 { HostPass secret1 Service serviceA } 1001 { HostPass secret2 Service serviceA } 1002 { AuthN 62618356157083313953659443711837574706224086057551 AuthN 20427737733677817431836864820217527591008711003863 AuthN 70979542582114024334017868024554473396638523106022 AuthN 2702375049521348659606361903688258217224352016237 Service serviceA Service serviceB } A dynamic record starts with a { and ends with a }. The hostid is a unique number that identifies the client. HostPass is the text password that the client uses to authenticate. AuthN is the client's public key if QRC is being used. Please note that either hostpass or authn must be present for each host but they may not be used together. QRC keys may be generated with the genkeys utility provided in this distribution. Run genkeys and copy-paste the AuthN lines. AuthP and AuthQ lines are the client's private keys and should be sent to the client wishing to authenticate using QRC. authn is the client's public key. It may be represented as a series of authn lines in which case the digits are concatenated in appearance order originating a bigger public key. Service represents the services/modules that the client subscribes to. See MODULES for more information. Any line inside a record that does not have a known keyword is discarded and thus, may be used as a comment or additional information. Keywords are case insensitive thus AuthN is the same as authn. Please note that R3 clients should use password (and hostpass) and not QRC. The authentication sequence is different but the same keywords serves both purposes i.e., password in R3 and R4/R5. As of R5 the file dhisd no longer requires a hostname keyword. This is because the DHIS server is no longer DNS service specific. For a DNS service the dns engine should implement a matrix for translation between hostid and hostname. Since dhisd ignores anything that does not match an implemented command the dhis.db file may be used by engines to contain additional information. 1003 uses QRC and has the public key resulting from concatenating the number sequence. For each new dynamic host added, kill -HUP the dhisd process for database reloading. Change the permissions as you wish. In particular dhis.db should not be readable by anyone. Suggested example: chmod 700 /etc/dhis /etc/dhis/* chmod 600 /etc/dhis/db/dhis.db Add dhisd to your system's startup script (rc.local for BSD systems, SXXdhis under /etc/rc2.d for System V). A simple line such as /etc/dhis/bin/dhisd will do. Now create /etc/dhis/db/services.db Insert one line per module implemented. See MODULES for a detailed description of the modular architecture and services.db format. And the DHIS server is installed. See the README file for more information on the server and MODULES for information on the new modular structure of the server. You may also run /etc/dhis/bin/dhisd now if you wish to run DHIS at once. 3. Adding Records ----------------- For each new host, as described above, a new record must be added to dhis.db and a kill -HUP must be sent to the dhisd process. 4. Running dhisd in debug mode ------------------------------ The DHIS server dhisd may be configured to log DEBUG messages to syslog. Currently most messages are logged under LOG_DEBUG so a proper log file specified in syslog.conf is required. By default dhisd does not log much. Currently most information will be dumped on level 1 and only one function will log on level 2. There are two ways of turning debugging on: 1) Use the -D option To log on level 1 use dhisd -D To log on level 2 use dhisd -D -D 2) Using SIGUSR1 and SIGUSR2 dhisd can be configured at run time to increase or reset its log level. Sengind a SIGURS1 to the dhisd process increases its log level by one. Sending a SIGUSR2 to the process resets the log level to 0. And that's it. The DHIS server is installed. dhisd-5.3/Makefile000644 000000 000764 00000004106 10341072113 014050 0ustar00rootdhis000000 000000 # - # 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 CC=gcc CFLAGS=-Wall -Wformat -I/usr/local/include # -DDONT_FORK LFLAGS=-L/usr/local/lib CP=cp INSTALLDIR=/etc/dhis/bin MODE=700 OWNER=root MKDIR=mkdir -p CHOWN=chown CHMOD=chmod # For System V (Solaris) uncomment -lnd -lsocket LIBS=-lgmp OBJS=log.o network.o misc.o db.o online.o service.o main.o RM=rm -f all: dhisd genkeys dhisd: $(OBJS) $(CC) $(LFLAGS) -o dhisd $(OBJS) $(LIBS) strip dhisd genkeys: $(CC) $(CFLAGS) $(LFLAGS) genkeys.c -DQRC=1 -o genkeys -lgmp install: dhisd genkeys $(MKDIR) $(INSTALLDIR) $(CP) dhisd genkeys $(INSTALLDIR) $(CHOWN) $(OWNER) $(INSTALLDIR)/dhisd $(INSTALLDIR)/genkeys $(CHMOD) $(MODE) $(INSTALLDIR)/dhisd $(INSTALLDIR)/genkeys clean: $(RM) *.core core genkeys dhisd *.o *~ dhisd-5.3/README000644 000000 000764 00000026246 10737677641 013333 0ustar00rootdhis000000 000000 README file for DHIS server rel5.3 ================================== DHIS Release 5.3 introduces: ============================ Corrected bug that caused improper handling of comment character (;) in the database file. DHIS Release 5.2 introduces: ============================ Documentation Updates DHIS Release 5.1 introduces: ============================ AUTH_ACK packets return the client's external interface IP address for its possible use. DHIS Release 5.0 introduces: ============================ A new redefined protocol Configurable refresh rates No longer a DNS-only system A modular architecture for multiple types of updates based on dynamic IP address client assignments. Multi-client and Multi-server support. For a description and understanding of the new modular structure please see the MODULES file in this distribution. For the new DHIS R5 protocol specifications please see the DHIS Release 5 Specification [DHISR5SPEC.pdf] document. For a step-by-step QRC description in C using libgmp please see Implementing QRC Authentication using the GNU Multi-Precision library [IQRCGMP.pdf] DHIS Principle and Architecture: ================================ DHIS is a client-server architecture meant to update databases for systems which are assigned a dynamic IP[v4] address. By the means of a DHIS client a host which is assigned a dynamic IP address (either from its ISP or from DHCP) is able to communicate with a DHIS server in order to advertise its newly acquired IP address. DHIS comprises a UDP based protocol to achieve this purpose. A DHIS client has a unique identification number and a set of authentication keys, runs in background, and attempts to reach its server. The DHIS server (permanently online) listens to UDP messages from its clients and authenticates these against its knowledge of keys. When authentication is successful the DHIS server updates one or more databases with the newly received IP address for the given client. The server then keeps sending, every period of time, check requests to each of its connected clients. These need to be acknowledged. If not the server will consider, on an individual basis, that the client has disconnected and will again update the databases to an offline state. Alternativelly the server may receive an OFFLINE_REQ packet from the client, in which case the DNS record is updated at once and the online state droped. Unlike previous versions of the DHIS server, release 5 no longer attempts to provide Dynamic DNS only. Instead, the current distribution provides a server capable of handling multiple services implemented externally by modules. Dynamic DNS is one possible server to provide with a DHIS server but not the only one. Therefore all DNS related code has been removed from this release. For details on the new modular architecture please see MODULES. In essence the DHIS server: Listens to a UDP port for messages from clients Authenticates clients Submits online requests to sub-processes Checks that clients are still connected If not, submits offline requests to sub-processes Compatibility: ============== The DHIS release 5 server dhisd is compatible with release 3 and 4 clients. Release 3 and 4 servers are not, however, compatible with release 5 clients. Secure QRC Authentication: ========================== On a secure level DHIS 5 has built in public key authentication based on QRC (Quadratic Residue Cypher). The server(dhisd) supports two methods of authentication, password and qrc. Furthermore, dhisd 5 is compatible with R3 authentication scheme. In R5 authentication (and protocol) the client sends an ECHO_REQ packet to the server from which it expects an ECHO_REP. If received the connection is established and the client proceeds to authentication. If mode is password, a simple password is sent raw over the network upon which the server confirms or denies the online state. If scheme is QRC the server sends the client an AUTH_SY packet to which the client must reply with an AUTH_SX before authentication can be confirmed. The QRC algorithm, as implemented in DHIS 5, is as follows: The client has two 100 digit keys P and Q. The server has (for each client) the public key N obtained by P*Q. P and Q are both prime and congruent to 3 mod 4. When authentication is requested the server generates a random number (prime relative to N) called X and squares it mod N. It then sends its square to the client (Y) which by its turn has to calculte its square root mod N (X') using the chinese remainder theorem. X' is sent back and compared with X. X' may only be calculated knowing the two private keys factors P and Q. In order to make use of QRC dhisd uses the GNU Multi Precision Library gmp. Possible DHIS services in modules: ================================== 1) Dynamic DNS Update 2) Mail relaying 3) IPinIP automatic tunneling 4) IPv6inIP automatic tunneling 5) IPSEC automatic tunneling 6) Firewall access control 7) Mail relay access database control 8) A simple log server 9) Monitoring online status service etc ... Signals: ======== dhisd accepts HUP and TERM signals. A kill -HUP will make it reload the hosts database and kill -TERM will terminate it. Its pid number is recorded a the text file (default: /etc/dhis/pid/dhisd.pid) Before terminating with SIGTERM dhisd will attempt to bring all online clients offline. Logging: ======== dhisd logs online and offline transitions on a text file (default: /etc/dhis/log/dhisd.log) Command Line Options: ===================== dhisd supports the following command line options: -p allows the server to listen to an alternative port. Default is 58800. -P allows the specification of an alternative port e.g. dhisd -P /var/run/dhisd.pid -l allows specifying a path for the log file e.g. dhisd -l /var/log/dhisd.log -d allows specifying a path for the database file e.g. dhisd -d /usr/local/etc/dhis.db -s allows specifying a path for the services file. e.g. dhisd -s /usr/local/etc/services.db All options may be used in conjunction. Multi-server mode: ================== Since release 5 (due to the R5 client) DHIS may be used in more than one server at the same time for redundancy or load sharing purposes. DHIS R5 clients has the possibility of specifying multiple redundant servers. When connected the clients try to reach one of the available servers and use the one that provides a faster reply (or a reply at all if others are down). The only restriction to running DHIS in redundant multi-servers is to keep exactly the same database files on all redundant systems at all times. An example for a redundant or load-balanced dynamic DNS service: Primary DNS server A Secondary DNS server B | +-----------------+ | | | -------------------------------------------------- | | DHIS Server C DHIS Server D \ / ----- client ----- Client attempts to communicate with C and D. Client uses whichever replies (first) and authenticates with it. Say, if C picks up the request, C issues an nsupdate to A or B. An Update is then sent to B or A if DNS NOTIFY is configured. If C is down D will keep the system running. If is also possible to run multiple DHIS servers on the same machine (using different UDP port and file locations) in either independent or redundant mode. Modules required: ================= This distribution of dhisd by itself does not provide any particular service apart from learning dynamic IP addresses from clients. In order to implement a service a module engine needs to be installed and configured in services.db Some modules are available for download at the DHIS site. One may wish to write new modules using the interface described in MODULES. A module represents the action to take when one client becomes online or offline. Firewalls: ========== In order to configure a firewall for a DHIS server ensure that: The server can receive UDP packets on its listening port (default: 58800) The server can send UDP packets to anywhere/anyport (Since the client has the possibility of changing its UDP port) Refreshing and keeping the connection alive: ============================================ The new R5 method of keep-alive for DHIS is as follows: The client authenticates with the server. Optionally the client (in the authentication request) sends a refresh rate proposal. The server updates the client with its subscribed services and initialises the refresh period to a default of 60 seconds. If the refresh period was proposed by the client in the AUTH request the server compares this value against minimum and maximum limits and, if valid, uses this refresh delay instead. When N seconds have elapsed (N is the refresh delay) the server sends a CHECK_REQ packet to the client and expects a CHECK_ACK. If more than 3 CHECK_ACK packets are not received the client is marked offline. Service Memberships: ==================== Each client in dhis.db may be subscribed to one or more services (in services.db) with the service keyword. If a client does not have a service keyword line the server will attempt to match it against a service called default. If such service exists the client will automatically be subscribed to it. If not the client will not update any services (may still be useful for OnCmd and OffCmd). If however the client has at least one service keyword line on its section in dhis.db the default service will not be used. In order to "also" subscribe to the default service add a second service line with "service default". Online and Offline Commands: ============================ In addition to the modular membership described in MODULES for DHIS server clients, the server may run individual commands for a given client at online and offline transitions. For each client in dhis.db: If the client record has a line in the form: OnCmd /path/to/on/cmd /path/to/on/cmd is executed when that client becomes online. If the client record has a line in the form: OffCmd /path/to/off/cmd /path/to/off/cmd is executed when that client becomes offline. Both OffCmd and OnCmd executions occur with 2 parameters, the HostID of the client and the IP address acquired via DHIS. In addition both oncmd and offcmd commands may be invoqued with additional parameters (3, 4, 5, ...) as they appear in the dhis.db file. The first "word" after the command is passed to the external program as argument 3 (1 and 2 are id and address from above), the second as argument 4 and so on... Example of a simple logging test: 1000 { hostpass something oncmd /etc/oncmd } # /etc/oncmd #!/bin/sh # echo I am $1 online now at $2 OnCmd = oncmd and OffCmd = offcmd as keywords are not case sensitive. Support: ======== Please address any questions or bugs regarding dhisd to support (at) dhis.org dhisd-5.3/db.c000644 000000 000764 00000013760 10737721271 013166 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "db.h" #include "misc.h" db_t *dbase=NULL; unsigned char dbase_file[256]; int db_add_service(unsigned char *service,db_service_t **sbp) { struct service_s *sp; db_service_t *bp; sp=service_get_by_name(service); if(sp==NULL) return(1); bp=(*sbp); if(bp==NULL) { (*sbp)=(db_service_t *)malloc(sizeof(db_service_t)); if(*sbp == NULL) return(1); bp=(*sbp); } else { while(bp->next!=NULL) bp=bp->next; bp->next=(db_service_t *)malloc(sizeof(db_service_t)); if(bp->next==NULL) return(1); bp=bp->next; } bp->next=NULL; bp->sp=sp; return(0); } int db_reload(void) { FILE *fp; unsigned char str[1024]; db_t *rec; unsigned char keyn[1024]; if(dbase!=NULL) db_free(); DSYSLOG(1,(LOG_DEBUG,"db_reload(): Loading DHIS database %s\n",dbase_file)); fp=fopen(dbase_file,"r"); if(fp==NULL) return(0); while(fgets(str,1024,fp)!=NULL) { off_nl(str); if(strchr(line_entry(1,str),';')==NULL) if(!strcmp(line_entry(2,str),"{")) { unsigned char cmd[64]; char *cp; rec=(db_t *)malloc(sizeof(db_t)); if(rec==NULL) { fclose(fp); return(0); } rec->id=atoi(line_entry(1,str)); rec->ltod=0; rec->oncmd[0]='\0'; rec->offcmd[0]='\0'; rec->service=NULL; rec->xstage=0; rec->refresh=NEXT_CHECK; rec->atype=0; keyn[0]='\0'; do { if(fgets(str,1024,fp)==NULL) { fclose(fp); if(rec->atype==AQRC) mpz_clear(rec->authn); free(rec); return(0); } off_nl(str); strcpy(cmd,line_entry(1,str)); strtolower(cmd); if(!strcmp(cmd,"hostpass")) { strcpy(rec->pass,line_entry(2,str)); rec->atype=APASS; if((cp=strchr(rec->pass,';'))!=NULL) *cp='\0'; } if(!strcmp(cmd,"oncmd")) { strcpy(rec->oncmd,line_ptr(2,str)); if((cp=strchr(rec->oncmd,';'))!=NULL) *cp='\0'; } if(!strcmp(cmd,"offcmd")) { strcpy(rec->offcmd,line_ptr(2,str)); if((cp=strchr(rec->offcmd,';'))!=NULL) *cp='\0'; } if(!strcmp(cmd,"service")) { if(db_add_service(line_entry(2,str),&(rec->service))) { syslog(LOG_ERR,"Failed to load service %s for %d", line_entry(2,str),rec->id); DSYSLOG(1,(LOG_DEBUG,"db_reload(): Failed to load service %s for %d\n", line_entry(2,str),rec->id)); } } if(!strcmp(cmd,"authn")) { strcat(keyn,line_entry(2,str)); if((cp=strchr(keyn,';'))!=NULL) *cp='\0'; rec->atype=AQRC; } } while(strcmp(line_entry(1,str),"}")); if(!rec->atype) free(rec); else if(rec->atype==AQRC && keyn[0]=='\0') free(rec); else { if(rec->atype==AQRC) { mpz_init(rec->authn); mpz_set_str(rec->authn,keyn,10); } if(rec->service==NULL) db_add_service("default",&(rec->service)); db_add(rec); } DSYSLOG(1,(LOG_DEBUG,"db_reload(): Read record %d\n",rec->id)); } /* End if */ } /* End while */ fclose(fp); DSYSLOG(1,(LOG_DEBUG,"db_reload(): Database loaded\n")); return(1); } int db_free() { db_t *p1,*p2; if(dbase==NULL) return(1); p1=dbase; while(p1!=NULL) { db_service_t *dbp; while(p1->service!=NULL) { dbp=p1->service->next; free(p1->service); p1->service=dbp; } p2=p1; p1=p1->next; if(p2->atype==AQRC) mpz_clear(p2->authn); if(p2->atype==AQRC && p2->xstage==1) mpz_clear(p2->x); free(p2); } dbase=NULL; return(1); } unsigned char *db_password(int id) { db_t *p; static unsigned char pass[MAX_PASS]; p=dbase; while(p!=NULL) { if(p->id==id) { strcpy(pass,p->pass); return(pass); } p=p->next; } return(NULL); } int db_add(db_t *rec) { db_t *p; p=dbase; if(dbase==NULL) { dbase=rec; dbase->next=NULL; return(1); } while(p->next!=NULL) p=p->next; p->next=rec; p->next->next=NULL; return(1); } int db_get_ltod(int id) { db_t *p; p=dbase; while(p!=NULL) { if(id==p->id) return(p->ltod); p=p->next; } return(0); } int db_set_ltod(int id,int ltod) { db_t *p; p=dbase; while(p!=NULL) { if(p->id==id) { p->ltod=ltod; DSYSLOG(1,(LOG_DEBUG,"db_set_ltod(): Setting LTOD to %d on %d\n", p->ltod,p->id)); return(1); } p=p->next; } return(0); } db_service_t *db_get_service_by_id(int id) { db_t *dp; dp=dbase; while(dp!=NULL) { if(dp->id==id) return(dp->service); dp=dp->next; } return(NULL); } unsigned char *db_get_oncmd(int id) { db_t *dp; dp=dbase; while(dp!=NULL) { if(dp->id==id) return(dp->oncmd); dp=dp->next; } return(NULL); } unsigned char *db_get_offcmd(int id) { db_t *dp; dp=dbase; while(dp!=NULL) { if(dp->id==id) return(dp->offcmd); dp=dp->next; } return(NULL); } dhisd-5.3/db.h000644 000000 000764 00000004125 10341072155 013155 0ustar00rootdhis000000 000000 /*- * 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 */ #include "service.h" typedef struct db_service_t_s { struct service_s *sp; struct db_service_t_s *next; } db_service_t; typedef struct db_t { int id; unsigned char pass[MAX_PASS]; int ltod; int atype; mpz_t authn; int xstage; int refresh; mpz_t x; db_service_t *service; unsigned char oncmd[256]; unsigned char offcmd[256]; struct db_t *next; } db_t; int db_reload(void); int db_free(void); int db_add(db_t *); unsigned char *db_password(int); int db_get_ltod(int); int db_set_ltod(int,int); int db_add_service(unsigned char *,db_service_t **); db_service_t *db_get_service_by_id(int); unsigned char *db_get_oncmd(int); unsigned char *db_get_offcmd(int); dhisd-5.3/dhisd.h000644 000000 000764 00000007024 10737677745 013715 0ustar00rootdhis000000 000000 /*- * 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #define BOURNE_SHELL "/bin/sh" #define DHIS_VERSION 53 /* Current version */ #define DHIS_RELEASE 53 /* Current release */ #define DHIS_R4 40 /* R4 starting version */ #define DHIS_MIN_VERSION 30 /* Minimum required version to run */ #define KA_OFFLINE 300 /* timeout for R3 clients */ #define PARSE_TIMEOUT 60 /* frequency of parse in sec */ #define MIN_NEXT_CHECK 60 /* mim allowed refresh */ #define NEXT_CHECK 120 /* default refresh */ #define MAX_NEXT_CHECK (60*60*6) /* max allowed refresh secs */ #define CHECK_FAILS 3 /* maximum check fails */ #define DHISD_PORT 58800 #define DHISD_PID "/etc/dhis/pid/dhisd.pid" #define DHISD_DB "/etc/dhis/db/dhis.db" #define DHISD_LOG "/etc/dhis/log/dhisd.log" #define DHISD_SERVICES "/etc/dhis/db/services.db" #define MAX_HOSTNAME 64 #define MAX_PASS 16 /* R3 messages */ #define R3_ONLINE_REQ 0x00000311 #define R3_OFFLINE_REQ 0x00000312 /* R4 messages */ #define R4_ECHO_REQ 0x00000411 #define R4_ECHO_ACK 0x00000412 #define R4_AUTH_REQ 0x00000421 #define R4_AUTH_DENY 0x00000422 #define R4_AUTH_ACK 0x00000423 #define R4_AUTH_SX 0x00000424 #define R4_AUTH_SY 0x00000425 #define R4_CHECK_REQ 0x00000441 #define R4_CHECK_ACK 0x00000442 #define R4_OFFLINE_REQ 0x00000451 /* R5 messages */ #define ECHO_REQ 0x00000511 #define ECHO_ACK 0x00000512 #define AUTH_REQ 0x00000521 #define AUTH_DENY 0x00000522 #define AUTH_ACK 0x00000523 #define AUTH_SX 0x00000524 #define AUTH_SY 0x00000525 #define R51_AUTH_ACK 0x00000526 #define CHECK_REQ 0x00000541 #define CHECK_ACK 0x00000542 #define OFFLINE_REQ 0x00000551 #define APASS 1 #define AQRC 2 extern int debug; #define DSYSLOG(d,m) \ do { \ if (debug>=d) \ syslog m; \ } while(0) dhisd-5.3/log.c000644 000000 000764 00000003512 10341073531 013342 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "log.h" #include "misc.h" FILE *flog; unsigned char logfile[256]; int msg_log(unsigned char *msg) { time_t tt; unsigned char buff[256]; DSYSLOG(1,(LOG_DEBUG,"msg_log(): Logging %s\n",msg)); flog=fopen(logfile,"a"); if(flog==NULL) return(0); tt=time(NULL); strcpy(buff,ctime(&tt)); off_nl(buff); strcat(buff," : "); strcat(buff,msg); strcat(buff,"\n"); fputs(buff,flog); fclose(flog); return(1); } dhisd-5.3/log.h000644 000000 000764 00000002653 10341073523 013355 0ustar00rootdhis000000 000000 /*- * 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 */ int msg_log(unsigned char *); dhisd-5.3/main.c000644 000000 000764 00000045005 10341102722 013503 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "online.h" #include "db.h" #include "network.h" #include "log.h" int r=0; int stage=0; extern online_t *onbase; extern db_t *dbase; extern unsigned char logfile[256]; extern unsigned char dbase_file[256]; unsigned char services_file[256]; unsigned char pid_file[256]; int rport=DHISD_PORT; /* R3 hashing function */ int pass_encrypt(unsigned char *pass,int n) { int res=0; while(*pass!='\0') res += (*pass++ * (n%256)); res += n+ 8 + (n%100); return(res); } int do_dgram(msg_t msg,int from) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Processing packet [OPCODE=%x] started\n", msg.hdr.opcode)); /* First lets take care of DHIS R3 compatible messages */ if(msg.hdr.versionid); if(p==NULL) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): HostID does not match database.\n")); return(0); } DSYSLOG(1,(LOG_DEBUG,"do_dgram: LTOD=%d\n",msg.hdr.rport)); if(db_get_ltod(m->id) >= msg.hdr.rport) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Security: Invalid ltod. Discarded.\n")); return(0); } db_set_ltod(m->id,msg.hdr.rport); if(pass_encrypt(p,msg.hdr.rport)!=m->pass) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Security: Invalid password. Discarded.\n")); return(0); } if(msg.hdr.opcode==R3_ONLINE_REQ) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Online Broadcast: callind on_update().\n")); on_update(m->id,from,0,3,0); } if(msg.hdr.opcode==R3_OFFLINE_REQ) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Offline Broadcast: callind on_delete().\n")); on_delete(m->id); } DSYSLOG(1,(LOG_DEBUG,"do_dgram(): End of R3 message processing.\n")); return(1); } /* end R3 */ /* Now lets process R4 messages */ if(msg.hdr.version>=40 && msg.hdr.version < 50) DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Message is in R4 format\n")); if(msg.hdr.opcode==R4_OFFLINE_REQ) { r4_offline_req_t *mp; online_t *op; mp=(r4_offline_req_t *)&msg; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): R4_OFFLINE_REQ received\n")); op=onbase; while(op!=NULL) { if(op->sid==mp->sid && op->addr==from) break; op=op->next; } if(op!=NULL) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Calling on_delete() for %d\n",op->id)); on_delete(op->id); } else { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Security: Invalid addr or sid. Discarded.\n")); } return(1); } if(msg.hdr.opcode==R4_ECHO_REQ) { r4_echo_ack_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): R4_ECHO_REQ received. Sending ECHO_ACK.\n")); m.hdr.opcode=R4_ECHO_ACK; m.oserial=msg.hdr.serial; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } if(msg.hdr.opcode==R4_CHECK_ACK) { online_t *p; r4_check_ack_t *mp; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received R4_CHECK_ACK.\n")); mp=(r4_check_ack_t *)&msg; p=onbase; while(p!=NULL) { if(p->addr==from) break; p=p->next; } if(p==NULL) return(0); if(mp->sid!=p->sid) return(0); on_update(p->id,from,msg.hdr.rport,4,0); p->ka=time(NULL) + NEXT_CHECK; p->check_fails=0; return(1); } if(msg.hdr.opcode==R4_AUTH_SX) { db_t *dbp; r4_auth_sendx_t *mp; mpz_t x; unsigned char buff[1024]; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received R4_AUTH_SX.\n")); dbp=dbase; mp=(r4_auth_sendx_t *)&msg; while(dbp!=NULL) { if(dbp->id==mp->id) break; dbp=dbp->next; } if(dbp==NULL) { r4_auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_DENY. Invalid ID.\n")); m.hdr.opcode=R4_AUTH_DENY; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } if(dbp->atype!=AQRC || dbp->xstage==0) { r4_auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_DENY. Not in X waiting mode.\n")); m.hdr.opcode=R4_AUTH_DENY; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } mpz_init(x); memcpy(buff,mp->x,200); buff[200]='\0'; mpz_set_str(x,buff,10); if(mpz_cmp(x,dbp->x)) { r4_auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_DENY. X and X do not match.\n")); m.hdr.opcode=R4_AUTH_DENY; net_write_message((msg_t *)&m,from,msg.hdr.rport); if(dbp->xstage) mpz_clear(dbp->x); dbp->xstage=0; mpz_clear(x); return(0); } else { r4_auth_ack_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_ACK. X and X match.\n")); mpz_clear(x); mpz_clear(dbp->x); dbp->xstage=0; m.hdr.opcode=R4_AUTH_ACK; if((m.sid=on_update(dbp->id,from,msg.hdr.rport,4,0))!=0) { net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } else return(0); } } if(msg.hdr.opcode==R4_AUTH_REQ) { db_t *dbp; r4_auth_req_t *mp; mp=(r4_auth_req_t *)&msg; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received R4_AUTH_REQ for %d\n",mp->id)); dbp=dbase; while(dbp!=NULL) { if(dbp->id==mp->id) break; dbp=dbp->next; } if(dbp==NULL) { r4_auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_DENY. Invalid ID.\n")); m.hdr.opcode=R4_AUTH_DENY; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } mp->pass[MAX_PASS-1]='\0'; if(dbp->atype==APASS) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Password Authentication.\n")); if(strcmp(mp->pass,dbp->pass)) { r4_auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_DENY. Invalid Password.\n")); m.hdr.opcode=R4_AUTH_DENY; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } else { r4_auth_ack_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_ACK.\n")); m.hdr.opcode=R4_AUTH_ACK; if((m.sid=on_update(dbp->id,from,msg.hdr.rport,4,0))!=0) { net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } else return(0); } } if(dbp->atype==AQRC) { r4_auth_sendy_t m; mpz_t y; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): QRC Authentication.\n")); if(dbp->xstage==1) { dbp->xstage=0; mpz_clear(dbp->x);} m.hdr.opcode=R4_AUTH_SY; dbp->xstage=1; mpz_init(dbp->x); qrc_genx(dbp->x,dbp->authn); mpz_init(y); qrc_geny(y,dbp->x,dbp->authn); qrc_fill_str(y,m.y,200); mpz_clear(y); DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending R4_AUTH_SY.\n")); net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } return(0); } /* Finally process R5 messages */ if(msg.hdr.version>=50) DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Message is in R5 format\n")); if(msg.hdr.opcode==OFFLINE_REQ) { offline_req_t *mp; online_t *op; mp=(offline_req_t *)&msg; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): OFFLINE_REQ received\n")); op=onbase; while(op!=NULL) { if(op->sid==mp->sid && op->addr==from) break; op=op->next; } if(op!=NULL) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Calling on_delete() for %d\n",op->id)); on_delete(op->id); } else { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Security: Invalid addr or sid. Discarded.\n")); } return(1); } if(msg.hdr.opcode==ECHO_REQ) { echo_ack_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): ECHO_REQ received. Sending ECHO_ACK.\n")); 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(1); } if(msg.hdr.opcode==CHECK_ACK) { online_t *p; check_ack_t *mp; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received CHECK_ACK.\n")); mp=(check_ack_t *)&msg; p=onbase; while(p!=NULL) { if(p->addr==from && p->id==mp->hdr.hostid) break; p=p->next; } if(p==NULL) return(0); if(mp->sid!=p->sid) return(0); on_update(p->id,from,msg.hdr.rport,5,0); p->ka=time(NULL) + p->refresh; p->check_fails=0; return(1); } if(msg.hdr.opcode==AUTH_SX) { db_t *dbp; auth_sendx_t *mp; mpz_t x; unsigned char buff[1024]; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received AUTH_SX.\n")); dbp=dbase; mp=(auth_sendx_t *)&msg; while(dbp!=NULL) { if(dbp->id==mp->hdr.hostid) break; dbp=dbp->next; } if(dbp==NULL) { auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_DENY. Invalid ID.\n")); m.hdr.opcode=AUTH_DENY; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } if(dbp->atype!=AQRC || dbp->xstage==0) { auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_DENY. Not in X waiting mode.\n")); m.hdr.opcode=AUTH_DENY; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } mpz_init(x); memcpy(buff,mp->x,200); buff[200]='\0'; mpz_set_str(x,buff,10); if(mpz_cmp(x,dbp->x)) { auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_DENY. X and X do not match.\n")); m.hdr.opcode=AUTH_DENY; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); if(dbp->xstage) mpz_clear(dbp->x); dbp->xstage=0; mpz_clear(x); return(0); } else { auth_ack_t m; auth_ack_51_t m51; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_ACK. X and X match.\n")); mpz_clear(x); mpz_clear(dbp->x); dbp->xstage=0; if(msg.hdr.version>=51) { m51.hdr.opcode=R51_AUTH_ACK; m51.hdr.hostid=msg.hdr.hostid; m51.raddr=from; if((m51.sid=on_update(dbp->id,from,msg.hdr.rport, 5,dbp->refresh))!=0) { net_write_message((msg_t *)&m51,from,msg.hdr.rport); return(1); } else return(0); } else { m.hdr.opcode=AUTH_ACK; m.hdr.hostid=msg.hdr.hostid; if((m.sid=on_update(dbp->id,from,msg.hdr.rport, 5,dbp->refresh))!=0) { net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } else return(0); } } } if(msg.hdr.opcode==AUTH_REQ) { db_t *dbp; auth_req_t *mp; mp=(auth_req_t *)&msg; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Received AUTH_REQ for %d\n",mp->hdr.hostid)); DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Refresh rate is set to %d\n",mp->refresh)); dbp=dbase; while(dbp!=NULL) { if(dbp->id==mp->hdr.hostid) break; dbp=dbp->next; } if(dbp==NULL) { auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_DENY. Invalid ID.\n")); m.hdr.opcode=AUTH_DENY; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } mp->pass[MAX_PASS-1]='\0'; if(dbp->atype==APASS) { DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Password Authentication.\n")); if(strcmp(mp->pass,dbp->pass)) { auth_deny_t m; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_DENY. Invalid Password.\n")); m.hdr.opcode=AUTH_DENY; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(0); } else { auth_ack_t m; auth_ack_51_t m51; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_ACK.\n")); dbp->refresh=mp->refresh; if(msg.hdr.version>=DHIS_VERSION) { m51.hdr.opcode=R51_AUTH_ACK; m51.hdr.hostid=msg.hdr.hostid; m51.raddr=from; if((m51.sid=on_update(dbp->id,from,msg.hdr.rport,5, dbp->refresh))!=0) { net_write_message((msg_t *)&m51,from,msg.hdr.rport); return(1); } else return(0); } else { m.hdr.opcode=AUTH_ACK; m.hdr.hostid=msg.hdr.hostid; if((m.sid=on_update(dbp->id,from,msg.hdr.rport,5, dbp->refresh))!=0) { net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } else return(0); } } } if(dbp->atype==AQRC) { auth_sendy_t m; mpz_t y; DSYSLOG(1,(LOG_DEBUG,"do_dgram(): QRC Authentication.\n")); dbp->refresh=mp->refresh; if(dbp->xstage==1) { dbp->xstage=0; mpz_clear(dbp->x);} m.hdr.opcode=AUTH_SY; dbp->xstage=1; mpz_init(dbp->x); qrc_genx(dbp->x,dbp->authn); mpz_init(y); qrc_geny(y,dbp->x,dbp->authn); qrc_fill_str(y,m.y,200); mpz_clear(y); DSYSLOG(1,(LOG_DEBUG,"do_dgram(): Sending AUTH_SY.\n")); m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return(1); } return(0); } return(1); } void sig_parse() { if(!stage) on_parse(); signal(SIGALRM,sig_parse); alarm(PARSE_TIMEOUT); } void sig_hup() { if(!stage) db_reload(); else stage=2; service_send_reload(); signal(SIGHUP,sig_hup); } void sig_void() { } int debug = 0; void sig_usr1() { debug++; syslog(LOG_DEBUG,"debug level %d\n", debug); signal(SIGUSR1,sig_usr1); } void sig_usr2() { debug = 0; syslog(LOG_DEBUG,"debug level %d\n", debug); signal(SIGUSR2,sig_usr2); } void sig_term() { signal(SIGCHLD,sig_void); on_free(); db_free(); service_send_term(); service_free(); net_close(); msg_log("SIGTERM received. Exiting ..."); unlink(pid_file); exit(0); } void usage(unsigned char *s) { fprintf(stderr,"Syntax: %s [-D] [-p UDP_PORT] [-d dbase_file] [-s services_file] [-l log_file]\n",s); fprintf(stderr," [-P pid_file]\n"); exit(0); } int main(int argc,char *argv[]) { FILE *fp; unsigned char str[128]; extern char *optarg; int c; if(getuid()) { DSYSLOG(0,(LOG_ERR,"main(): %s must be executed as root\n",argv[0])); exit(0); } strcpy(logfile,DHISD_LOG); strcpy(pid_file,DHISD_PID); strcpy(dbase_file,DHISD_DB); strcpy(services_file,DHISD_SERVICES); while((c=getopt(argc,argv,"Dhp:P:l:d:s:")) !=EOF) { switch(c) { case('l'):strcpy(logfile,optarg);break; case('P'):strcpy(pid_file,optarg);break; case('p'):rport=atoi(optarg);break; case('d'):strcpy(dbase_file,optarg);break; case('D'):debug++;break; case('s'):strcpy(services_file,optarg);break; case('h'): usage(argv[0]); default: usage(argv[0]); } } #ifndef DONT_FORK setsid(); if(fork()) _exit(0); #endif if(net_init(rport)) { syslog(LOG_ERR,"Unable to initialise network"); DSYSLOG(1,(LOG_DEBUG,"main(): Failed to initialise network\n")); exit(255); } if(!read_services(services_file)) { syslog(LOG_ERR,"Unable to read any service"); DSYSLOG(1,(LOG_DEBUG,"main(): Failed to read services\n")); exit(255); } if(!init_services()) { syslog(LOG_ERR,"Unable to initialise services"); DSYSLOG(1,(LOG_DEBUG,"main(): Failed to initialise services\n")); exit(255); } if(!db_reload()) { syslog(LOG_ERR,"Unable to open database file"); DSYSLOG(1,(LOG_DEBUG,"main(): Failed to read database\n")); sig_term(); exit(255); } #ifndef DONT_FORK close(0); close(1); close(2); #endif unlink(pid_file); fp=fopen(pid_file,"w"); if(fp!=NULL) { fprintf(fp,"%d",(int)getpid()); fclose(fp); } sprintf(str,"Datagram Server Started [%d]",(int)getpid()); msg_log(str); signal(SIGUSR1,sig_usr1); signal(SIGUSR2,sig_usr2); signal(SIGTERM,sig_term); signal(SIGHUP,sig_hup); signal(SIGALRM,sig_parse); alarm(PARSE_TIMEOUT); for(;;) { msg_t msg; int from; if(!net_read_message(&msg,&from)) continue; stage=1; do_dgram(msg,from); if(stage==2) { stage=0; sig_hup(); } else stage=0; } } dhisd-5.3/misc.c000644 000000 000764 00000006553 10341073550 013525 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "misc.h" void dot_to_colon(unsigned char *s) { while(*s!='\0') { if(*s=='.') *s=':'; s++; } } void strtolower(unsigned char *s) { while(*s!='\0') { *s = tolower(*s); s++; } } void off_nl(unsigned char *s) { while(*s!='\0' && *s!='\n' && *s!='\r') s++; *s='\0'; return; } unsigned char *line_ptr(int idx,unsigned char *buff) { int i; static unsigned char m[1]; idx--; m[0]='\0'; while((*buff==' ' || *buff=='\t') && *buff!='\0' && *buff!='\n') buff++; if(*buff=='\0' || *buff=='\n') return(m); for(i=0;ihdr.opcode; swap_msg((int *)&(p->hdr),4); if(mode==2) opcode=p->hdr.opcode; if(opcode >= ECHO_REQ ) swap_int((int *)&(p->hdr.hostid)); switch(opcode) { case(ECHO_REQ): break; case(ECHO_ACK): { echo_ack_t *p2; p2=(echo_ack_t *)p; swap_int((int *)&(p2->oserial)); break; } case(AUTH_REQ): { auth_req_t *p2; p2=(auth_req_t *)p; swap_int((int *)&(p2->refresh)); break; } case(AUTH_ACK): { auth_ack_t *p2; p2=(auth_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(R51_AUTH_ACK): { auth_ack_51_t *p2; p2=(auth_ack_51_t *)p; swap_int((int *)&(p2->sid)); break; } case(AUTH_DENY): break; case(AUTH_SX): { auth_sendx_t *p2; p2=(auth_sendx_t *)p; break; } case(AUTH_SY): break; case(CHECK_REQ): { check_req_t *p2; p2=(check_req_t *)p; swap_int((int *)&(p2->next_check)); break; } case(CHECK_ACK): { check_ack_t *p2; p2=(check_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(OFFLINE_REQ): { offline_req_t *p2; p2=(offline_req_t *)p; swap_int((int *)&(p2->sid)); break; } /* R4 messages */ case(R4_ECHO_REQ): break; case(R4_ECHO_ACK): { r4_echo_ack_t *p2; p2=(r4_echo_ack_t *)p; swap_int((int *)&(p2->oserial)); break; } case(R4_AUTH_REQ): { r4_auth_req_t *p2; p2=(r4_auth_req_t *)p; swap_int((int *)&(p2->id)); break; } case(R4_AUTH_ACK): { r4_auth_ack_t *p2; p2=(r4_auth_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(R4_AUTH_DENY): break; case(R4_AUTH_SX): { r4_auth_sendx_t *p2; p2=(r4_auth_sendx_t *)p; swap_int((int *)&(p2->id)); break; } case(R4_AUTH_SY): break; case(R4_CHECK_REQ): { r4_check_req_t *p2; p2=(r4_check_req_t *)p; swap_int((int *)&(p2->next_check)); break; } case(R4_CHECK_ACK): { r4_check_ack_t *p2; p2=(r4_check_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(R4_OFFLINE_REQ): { r4_offline_req_t *p2; p2=(r4_offline_req_t *)p; swap_int((int *)&(p2->sid)); break; } /* R3 messages */ case(R3_OFFLINE_REQ): { r3_offline_req_t *p2; p2=(r3_offline_req_t *)p; swap_int((int *)&(p2->id)); swap_int((int *)&(p2->pass)); break; } case(R3_ONLINE_REQ): { r3_online_req_t *p2; p2=(r3_online_req_t *)p; swap_int((int *)&(p2->id)); swap_int((int *)&(p2->pass)); break; } } return; } int get_serial(void) { static int s=0; return(++s); } /* * net_init() - Initialises the socket descriptor for receiving * UDP connections * * Updates: udp_sock only * * Returns: 0 on success, 1 on error * */ int net_init(int port) { struct sockaddr_in sa; /* Create UDP socket */ udp_sock=socket(AF_INET,SOCK_DGRAM,0); if(udp_sock<0) return(1); /* Bind the UDP socket */ sa.sin_family=AF_INET; sa.sin_port=htons(port); sa.sin_addr.s_addr=INADDR_ANY; if(bind(udp_sock,(struct sockaddr *)&sa,sizeof(struct sockaddr_in))) { close(udp_sock); return(1); } /* UDP socket is ready to receive messages */ return(0); } /* * net_close() - Closes sockets associated with UDP incoming ports * * Updates: udp_sock only * * Returns: 0 * */ int net_close(void) { close(udp_sock); return(0); } /* * net_check_message() - Returns 1 if there is a message to be read or 0 * otherwise. * */ int net_check_message(void) { fd_set readfds; struct timeval tv; /* Prepare for select */ FD_ZERO(&readfds); FD_SET(udp_sock,&readfds); tv.tv_sec=0; tv.tv_usec=0; /* Check for new messages */ if(select(udp_sock+1,&readfds,NULL,NULL,&tv)==-1) return(0); if(!FD_ISSET(udp_sock,&readfds)) return(0); return(1); } /* * net_read_message() - Reads a message into *p and returns length read * or 0 on error. * */ int net_read_message(msg_t *p,int *from) { int n,sl; struct sockaddr_in sa; /* Read message */ sl=sizeof(struct sockaddr_in); n=recvfrom(udp_sock,p,MAX_MSG,0,(struct sockaddr *)&sa,&sl); if(n<=0 || n >MAX_MSG) return(0); DSYSLOG(1,(LOG_DEBUG,"net_read_message(): Message arrived from %s\n", inet_ntoa(sa.sin_addr))); /* Convert to big endian if necessary */ if(little_endian()) convert_message(p,2); memcpy(from,&sa.sin_addr,sizeof(struct in_addr)); return(n); } /* * net_write_message() - Writes a message from *p and returns the number of * bytes sent or 0 on error. * */ int net_write_message(msg_t *p,int toaddr,int toport) { struct sockaddr_in sa; int s; int len; int r; { struct in_addr sa; sa.s_addr=toaddr; DSYSLOG(1,(LOG_DEBUG,"net_write_message(): Sending Message to %s\n", inet_ntoa(sa))); } p->hdr.version=DHIS_VERSION; p->hdr.serial=get_serial(); p->hdr.rport=rport; /* set destination */ if((s=socket(AF_INET,SOCK_DGRAM,0))<0) return(0); sa.sin_family=AF_INET; sa.sin_port=htons(toport); sa.sin_addr.s_addr=toaddr; /* Get message size */ len=msg_size_by_opcode(p->hdr.opcode); /* Convert to big endian if necessary */ if(little_endian()) convert_message(p,1); /* Send message request */ r=sendto(s,(unsigned char *)p,len,0,(struct sockaddr *)&sa, sizeof(struct sockaddr_in)); close(s); /* Convert back just in case */ if(little_endian()) convert_message(p,2); return(r); } /* qrc_random() - Generates a random integer of n digits * n may be up to 1024 */ void qrc_random(mpz_t x,int n) { char buff[1024],temp[128]; static int seed=0; if(!seed) { seed++; srandom(time(NULL)); } memset(buff,0,256); memset(temp,0,128); do { sprintf(temp,"%lu",(unsigned long int)random()); strcat(buff,temp); } while(strlen(buff) < n); buff[n]='\0'; mpz_set_str(x,buff,10); return; } /* qrc_genkey() - Generates an integer of 100 digits being congruent * to 3 mod 4 * */ void qrc_genkey(mpz_t k) { int flag=1; do { mpz_t a,b; /* Get a prime number */ do qrc_random(k,100); while(!mpz_probab_prime_p(k,5)); /* Now see if it is congruent to 3 mod 4 */ mpz_init(a);mpz_init(b); mpz_set_ui(a,4); mpz_mod(b,k,a); mpz_set_ui(a,3); if(!mpz_cmp(a,b)) flag=0; mpz_clear(a); mpz_clear(b); } while(flag); } /* qrc_genx() - Geretates a random x relatively prime to n * */ void qrc_genx(mpz_t x,mpz_t n) { int i; mpz_t t; i=mpz_sizeinbase(n,10); /* Get size of n and take 1 */ i--; mpz_init(t); do { /* Generate x of n-1 digits */ qrc_random(x,i); qrc_geny(t,x,n); /* square it modulo n to get */ mpz_set(x,t); /* quadractic residue */ mpz_gcd(t,x,n); } while(mpz_cmp_ui(t,1)); /* test relative primeness */ mpz_clear(t); } /* qrc_geny() - y is the quadractic residue given by x^2 mod n * */ void qrc_geny(mpz_t y,mpz_t x,mpz_t n) { mpz_powm_ui(y,x,2,n); } /* qrc_sqrty() - Calculates the square root of y mod k using a^((k+1)/4))mod k * */ void qrc_sqrty(mpz_t s,mpz_t y,mpz_t k) { mpz_t t1,t2,t3; mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_set(t1,k); mpz_set_ui(t3,4); mpz_add_ui(t2,t1,1); /* t2 = k+1 */ mpz_divexact(t1,t2,t3); /* t1 = t2/4 */ mpz_powm(s,y,t1,k); mpz_clear(t1); mpz_clear(t2); mpz_clear(t3); } /* qrc_crt() - Applies the Chinese remainder theorem and calculates x * */ void qrc_crt(mpz_t x,mpz_t xp,mpz_t xq,mpz_t p,mpz_t q) { mpz_t s,t,g1,g2; mpz_t temp; mpz_init(s); mpz_init(t); mpz_init(g1); mpz_init(g2); mpz_init(temp); /* Use Euclid's theorem to find s and t */ mpz_gcdext(g1,s,t,q,p); mpz_mul(temp,xp,s); /* Do g1 = x1.s.q */ mpz_mul(g1,temp,q); mpz_mul(temp,xq,t); /* Do g2 = x2.t.p */ mpz_mul(g2,temp,p); mpz_add(x,g1,g2); /* Do x = g1 + g2 */ mpz_clear(temp); mpz_clear(s); mpz_clear(t); mpz_clear(g1); mpz_clear(g2); } /* qrc_fill_str() - This function fills a buffer pointed by str * with n digits of x. Adds 0's to the left if * required. */ void qrc_fill_str(mpz_t x,unsigned char *str,int n) { int i,j; unsigned char buff[1024]; unsigned char buff2[1024]; unsigned char *cp1,*cp2; i=mpz_sizeinbase(x,10); /* Get size of x */ j=n-i; /* j = number of 0's to add */ if(j<0) return; buff[0]='\0'; for(i=0;i OffCmd /etc/dhis/db/1004/off.sh } dhisd-5.3/online.c000644 000000 000764 00000012130 10341100124 014026 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "online.h" #include "db.h" #include "network.h" #include "log.h" online_t *onbase=NULL; int on_whereis(int id) { online_t *p; p=onbase; while(p!=NULL) { if(p->id==id) return(p->addr); p=p->next; } return(0); } int on_add(int id,int addr,int port,int proto,int refresh) { online_t *p; struct in_addr in; unsigned char str[128]; p=onbase; if(p!=NULL) while(p->next!=NULL) p=p->next; if(p==NULL) { onbase=(online_t *)malloc(sizeof(online_t)); p=onbase; } else { p->next=(online_t *)malloc(sizeof(online_t)); p=p->next; } if(p==NULL) return(0); p->next=NULL; p->id=id; p->addr=addr; if(proto>=4) p->port=port; else p->port=DHISD_PORT; p->proto=proto; p->check_fails=0; p->sid=0; if(refresh>=MIN_NEXT_CHECK && refresh <=MAX_NEXT_CHECK) { p->refresh=refresh; } else { if(refresh) DSYSLOG(1,(LOG_DEBUG,"on_add(): Refresh rate out of limits\n")); p->refresh=NEXT_CHECK; } if(p->proto>=4) p->ka=time(NULL) + p->refresh; else p->ka=time(NULL); srandom(time(NULL)); while(!(p->sid=random())); DSYSLOG(1,(LOG_DEBUG,"on_add(): Marking Host %d Online\n",p->id)); mark_online(p->id,p->addr); in.s_addr = p->addr; sprintf(str,"-> online %d [%s]",p->id,inet_ntoa(in)); msg_log(str); return(p->sid); } int on_delete(int id) { online_t *p1,*p2; unsigned char str[128]; struct in_addr in; p1=onbase; while(p1!=NULL) { if(p1->id==id) break; p2=p1; p1=p1->next; } if(p1==NULL) return(0); if(p1==onbase) onbase=p1->next; else p2->next=p1->next; DSYSLOG(1,(LOG_DEBUG,"on_add(): Marking Host %d Offline\n",p1->id)); mark_offline(p1->id,p1->addr); in.s_addr = p1->addr; sprintf(str,"-> offline %d [%s]",p1->id,inet_ntoa(in)); msg_log(str); free(p1); return(1); } int on_update(int id,int addr,int port,int proto,int refresh) { online_t *p; struct in_addr in; unsigned char str[128]; int oaddr; p=onbase; while(p!=NULL) { if(p->id==id) break; p=p->next; } if(p==NULL) { return(on_add(id,addr,port,proto,refresh)); } if(proto>=4) { p->ka=time(NULL)+p->refresh; p->check_fails=0; } else p->ka=time(NULL); if(p->addr==addr) return(p->sid); DSYSLOG(1,(LOG_DEBUG,"on_add(): Updating R3 host %d \n",p->id)); oaddr= p->addr; p->addr=addr; mark_update(p->id,p->addr,oaddr); in.s_addr = p->addr; sprintf(str,"-> update %d [%s]",p->id,inet_ntoa(in)); msg_log(str); return(p->sid); } int on_parse(void) { online_t *p1,*p2; time_t t; DSYSLOG(2,(LOG_DEBUG,"on_parse(): Executing.\n")); p1=onbase; t=time(NULL); while(p1!=NULL) { p2=p1->next; if(p1->proto==3) if((t - p1->ka) > KA_OFFLINE) on_delete(p1->id); if(p1->proto==4 || p1->proto ==5) { if(p1->check_fails > CHECK_FAILS) on_delete(p1->id); else { if (p1->proto == 4) { if(p1->ka < time(NULL)) { r4_check_req_t m; DSYSLOG(1,(LOG_DEBUG,"on_parse(): Sending R4_CHECK_REQ to %d\n", p1->id)); m.hdr.opcode=R4_CHECK_REQ; m.next_check=p1->refresh; net_write_message((msg_t *)&m,p1->addr,p1->port); p1->check_fails++; } /* end if ka */ } /* end proto */ if(p1->proto==5) { if(p1->ka < time(NULL)) { check_req_t m; DSYSLOG(1,(LOG_DEBUG,"on_parse(): Sending CHECK_REQ to %d\n", p1->id)); m.hdr.opcode=CHECK_REQ; m.hdr.hostid=p1->id; m.next_check=p1->refresh; net_write_message((msg_t *)&m,p1->addr,p1->port); p1->check_fails++; } /* end if ka */ } /* end proto 5 */ }} p1=p2; } return(1); } int on_getsid(int id) { online_t *p; p=onbase; while(p!=NULL) { if(p->id==id) return(p->sid); p=p->next; } return(0); } void on_free(void) { online_t *op; op=onbase; while(op!=NULL) { mark_offline(op->id,op->addr); op=op->next; free(onbase); onbase=op; } } dhisd-5.3/online.h000644 000000 000764 00000003447 10341073662 014066 0ustar00rootdhis000000 000000 /*- * 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 */ /* online_t structure */ typedef struct online_t { int id; int addr; int port; int refresh; int ka; int proto; int check_fails; int sid; struct online_t *next; } online_t; /* Function prototypes */ int on_whereis(int); int on_add(int,int,int,int,int); int on_delete(int); int on_update(int,int,int,int,int); int on_parse(void); int on_getsid(int); void on_free(void); dhisd-5.3/services.db.sample000644 000000 000764 00000001260 07261407612 016035 0ustar00rootdhis000000 000000 ; ; DHIS R5 ; ; A DHIS services database example for services default and dns ; ; Service default runs a dummy engine. 2 process instances are ; spawned for default executing /etc/dhis/bin/dhis-dummy-engine ; ; It is important for any command given in column 3 to be an existing ; command, executable, and compliant with the interface described in ; MODULES. A non-existant or non-compliant command line will make dhisd ; fork time after time creating a second dhisd process which is always ; terminating and consuming a great deal of system load without any ; effect. default 2 /etc/dhis/bin/dhis-dummy-engine ; Service dns runs on 4 processes ; dns 4 /etc/dhis/bin/dhis-dns-engine dhisd-5.3/service.h000644 000000 000764 00000004414 10341077643 014240 0ustar00rootdhis000000 000000 /*- * 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 */ /* Command strings to send to external process */ #define SADD "add" #define SDELETE "delete" #define SUPDATE "update" #define SRELOAD "reload" #define SEXIT "exit" struct service_fds_s { int fd; int pid; struct service_fds_s *next; }; struct service_s { unsigned char service[128]; unsigned char command[256]; int nprocs; struct service_fds_s *rrfdp; struct service_fds_s *fdp; struct service_s *next; }; void mark_online(int,int); void mark_update(int,int,int); void mark_offline(int,int); int read_services(unsigned char *); int init_services(void); void sigchld(); struct service_s *service_get_by_name(unsigned char *); void service_issue_command(unsigned char *,int,unsigned char *,unsigned char *); void fork_cmd(unsigned char *,int,unsigned char *); void service_free(void); void service_send_term(void); void service_send_reload(void); dhisd-5.3/service.c000644 000000 000764 00000025342 10341077734 014237 0ustar00rootdhis000000 000000 /*- * 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 */ #include "dhisd.h" #include "misc.h" #include "db.h" #include "network.h" #include struct service_s *sbase=NULL; void fork_cmd(unsigned char *cmd,int id,unsigned char *addr) { unsigned char line[1024]; unsigned char path[1024]; strcpy(path,line_entry(1,cmd)); sprintf(line,"%s %d %s %s",path,id,addr,line_ptr(2,cmd)); if(!fork()) { system(line); exit(0); } return; } void mark_update(int id,int addr,int oaddr) { struct in_addr sa,osa; unsigned char addrs[32],oaddrs[32]; unsigned char *cp; sa.s_addr=addr; osa.s_addr=oaddr; strcpy(addrs,inet_ntoa((struct in_addr)sa)); strcpy(oaddrs,inet_ntoa((struct in_addr)osa)); DSYSLOG(1,(LOG_DEBUG,"mark_update() %d %s %s\n",id,addrs,oaddrs)); service_issue_command(SUPDATE,id,addrs,oaddrs); cp=db_get_oncmd(id); if(cp!=NULL) { if(cp[0]!='\0') fork_cmd(cp,id,addrs); } cp=db_get_offcmd(id); if(cp!=NULL) { if(cp[0]!='\0') fork_cmd(cp,id,addrs); } } void mark_online(int id,int addr) { struct in_addr sa; unsigned char addrs[32]; unsigned char *cp; sa.s_addr=addr; strcpy(addrs,inet_ntoa((struct in_addr)sa)); DSYSLOG(1,(LOG_DEBUG,"mark_online() %d %s\n",id,addrs)); service_issue_command(SADD,id,addrs,""); cp=db_get_oncmd(id); if(cp!=NULL) { if(cp[0]!='\0') fork_cmd(cp,id,addrs); } } void mark_offline(int id,int addr) { struct in_addr sa; unsigned char addrs[32]; unsigned char *cp; sa.s_addr=addr; strcpy(addrs,inet_ntoa((struct in_addr)sa)); DSYSLOG(1,(LOG_DEBUG,"mark_offline(): %d\n",id)); service_issue_command(SDELETE,id,addrs,""); cp=db_get_offcmd(id); if(cp!=NULL) { if(cp[0]!='\0') fork_cmd(cp,id,addrs); } } int read_services(unsigned char *path) { FILE *fp; unsigned char line[1024]; DSYSLOG(1,(LOG_DEBUG,"read_services(): Reading services database\n")); fp=fopen(path,"r"); if(fp==NULL) { DSYSLOG(1,(LOG_DEBUG,"read_services(): Failed to open database\n")); return(0); } while(fgets(line,1024,fp)!=NULL) { unsigned char stag[128]; unsigned char scmd[256]; int nprocs; struct service_s *sp; off_nl(line); strcpy(stag,line_entry(1,line)); nprocs=atoi(line_entry(2,line)); strcpy(scmd,line_entry(3,line)); if(scmd[0]==';' || nprocs<0 || stag[0]==';') continue; if(stag[0]=='\0') continue; if(sbase==NULL) { sbase=(struct service_s *)malloc(sizeof(struct service_s)); if(sbase==NULL) continue; sp=sbase; } else { sp=sbase; while(sp->next!=NULL) sp=sp->next; sp->next=(struct service_s *)malloc(sizeof(struct service_s)); if(sp->next==NULL) continue; sp=sp->next; } DSYSLOG(1,(LOG_DEBUG,"read_services(): Memory allocated for service %s\n",stag)); sp->next=NULL; sp->fdp=NULL; sp->rrfdp=NULL; sp->nprocs=nprocs; strcpy(sp->service,stag); strcpy(sp->command,scmd); DSYSLOG(1,(LOG_DEBUG,"read_services(): Service %s added to list\n", stag)); } fclose(fp); DSYSLOG(1,(LOG_DEBUG,"read_services(): Finished reading services database\n")); if(sbase!=NULL) return(1); return(0); } int init_services(void) { struct service_s *sp; DSYSLOG(1,(LOG_DEBUG,"init_services(): Initialising services\n")); sp=sbase; if(sp==NULL) return(0); while(sp!=NULL) { int j; DSYSLOG(1,(LOG_DEBUG,"init_services(): Processing %s\n",sp->service)); for(j=0;jnprocs;j++) { int fieldes[2]; struct service_fds_s *fp; fp=sp->fdp; if(fp==NULL) { sp->fdp=(struct service_fds_s *)malloc(sizeof(struct service_fds_s)); if(sp->fdp==NULL) return(0); fp=sp->fdp; sp->rrfdp=fp; } else { while(fp->next!=NULL) fp=fp->next; fp->next=(struct service_fds_s *)malloc(sizeof(struct service_fds_s)); if(fp->next==NULL) return(0); fp=fp->next; } fp->next=NULL; DSYSLOG(1,(LOG_DEBUG,"init_services(): Creating process instance %d\n",j)); if(pipe(fieldes)<0) return(0); /* Create a pipe for external communication */ DSYSLOG(1,(LOG_DEBUG,"init_services(): Pipe created R:%d W:%d\n", fieldes[0],fieldes[1])); signal(SIGCHLD,sigchld); fp->pid=fork(); if(!(fp->pid)) { /* we are child */ int fo; int f0,f1,f2; net_close(); DSYSLOG(1,(LOG_DEBUG,"init_services(): I am the child for instance %d\n",j)); close(fieldes[1]); /* child doesn't write */ /* lets get a null device for output */ fo=open("/dev/null",O_WRONLY,0); if(fo<0) return(0); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: /dev/null open on %d\n",fo)); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: read pipe descriptior %d\n", fieldes[0])); /* set stdin from pipe */ close(0); f0=dup2(fieldes[0],0); if(f0) { DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdin redirect failed\n")); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: %s\n", strerror(errno))); return(0); } close(fieldes[0]); /* server doesn't read */ DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdin redirected (%d)\n",fo)); /* set stdout to /dev/null */ close(1); f1=dup2(fo,1); if(f1!=1) return(0); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdout redirected (%d)\n",fo)); /* set stderr to /dev/null */ close(2); f2=dup2(fo,2); if(f2!=2) return(0); close(fo); /* we are ready to go */ execlp(sp->command,sp->command,NULL); exit(0); } DSYSLOG(1,(LOG_DEBUG,"init_services(): Parent got child %d\n",fp->pid)); fp->fd=fieldes[1]; close(fieldes[0]); } /* close for */ sp=sp->next; } DSYSLOG(1,(LOG_DEBUG,"init_services(): Finished initialising services\n")); return(1); } void sigchld() { int pid; int s; struct service_s *sp; struct service_fds_s *fp; int fieldes[2]; pid=wait(&s); DSYSLOG(1,(LOG_DEBUG,"Received child %d termination signal\n",pid)); sp=sbase; while(sp!=NULL) { fp=sp->fdp; while(fp!=NULL) { if(fp->pid==pid) { DSYSLOG(1,(LOG_DEBUG,"Restarting service process for %s\n",sp->service)); close(fp->fd); /* close previous pipe */ DSYSLOG(1,(LOG_DEBUG,"init_services(): Creating process instance\n")); if(pipe(fieldes)<0) { /* Create a pipe for external communication */ signal(SIGCHLD,sigchld); return; } DSYSLOG(1,(LOG_DEBUG,"init_services(): Pipe created R:%d W:%d\n", fieldes[0],fieldes[1])); fp->fd=fieldes[1]; fp->pid=fork(); if(!(fp->pid)) { /* we are child */ int fo; int f0,f1,f2; net_close(); DSYSLOG(1,(LOG_DEBUG,"init_services(): I am the child %d\n",getpid())); close(fieldes[1]); /* child doesn't write */ /* lets get a null device for output */ fo=open("/dev/null",O_WRONLY,0); if(fo<0) exit(1); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: /dev/null open on %d\n",fo)); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: read pipe descriptior %d\n", fieldes[0])); /* set stdin from pipe */ close(0); f0=dup2(fieldes[0],0); if(f0) { DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdin redirect failed\n")); DSYSLOG(1,(LOG_DEBUG,"init_services(): child: %s\n", strerror(errno))); exit(1); } close(fieldes[0]); /* server doesn't read */ DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdin redirected (%d)\n",fo)); /* set stdout to /dev/null */ close(1); f1=dup2(fo,1); if(f1!=1) { exit(1); } DSYSLOG(1,(LOG_DEBUG,"init_services(): child: stdout redirected\n")); /* set stderr to /dev/null */ close(2); f2=dup2(fo,2); if(f2!=2) exit(1); close(fo); /* we are ready to go */ execlp(sp->command,sp->command,NULL); exit(0); } DSYSLOG(1,(LOG_DEBUG,"init_services(): Parent got child %d\n",fp->pid)); close(fieldes[0]); /* server doesn't read */ signal(SIGCHLD,sigchld); return; } fp=fp->next; } sp=sp->next; } signal(SIGCHLD,sigchld); } struct service_s *service_get_by_name(unsigned char *s) { struct service_s *sp; sp=sbase; while(sp!=NULL) { if(!strcmp(s,sp->service)) return(sp); sp=sp->next; } return(NULL); } void service_issue_command(unsigned char *cmd,int id,unsigned char *addr, unsigned char *oaddr) { db_service_t *dbp=NULL; /* DSYSLOG(1,(LOG_DEBUG,"service_issue_command: CMD=%s ID=%d ADDR=%s\n",cmd,id,addr)); */ dbp=db_get_service_by_id(id); DSYSLOG(1,(LOG_DEBUG,"service_issue_command: Got service list for client.\n")); if(dbp==NULL) return; while(dbp!=NULL) { unsigned char str[256]; sprintf(str,"%s %s %d %s %s\n",cmd,dbp->sp->service, id,addr,oaddr); DSYSLOG(1,(LOG_DEBUG,"service_issue_command: Sending command to %d\n", dbp->sp->rrfdp->pid)); write(dbp->sp->rrfdp->fd,str,strlen(str)); /* round robin */ dbp->sp->rrfdp=dbp->sp->rrfdp->next; if(dbp->sp->rrfdp==NULL) dbp->sp->rrfdp=dbp->sp->fdp; dbp=dbp->next; /* next service */ } return; } void service_free(void) { struct service_s *sp; struct service_fds_s *fsp; sp=sbase; while(sp!=NULL) { fsp=sp->fdp; while(fsp!=NULL) { sp->fdp=sp->fdp->next; close(fsp->fd); free(fsp); fsp=sp->fdp; } sbase=sp->next; free(sp); sp=sbase; } } void service_send_term(void) { struct service_s *sp; struct service_fds_s *fsp; sp=sbase; while(sp!=NULL) { fsp=sp->fdp; while(fsp!=NULL) { unsigned char str[32]; sprintf(str,"%s\n",SEXIT); write(fsp->fd,str,strlen(str)); close(fsp->fd); fsp->pid=-1; fsp=fsp->next; } sp=sp->next; } } void service_send_reload(void) { struct service_s *sp; struct service_fds_s *fsp; sp=sbase; while(sp!=NULL) { fsp=sp->fdp; while(fsp!=NULL) { unsigned char str[32]; sprintf(str,"%s\n",SRELOAD); write(fsp->fd,str,strlen(str)); fsp=fsp->next; } sp=sp->next; } } dhisd-5.3/genkeys.c000644 000000 000764 00000005736 10341072227 014241 0ustar00rootdhis000000 000000 /*- * 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 */ #include #include #include #include #ifdef QRC #include /* qrc_random() - Generates a random integer of n digits * n may be up to 1024 */ void qrc_random(mpz_t x,int n) { char buff[1024],temp[128]; static int seed=0; if(!seed) { seed++; srandom(time(NULL)); } memset(buff,0,256); memset(temp,0,128); do { sprintf(temp,"%lu",(unsigned long int)random()); strcat(buff,temp); } while(strlen(buff) < n); buff[n]='\0'; mpz_set_str(x,buff,10); return; } /* qrc_genkey() - Generates an integer of 100 digits being congruent * to 3 mod 4 * */ void qrc_genkey(mpz_t k) { int flag=1; do { mpz_t a,b; /* Get a prime number */ do qrc_random(k,100); while(!mpz_probab_prime_p(k,5)); /* Now see if it is congruent to 3 mod 4 */ mpz_init(a);mpz_init(b); mpz_set_ui(a,4); mpz_mod(b,k,a); mpz_set_ui(a,3); if(!mpz_cmp(a,b)) flag=0; mpz_clear(a); mpz_clear(b); } while(flag); } void show_key(mpz_t key,int n,char *s) { unsigned char buff[1024]; unsigned char chunk[128]; unsigned char *cp; int i; mpz_get_str(buff,10,key); cp=buff; for(i=0;i= 5 you will need to create and configure this file first. Main operation mode of the DHIS server: --------------------------------------- When executed the DHIS server reads its client's database (by default from /etc/dhis/db/dhis.db) into memory and proceeds to listening mode on a UDP port (by default 58800). When messages arrive the server responds accordingly, authenticates the clients (based on the keys and information loaded from the database) and marks them online. Furthermore the server keeps sending periodic checks to each and every client in order to verify that these are still connected. If a particular client fails to reply the server will consider it offline and mark it accordingly. Each client is identified to a server by a single ID number called the HostID. The new modular structure implements a means to mark these hosts online and offline. Instead of simply updating DNS, the DHIS server now sends the request to a child process which will, in its turn, perform the required updating function for the particular client. Likewise if the client is turned offline a similar request is submitted. What are DHIS 5 modules ? ------------------------- DHIS server R5 modules are sub-processes (engines) that execute a particular updating task. One module may update DNS whilst another may open a port in a firewall for the particular dynamic IP. Clients in DHIS R5 may subscribe services. The server 5 supports multiple modules/services. Thus, one particular client may be subscribed into the DNS service while another subscribed to the Firewall service while yet another to both. A module structure has the following fields: service tag - a single word identifying the module / must match service in dhis.db number of proceeses - the number of concurrent processes that implement the module command - the module engine process command to be executed Example of /etc/dhis/db/services.db ----------------------------------- Before executing dhisd make sure that you have created a valid /etc/dhis/db/services.db file. The syntax for the file is as follows: service_tag number_of_processes_command For example, let us assume we have two services named dns and fw (as service tags). One possible services.db could look like: ;------------------------------------------------------------------------------ ; This is a comment line dns 4 /etc/dhis/bin/dhis-dns-engine fw 2 /etc/dhis/bin/dhis-fw-engine ;------------------------------------------------------------------------------ Inter-process communication for modules: ---------------------------------------- On startup dhisd (the DHIS server) reads the services.db database and loads its lines into memory. In the example above two module references are loaded, dns and fw. It then checks how many processes it should spawn for each module (4 for dns and 2 for fw). For each module/process instance it creates a pipe, forks itself, redirects the child's stdin to the pipe and executes the command given in column 3. The idea behind the number of processes is one to allow load-sharing. The number of processes should be carefully chosen. For example a service with many clients may require several concurrent processes while a not so used service may have just one. It is up to each and everyone to decide how many processes per service should be spawned. The more processes the more concurrent updates may be performed, especially if these are likely to consume a reasonable ammount of time since they are processes sequencially by each process. Each of the processes is exactly the same and does exactly the same thing for each service. In the example above dhisd (the main process) would give birth to 4 dns processes plus 2 fw processes. Upon a DNS request the server passes the update task to one of its 4 dns childs. Upon a firewall request the request to one of its 2 firewall childs. The algorithm to decice which process to pass a request is a round-robin one. The first DNS update request will be sent to process 1, the second to 2, ... the 5th to 1 and so on ... If any one child dies the server re-executes it upon detection. The only thing to take into account is open file descriptors. DHIS by default uses 2 file descriptors (for UDP socket and log file) In addition, for each child it needs two file descriptors one of which is closed soon after creation. If a particular system has a maximum file descriptor number per process of say 30 (this should be OS specific and configurable): dhisd - 2 + 1 per child - 1 The server may spawn in total 27 child processes (all services * instances) It would be wise to leave a few descriptors available (for reloading database, etc) so therefore a maximum number of child processes could for be set to 25 or 24. Service Membership for clients ------------------------------ Defining which clients are subscribed to which services is straight forward. For each client record in dhis.db (between { and }) add a line starting with service and followed by the service tag name. For example: dhis.db: 1000 { hostpass mypassword service dns } 1001 { hostpass myotherpassword service fw } 1002 { hostpass someotherpassword service dns service fw } For each client record in dhis.db, if the service keyword is not specified the server will automatically try to bind it to a service with a tag of "default". Thus naming a service "default" in services.db makes all clients which don't have a service keyword subscribe to it automatically. Note however that by specifying a second service for a particular client the default service will no longer be used. In this case "service default" would also need to be added for that particular client record. The algorithm is simple: for each client: is there a list of services ? if so, update all those registered if not, is there a service called "default" ? if so, update using default otherwise do nothing for that client Database reloads ---------------- Whenever a database reload is issued (with SIGHUP to dhisd) the dhis.db file is re-read. However the services file is not reloaded and the child processes are kept open and running. Once services.db is updated the server dhisd needs to be terminated (wish SIGTERM) and restarted for these changes to take effect. Communication to the child processes ------------------------------------ Communication to child processes is achieved through pipes. Before forking for each service/instance engine process the server creates a pipe with 2 file descriptors. Once forked the server closes its reading descriptor for that pipe. The client closes its write descriptor. (The server sends messages to childs but not the other way around). The open descriptor is kept in a list of service/instance. Both stdout and stderr of child processes are redirected to /dev/null On each update the server simply writes a text message to the corresponding pipe terminated by a \n character. The child reads that message, executes it, and proceeds waiting for a new message. The language used between server and childs is formed by 5 commands, namely add, update, delete, reload and exit. This language is called the DHIS module interface and must be understood by all module engines that are to work with this DHIS server. server -> exit\n -> child The server is telling the child engine that it will terminate (possibly has been issued a SIGTERM) and therefore that the child should also terminate itself. server -> reload\n -> child The server is telling the child that it has reloaded its dhis.db file. Since the child may need itself to match the ID numbers to additional information, if required the child should also reload any external databases. A clear example of this is when a record is added to dhis.db and the child keeps a in-memory list of existing IDs and, for example, hostnames for DNS. The reload instruction tells the child process that (possibly) a new host has been added and therefore it should as well reload its own database file. server -> add service_tag id x.x.x.x\n -> child The server issues an online task to the child. Service tag is the name of the service (as in dhid.db and services.db), id is the client's ID number and x.x.x.x is its newly acquired dynamic IP address. The service_tag may be discarded in an engine that only does one thing. However one may wish to write an engine that does 2 or 3 different things and therefore, a means to differentiate these is also passed. server -> update service_tag id x.x.x.x y.y.y.y\n -> child Like in the add command the server tells the client that the IP address of client ID has changed. The child should then update its entries. A typical structure of update is that of issuing a delete followed by an add. x.x.x.x is the new IP address, y.y.y.y is the old IP address. server -> delete service_tag id x.x.x.x\n -> child The server tells the child that client id has been disconnected or is no longer reachable at the previous IP address. These are the 5 commands that need to be implemented in any dhisd module engine. The engine program: ------------------- The engine (child) process is a program and may be as simple as a shell script or as complex as wished. In its pure form it just does: while(true) read a line from stdin process a line Example engine for DNS: ----------------------- while(true) read line from stdin if(line == exit) exit if(line == reload) reload internal database if(line == add) { get hostname for passed id issue nsupdate for hostname with passed address } if(line==update) { get hostnamed for passed id issue nsupdate for hostname with passed address } if(line==delete) { get hostname from passed id issue nsupdate for hostname with an offline address } Writting engines ---------------- As previously said, module engines may easily be written and used with DHIS providing they comply with the above interface. Writting of engines is encouraged and we (at DHIS) would very much like to include any third party modules in our distributions. Modules may be for a particular task ... or many ... for a particular platform/os ... or many If you have any modules that you would like to share, please email support (at) dhis.org with your contributions and we will make them available for download by others. Example Engine: --------------- An example shell script engine is provided in engines/dhis-dummy-log-engine.sh This is a very simple engine module that only reads from the parent dhisd process and writes output lines to a log file in tmp. It may be used for testing purposes before trying to use a more "useful" engine. dhisd-5.3/engines/dhis-dummy-log-engine.sh000500 000000 000764 00000001111 07260063071 020467 0ustar00rootdhis000000 000000 #!/bin/sh echo [$$] [`date`] Starting >> /tmp/dhis-dummy-log-engine.log while true do read line echo [$$] `date` Received: $line >> /tmp/dhis-dummy-log-engine.log case $line in 'exit') exit 0 ;; 'reload') echo [$$] `date` RELOAD issued >> /tmp/dhis-dummy-log-engine.log ;; esac cmd=`echo $line | awk '{ print $1 }'` case $cmd in 'add') echo [$$] `date` $line >> /tmp/dhis-dummy-log-engine.log ;; 'update') echo [$$] `date` $line >> /tmp/dhis-dummy-log-engine.log ;; 'delete') echo [$$] `date` $line >> /tmp/dhis-dummy-log-engine.log ;; esac done