OSDN Git Service

Ver.0.8.1
authorwatanaby <watanaby@users.sourceforge.net>
Fri, 5 Apr 2013 02:20:09 +0000 (11:20 +0900)
committerwatanaby <watanaby@users.sourceforge.net>
Fri, 5 Apr 2013 02:20:09 +0000 (11:20 +0900)
87 files changed:
README [new file with mode: 0755]
conf/ipfwctrlmd.pl.sample [new file with mode: 0755]
conf/opengatemd.conf.sample [new file with mode: 0644]
conf/opengatemmng.conf.sample [new file with mode: 0644]
conf/rc.firewall.sample [new file with mode: 0644]
conf/warningmail.sample [new file with mode: 0644]
doc/Changes.html [new file with mode: 0644]
doc/GPL.txt [new file with mode: 0644]
doc/install.txt [new file with mode: 0644]
ezxml/GNUmakefile [new file with mode: 0644]
ezxml/Makefile [new file with mode: 0644]
ezxml/changelog.txt [new file with mode: 0644]
ezxml/ezxml.c [new file with mode: 0644]
ezxml/ezxml.h [new file with mode: 0644]
ezxml/ezxml.html [new file with mode: 0644]
ezxml/ezxml.txt [new file with mode: 0644]
ezxml/license.txt [new file with mode: 0644]
html/en/macauth.html [new file with mode: 0644]
html/en/macchk.html [new file with mode: 0644]
html/en/macdeny.html [new file with mode: 0644]
html/en/macfwd.html [new file with mode: 0644]
html/en/macreg.html [new file with mode: 0644]
html/en/macreturn.html [new file with mode: 0644]
html/en/macupdate.html [new file with mode: 0644]
html/en/warning.php [new file with mode: 0644]
html/index.html.var [new file with mode: 0644]
html/ja/macauth.html [new file with mode: 0644]
html/ja/macchk.html [new file with mode: 0644]
html/ja/macdeny.html [new file with mode: 0644]
html/ja/macfwd.html [new file with mode: 0644]
html/ja/macreg.html [new file with mode: 0644]
html/ja/macreturn.html [new file with mode: 0644]
html/ja/macupdate.html [new file with mode: 0644]
html/ja/warning.php [new file with mode: 0644]
html/macchk.js [new file with mode: 0644]
mdsrc/Makefile [new file with mode: 0644]
mdsrc/error.c [new file with mode: 0644]
mdsrc/getparam.c [new file with mode: 0644]
mdsrc/ipfw.c [new file with mode: 0644]
mdsrc/macdbcache.c [new file with mode: 0644]
mdsrc/managementdb.c [new file with mode: 0644]
mdsrc/opengatemd.c [new file with mode: 0644]
mdsrc/opengatemd.h [new file with mode: 0644]
mdsrc/packetcache.c [new file with mode: 0644]
mdsrc/pcap.c [new file with mode: 0644]
mdsrc/session.c [new file with mode: 0644]
mdsrc/ttlcheck.c [new file with mode: 0644]
mdsrc/udpserv.c [new file with mode: 0644]
mdsrc/util.c [new file with mode: 0644]
mdsrc/workdb.c [new file with mode: 0644]
mngsrc/Makefile [new file with mode: 0644]
mngsrc/alarms.c [new file with mode: 0644]
mngsrc/auth-ftps.c [new file with mode: 0644]
mngsrc/auth-ldap.c [new file with mode: 0644]
mngsrc/auth-pam.c [new file with mode: 0644]
mngsrc/auth-pop3s.c [new file with mode: 0644]
mngsrc/auth-rad.c [new file with mode: 0644]
mngsrc/auth.c [new file with mode: 0644]
mngsrc/cgi.c [new file with mode: 0644]
mngsrc/error.c [new file with mode: 0644]
mngsrc/getmac.c [new file with mode: 0644]
mngsrc/getparam.c [new file with mode: 0644]
mngsrc/ipfw.c [new file with mode: 0644]
mngsrc/managementdb.c [new file with mode: 0644]
mngsrc/messages.c [new file with mode: 0644]
mngsrc/opengatemchk.c [new file with mode: 0644]
mngsrc/opengatemfwd.c [new file with mode: 0644]
mngsrc/opengatemmail.c [new file with mode: 0644]
mngsrc/opengatemmng.h [new file with mode: 0644]
mngsrc/opengatemown.c [new file with mode: 0644]
mngsrc/opengatemreg.c [new file with mode: 0644]
mngsrc/opengatemup.c [new file with mode: 0644]
mngsrc/proc.c [new file with mode: 0644]
mngsrc/queue.c [new file with mode: 0644]
mngsrc/udpcli.c [new file with mode: 0644]
mngsrc/util.c [new file with mode: 0644]
mngsrc/workdb.c [new file with mode: 0644]
phpsrc/showlog.php [new file with mode: 0644]
phpsrc/showtable.php [new file with mode: 0644]
phpsrc/updatemactable.php [new file with mode: 0644]
phpsrc/updatevendortable.php [new file with mode: 0644]
rc.d/opengatemd [new file with mode: 0755]
sqlscript/createtablescript [new file with mode: 0644]
sqlscript/insertmacscript [new file with mode: 0644]
sqlscript/updatescript1 [new file with mode: 0644]
sqlscript/updatescript2 [new file with mode: 0644]
sqlscript/updatescript3 [new file with mode: 0644]

diff --git a/README b/README
new file mode 100755 (executable)
index 0000000..c09e4ca
--- /dev/null
+++ b/README
@@ -0,0 +1,38 @@
+This archive contains OpengateM sources & documentations
+
+Copyright (C) 2011 Opengate Project Team
+      Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+
+-----------------------------------------------------
+install documentation is in doc
+-----------------------------------------------------
+
+Content of this archive
+
+README         This file
+conf           Configuration files
+doc            Documentations
+ezxml          Library by other author
+html           HTML files for management systems
+mdsrc          C sources of daemon 'opengatemd'
+mngsrc         C sources of management systems
+phpsrc         PHP sources
+rc.d           Sample script for rc.d
+sqlscript      Scripts to access SQL
+
diff --git a/conf/ipfwctrlmd.pl.sample b/conf/ipfwctrlmd.pl.sample
new file mode 100755 (executable)
index 0000000..05cfc56
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/perl -U
+
+### Firewall control perl script drived by opengatesrv.cgi ###
+###   (In default this script is disabled. See opengatesrv.conf.)
+###   (Consider setting by ipfw rule or opengatesrv.conf before use this)
+
+($ipfwpath,$rulenumber,$clientaddr,$userid,$macaddr,$userproperty,$ipfwtagnumber,$interface)=@ARGV;
+close STDOUT; close STDERR; close STDIN;
+
+
+## add ipfw rules
+system "$ipfwpath","-q","add","$rulenumber",
+    "count","tag","$ipfwtagnumber","ip","from","any","to","any",
+    "MAC", "any", "$macaddr", "via", "$interface", "keep-state";
+
+system "$ipfwpath","-q","add","$rulenumber",
+    "count","tag","$ipfwtagnumber","ip","from","any","to","any",
+    "MAC", "$macaddr", "any", "via", "$interface", "keep-state";
+
+exit 0;
+
+__END__
+
+########### Above line is the end of interpreting#############
+
+                  PARAMETERS
+
+ $ipfwpath  = path to ipfw command
+ $rulenumber= ipfw rule number. one number for one client
+ $clientaddr= client machine's IP address
+ $userid    = user's ID.  Auth server ID is attached(usr@svr), if entered.
+ $macaddr   = MAC address for the client machine
+ $interface = Network interface card name
+
+                   CAUTIONS
+
+*Be care to execute quickly and without delay. 
+ This script runs in EXCLUSIVE mode. 
+
+*Be care to add least rule set. 
+ The rules are added PER each client. 
+
+*Be care to eliminate bug and security hole.
+ At modification, debug it perfectly in stand along mode.
+
+*If possible, the rule should be written in rc.firewall.
+ Following can be written in rc.firewall
+  Deny some protocol though authentication passed.
+  Allow to access some server without authentication.
+
+*Following might be written in this script.
+  Deny guest users to access internal network.
+  Deny a client having specific MAC address.
+  Forward some service to proxy server after authentication.
+  (Last one might be written in rc.firewall as the rule of other 
+   side interface which is not used by opengate)
+
+                SIMPLE SCRIPT
+
+If you are confused, return to the following default script.
+=====================================================
+#!/usr/bin/perl
+
+($ipfwpath,$rulenumber,$clientaddr,$userid,$macaddr,$userproperty,$ipfwtagnumber,$interface)=@ARGV;
+close STDOUT; close STDERR; close STDIN;
+
+
+## add ipfw rules
+system "$ipfwpath","-q","add","$rulenumber",
+    "count","tag","$ipfwtagnumber","ip","from","any","to","any",
+    "MAC", "any", "$macaddr", "via", "$interface", "keep-state";
+
+system "$ipfwpath","-q","add","$rulenumber",
+    "count","tag","$ipfwtagnumber","ip","from","any","to","any",
+    "MAC", "$macaddr", "any", "via", "$interface", "keep-state";
+
+exit 0;
+======================================================
+
diff --git a/conf/opengatemd.conf.sample b/conf/opengatemd.conf.sample
new file mode 100644 (file)
index 0000000..ece5083
--- /dev/null
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<Opengatemd ConfigVersion="0.6.0">
+
+       <!-- Debug dump level -->
+       <!-- Set 0 to write only open/close and error messages to syslog -->
+       <!-- Set 1 to write some information adding to 0 -->
+       <!-- Set 2 to write many information to syslog -->
+       <!-- Set 3 to write many information (including busy loop) to syslog -->
+       <Debug>1</Debug>
+
+       <!-- Syslog (local0, local1, .., local7)-->
+       <Syslog>
+               <Enable>1</Enable>
+               <Facility>local1</Facility>
+       </Syslog>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- MySql database (for mac address management) parameters -->
+       <MySqlDb>
+               <Server>localhost</Server>
+               <User>root</User>
+               <Password></Password>
+               <Database>opengatem</Database>
+       </MySqlDb>
+       
+       <!-- UDP server port to receive command from managing machine -->
+       <!-- Be care to set firewall properly to pass the udp packet -->
+       <UdpServerPort>4989</UdpServerPort>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- # Set hosts where opengateMmng are running # --> 
+       <!-- OpengateMmng acts as UDP client and Md(daemon) acts as server -->
+       <!-- DB update is transmitted immediately with this UDP --> 
+       <!-- (If failed, update is transmitted after cache timeout) --> 
+       <!-- Following set trusted UDP clients from which UDP are allowed -->
+       <!-- (Local host is trusted) -->
+       <!-- Be care to set firewall properly to pass the packet -->
+       <!--
+               <UdpClient>192.168.1.1</UdpClient>
+               <UdpClient>192.168.2.1</UdpClient>
+               <UdpClient>192.168.3.1</UdpClient>
+       -->
+       
+       <!-- ### MUST BE MODIFIED ## -->
+       <!--libpcap parameters -->
+       <Pcap>
+               <!-- device to sniff on -->
+               <Device>fxp0</Device>
+
+               <!-- snapshot length (=tcpdump defalut) -->
+               <SnapLength>68</SnapLength>
+
+               <!-- capture timeout in msec --> 
+               <Timeout>200</Timeout>
+
+               <!-- promiscuous mode(1=on) -->
+               <Promiscuous>0</Promiscuous>
+
+               <!-- pcap filter -->
+               <!-- %s is replaced with mac address of this pcap device -->
+               <Filter>(not ether src %s) and (not src net fe80::0/64)</Filter>
+       </Pcap>
+
+               <!-- valid initial ttl values in many systems -->
+       <!-- (http://noahdavids.org/self_published/TTL_values.html) -->
+       <ValidInitialTtl>30 32 60 64 128 200 255</ValidInitialTtl>
+
+       <!-- IPFW rule number range and tag number used by opengate -->
+       <IpfwRule>
+               <Min>10000</Min>
+               <Max>50000</Max>
+               <Interval>1</Interval>
+       </IpfwRule>
+
+       <!-- IPFW Tag number used in rc.firewall -->
+       <IpfwTagNumber>123</IpfwTagNumber>
+
+       <!-- if no packet relating to the address is detected -->
+       <!-- in this time length (second), -->
+       <!--  close the network and remove session -->
+       <UselessTimeout>3600</UselessTimeout>
+
+       <!-- interval (second) to run procedure for above checking -->
+       <UselessCheckInterval>3600</UselessCheckInterval>
+
+       <!-- Address Pair Cache Timeout: packet check skip Interval (second) -->
+       <CacheTimeout>1200</CacheTimeout>
+
+       <!-- Mac Address Cache Timeout: MAC DB Cache Hold Time (second) -->
+       <MacCacheTimeout>1200</MacCacheTimeout>
+
+       <!-- SQLite busy timeout (milli-seconds) -->
+       <SqliteBusyTimeout>100</SqliteBusyTimeout>
+
+       <!-- SQLite database file -->
+       <!-- for opengatemd work -->
+       <SqliteDbMd>/tmp/opengatemd.db</SqliteDbMd>
+
+       <!-- SQLite database file -->
+       <!-- for opengate session management -->
+       <SqliteDb>/tmp/opengate.db</SqliteDb>
+
+       <!-- programs -->
+       <MacCheckDaemon>opengatemd</MacCheckDaemon>
+
+       <!-- Related command path -->
+       <IpfwPath>/sbin/ipfw</IpfwPath>
+
+       <!-- ipfw exclusive exec lock timeout (second) -->
+       <LockTimeout>10</LockTimeout>
+
+       <!-- Lock file to prevent overlapped ipfw rule number -->
+       <!-- exclusive execution to opengate processes -->
+       <LockFile>/tmp/opengate.lock</LockFile>
+
+       <!-- Lock file to prevent overlapped daemon proc -->
+       <DaemonLockFile>/tmp/opengatemd.lock</DaemonLockFile>
+
+       <!-- Ipfw is opened via perl script(1) or direct from C(0) -->
+       <IpfwScript>
+               <Enable>0</Enable>
+               <Path>/etc/opengate/ipfwctrlmd.pl</Path>
+       </IpfwScript>
+
+       <!-- Related command path -->
+       <ArpPath>/usr/sbin/arp</ArpPath>
+       <NdpPath>/usr/sbin/ndp</NdpPath>
+
+       <!-- flag to write log at detecting nat/router insertion -->
+       <!-- if ShowNat=1, write at detecting unknown nat/router -->
+       <!-- if ShowRouter=1, write at detecting routers defined below --> 
+       <ShowNat>0</ShowNat>
+       <ShowRouter>0</ShowRouter>
+
+       <!-- subnets under the gateway  -->
+       <!--  use to ignore valid routers in nat detectiion --> 
+       <!--  if not set, nat/router under gateway is suspected as nat -->
+       <!-- [(ipv4 address)/(netmask length) (router hop count)] -->
+       <!--  examples -->
+       <!-- <SubnetHopCount>192.168.0.0/22 1</SubnetHopCount> -->
+       <!-- <SubnetHopCount>192.168.1.0/24 2</SubnetHopCount> -->
+       <!-- <SubnetHopCount>192.168.161.0/22 1</SubnetHopCount> -->
+       <!-- <SubnetHopCount>192.168.240.0/22 1</SubnetHopCount> -->
+       <!-- <SubnetHopCount>192.168.161.0/24 2</SubnetHopCount> -->
+
+       <!-- Caution: ExrtaSet cannot use in opengatemd -->
+       <!-- because one deamon controls all users -->
+
+</Opengatemd> 
+<!-- ## End of Configuration ## -->
diff --git a/conf/opengatemmng.conf.sample b/conf/opengatemmng.conf.sample
new file mode 100644 (file)
index 0000000..da0f5fb
--- /dev/null
@@ -0,0 +1,484 @@
+<?xml version="1.0"?>
+<Opengatemmng ConfigVersion="0.7.5">
+
+       <!-- #########################################################
+            ## Opengate gateway server hostname(FQDN or IP address)## -->
+       <OpengateServerName>opengate.og.saga-u.ac.jp</OpengateServerName>
+
+       <!-- Debug dump level -->
+       <!-- Set 0 to write only open/close and error messages to syslog -->
+       <!-- Set 1 to write some information adding to 0 -->
+       <!-- Set 2 to write many information to syslog -->
+       <!-- Set 3 to write more information to syslog -->
+       <Debug>1</Debug>
+
+       <!-- Syslog (local0, local1, .., local7)-->
+       <Syslog>
+               <Enable>1</Enable>
+               <Facility>local1</Facility>
+       </Syslog>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- network interface device name -->
+       <Device>fxp0</Device> 
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- auth server setting for administrators(watanaby,admin1,admin2) -->
+       <AuthServer>
+               <UserType>admin</UserType>
+               <Protocol>pop3s</Protocol>
+               <Address>192.168.0.2</Address>
+               <AcceptUsers>watanaby admin1 admin2</AcceptUsers>
+       </AuthServer>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- auth server setting for normal(not admin) users  -->
+       <AuthServer>
+               <Protocol>shibboleth</Protocol>
+               <UidAttribute>uid</UidAttribute>
+               <EppnAttribute>eppn</EppnAttribute>
+               <MailAttribute>mail</MailAttribute>
+       </AuthServer>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- # Set hosts where opengateMd (daemon) is running # --> 
+       <!-- Daemon acts as UDP server and opengateMmng as clients -->
+       <!-- DB update is transmitted immediately with this UDP --> 
+       <!-- (If failed, update is transmitted after cache timeout) --> 
+       <!-- Following set the servers [address port] receiving UDP -->
+       <!-- Be care to set firewall properly to pass the packet -->
+       <UdpServer>127.0.0.1 4989</UdpServer>
+       <!-- <UdpServer>192.168.1.1 4989</UdpServer> -->
+       <!-- <UdpServer>192.168.2.1 4989</UdpServer> -->
+       <!-- <UdpServer>192.168.3.1 4989</UdpServer> -->
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- MySql database (for mac address management) parameters -->
+       <MySqlDb>
+               <Server>localhost</Server>
+               <User>root</User>
+               <Password></Password>
+               <Database>opengatem</Database>
+       </MySqlDb>
+
+       <!-- ### MUST BE MODIFIED ## -->
+       <!-- Terminal allowed to register by owner oneself -->
+       <!-- The terminal type is checked by http-agent pattern 
+       having the form of "POSIX Extended Regular Expression".
+       Matching is sensitive to upper/lower case. 
+       If set NULL string, ALL agents are allowed -->
+       <!-- Can set multiple pattern tags. -->
+
+       <!-- TO ACTIVATE AGENT FILTER, REMOVE THIS COMMENT OUT TAG
+       <AllowableAgentPattern>iPhone|iPad|iPod|Android</AllowableAgentPattern>
+       <AllowableAgentPattern>Windows Phone|Windows CE</AllowableAgentPattern>
+       <AllowableAgentPattern>BlackBerry|RIM Tablet</AllowableAgentPattern>
+       -->
+
+       <!--  on click, network is opened in this time and closed (Sec) -->
+       <OpenTimeout>60</OpenTimeout>
+
+       <!-- SQLite busy timeout (milli-seconds) -->
+       <SqliteBusyTimeout>100</SqliteBusyTimeout>
+
+       <!-- SQLite database file -->
+       <!-- opengatemd work db -->
+       <SqliteDbMd>/tmp/opengatemd.db</SqliteDbMd>
+
+       <!-- opengatemmng work db -->
+       <SqliteDbMmng>/tmp/opengatemng.db</SqliteDbMmng>
+
+       <!-- SQLite database file -->
+       <!-- for opengate session management -->
+       <SqliteDb>/tmp/opengate.db</SqliteDb>
+
+       <!-- IPFW rule number range and tag number used by opengate -->
+       <IpfwRule>
+               <Min>10000</Min>
+               <Max>40000</Max>
+               <Interval>1</Interval>
+       </IpfwRule>
+
+       <!-- Ipfw is opened via perl script(1) or direct from C(0) -->
+       <IpfwScript>
+               <Enable>0</Enable>
+               <Path>/etc/opengate/ipfwctrlmd.pl</Path>
+       </IpfwScript>
+
+       <!-- IPFW Tag number used in rc.firewall -->
+       <IpfwTagNumber>123</IpfwTagNumber>
+
+       <!-- Related command path -->
+       <IpfwPath>/sbin/ipfw</IpfwPath>
+
+       <!-- ipfw exclusive exec lock timeout (second) -->
+       <LockTimeout>10</LockTimeout>
+
+       <!-- Lock file to prevent overlapped ipfw rule number -->
+       <!-- exclusive execution to opengate processes -->
+       <LockFile>/tmp/opengate.lock</LockFile>
+
+       <!-- daemon programs -->
+       <MacCheckDaemon>opengatemd</MacCheckDaemon>
+
+       <!-- Lock file to prevent overlapped daemon proc -->
+       <DaemonLockFile>/tmp/opengatemd.lock</DaemonLockFile>
+
+       <!-- Maximum count of register devices for one user -->
+       <MaxDevices>5</MaxDevices>
+
+       <!-- Mac Address Expiration Date(in MySql Date Format) -->
+       <LimitDate>adddate(last_day(adddate(now(),interval 15 day)),interval 1 day)</LimitDate>
+
+       <!-- The Date to Show Log in Web Page(in MySql Date Format) -->
+       <ShowLogAfter>adddate(now(), interval -1 month)</ShowLogAfter>
+
+       <!-- Available HTML languages (first lang is used as default) -->
+       <HtmlLangs>ja en</HtmlLangs>
+
+       <!-- Path to Apache Contents -->
+       <DocumentRoot>/usr/local/www/apache22/data</DocumentRoot>
+       <CgiDir>/cgi-bin</CgiDir>
+       <OpengateDir>/opengate</OpengateDir>
+
+       <!-- HTML Documents (in each language dir)-->
+       <DenyDoc>macdeny.html</DenyDoc>
+       <CheckDoc>macchk.html</CheckDoc>
+       <RegisterDoc>macreg.html</RegisterDoc>
+       <UpdateDoc>macupdate.html</UpdateDoc>
+       <AuthDoc>macauth.html</AuthDoc>
+       <AuthAdminDoc>macauth.html</AuthAdminDoc>
+       <OwnRegisterDoc>macreg.html</OwnRegisterDoc>
+       <OwnUpdateDoc>macupdate.html</OwnUpdateDoc>
+       <FwdDoc>macfwd.html</FwdDoc>
+       <ReturnDoc>macreturn.html</ReturnDoc>
+
+       <!-- timeout for above return jump -->
+       <ReturnWaitTime>10</ReturnWaitTime>
+
+       <!-- Related command path -->
+       <ArpPath>/usr/sbin/arp</ArpPath>
+       <NdpPath>/usr/sbin/ndp</NdpPath>
+
+       <!-- CGIs -->
+       <CheckCgi>opengatemchk.cgi</CheckCgi>
+       <RegisterCgi>opengatemreg.cgi</RegisterCgi>
+       <UpdateCgi>opengatemup.cgi</UpdateCgi>
+       <OwnCgi>opengatemown.cgi</OwnCgi>
+       <JumpCgi>opengatemown.cgi</JumpCgi> <!-- to insert page, modify this -->
+       <FwdCgi>opengatemfwd.cgi</FwdCgi>
+
+       <!-- maximum request count per day to modify mac registraion -->
+       <MaxMacModifyPerDay>30</MaxMacModifyPerDay>
+
+       <!-- cookie name to hold the dmin/user authentication state -->
+       <AuthAdminCookie>OpengatemAdmin</AuthAdminCookie>
+       <AuthUserCookie>OpengatemUser</AuthUserCookie>
+
+       <!-- Limit Date Warning Mail -->
+       <Mail>
+               <CmdPath>/bin/rmail</CmdPath>
+               <Content>/etc/opengate/warningmail</Content>
+               <Timing>date(now())=date(adddate(limitDate, interval -7 day)) or date(now())=date(adddate(limitDate, interval -1 day))</Timing>
+       </Mail>
+
+       <!-- Separate char between userID and extraID [userID@extraID] -->
+       <UserIdSeparator>@</UserIdSeparator>
+
+</Opengatemmng> 
+<!-- ## End of Configuration ## -->
+
+
+<!-- ## Following is only documentation ## -->
+
+
+<!--   ######################################
+       ###### About AuthServer setting ######
+       
+       ########### Format ############# 
+               {a|b}: a or b, set one of them 
+               [ x ]: x is optional
+                -x- : x is a value
+       
+       #### TYPE 1 (POP or FTP) ####
+       <AuthServer>
+               <Protocol>{pop3|pop3s|ftp|ftpse|ftpsi}</Protocol>
+               <Address>{-hostname-|-ip_address-}</Address>
+               [ <Port>-portno-</Port> ]
+               [ <Timeout>-seconds-</Timeout> ]
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+       </AuthServer>
+       #   AuthOK, if request by <Protocol> is accepted by <Address>.
+       #   Address is FQDN or IP address       
+       #   If <Port> is not defined, port number in /etc/services is used.
+       #   The request is aborted at <Timeout> seconds.
+       #   If <Timeout> is not defined, system value is used.
+       #   pop3s is SSLed pop3
+       #   ftpse is SSLed ftp run in Explicit mode. 
+       #   ftpsi is SSLed ftp run in Implicit mode.
+
+       #   MailDomain indicates the domain to which warning mail is sent.
+       #    if userid=watanaby and MailDomain=og.saga-u.ac.jp, 
+       #     time-limit-warning-mail is sent to watanaby@og.saga-u.ac.jp.
+
+       #### TYPE 2 (PAM) ####
+       <AuthServer>
+               <Protocol>pam</Protocol>
+               [ <ServiceName>-servicename_in_pam_conf-</ServiceName> ]
+               [ <Timeout>-second-</Timeout> ]
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+       </AuthServer>
+       #   Auth by PAM
+       #   If not define <ServiceName>, "opengate" is used in "pam.conf".
+
+       #### TYPE 3 (RADIUS) ####
+       <AuthServer>
+               <Protocol>radius</Protocol>
+               [ <ConfFile>-path_to_radius_conf-</ConfFile> ]
+               [ <Timeout>-second-</Timeout> ]
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+       </AuthServer>
+       #   Auth by RADIUS
+       #   If not define <ConfigFile>, "/etc/radius.conf" is used.
+       
+       #### TYPE 4 (LDAP) ####
+       <AuthServer>
+               <Protocol>ldap</Protocol>
+               <Uri>-uri-of-ldap-server-</Uri>
+               <BaseDN>-ldap_base_dn_to_search-</BaseDN>
+               [ <Timeout>-second-</Timeout> ]
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+       </AuthServer>
+       #   Auth by LDAP/LDAPS
+       #   Uri examples
+       #     'ldap://foo.bar.com' for NonSSL
+       #     'ldaps://foo.bar.com' for SSL
+       #     'ldaps://foo.bar.com:1234' to use specific port
+       
+       #### TYPE 5 (ACCEPT or DENY) ####
+       <AuthServer>
+               <Protocol>{accept|deny}</Protocol>
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+       </AuthServer>
+       #   The user is accepted or denied without inquiring auth.
+       #   ***This setting is prepared for debugging***
+
+       #### TYPE 6 (Shibboleth) ####
+       <AuthServer>
+                <Protocol>shibboleth</Protocol>
+               <UidAttribute>-env-vars-for-uid-</UidAttribute>
+               [<OrgAttribute>-env-vars-for-uid-</OrgAttribute>]
+               [<EppnAttribute>-env-vars-for-eppn-</EppnAttribute>]
+               [<MailAttribute>-env-vars-for-mail-address-</MailAttribute>]
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+        </AuthServer>
+
+       #   Auth by Shibboleth
+
+       #   'UidAttiribute' means the environment variable having UserId
+       #       in the organization.
+       #     E.G., 
+       #     <UidAttribute>uid persistent-id targeted-id</UidAttribute>
+       #       left item has priority, if not found, search next item
+
+       #   'OrgAttiribute' means the environment variable having Organization
+       #     E.G., 
+       #     <OrgAttribute>o affiliation Shib-Identity-Provider</OrgAttribute>
+       #       left item has priority, if not found, search next item
+
+       #   'EppnAttiribute' means the environment variable having
+       #     ePPN(edu person pricipal name 'user@org') or other global id 
+       #     E.G., 
+       #     <EppnAttribute>eppn mail</EppnAttribute>
+       #       left item has priority, if not found, search next item
+
+       #     If Uid and Eppn are defined, Uid has priority.
+
+       #   'MailAttiribute' means the environment variable for mail-address
+       #     E.G., 
+       #     <MailAttribute>mail</MailAttribute>
+       #       left item has priority, if not found, search next item
+
+       #   Set 'opengatemXXX.cgi as 'shibboleth' in .htaccess
+       #    <FILES opengatemXXX.cgi>
+       #      AuthType shibboleth
+       #      ShibRequestSetting requireSession 1
+       #      ShibRequireSession On
+       #      ShibUseHeaders On
+       #      require valid-user
+       #    </FILES>
+       #    ***Only one Shibboleth setting is permitted in conf***
+
+       #### TYPE 7 (Http Basic) ####
+       <AuthServer>
+                <Protocol>httpbasic</Protocol>
+               [<MailDomain>-mail-address-after-@-</MainDomain>]
+        </AuthServer>
+
+       #   Auth by http-basic
+       #   Set 'opengatemXXX.cgi' as 'Basic' in .htaccess
+       #    <FILES opengateXXX.cgi>
+       #      AuthType Basic
+       #      AuthServerFile /tmp/passwd.dat
+       #      AuthName "User"
+       #      require valid-user
+       #    </FILES>
+       #   environment variable REMOTE_USER is used for userid
+       #   ***Only one Httpbasic setting is permitted in conf***
+-->    
+
+<!--   ######## Examples of Auth Server Setting ##############
+       <AuthServer>
+               <Protocol>pop3s</Protocol>
+               <Address>pop.saga-u.ac.jp</Address>
+               <Timeout>30</Timeout>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+       <AuthServer>
+               <Protocol>ldap</Protocol>
+               <Uri>ldaps://ldap.saga-u.ac.jp</Uri>
+               <BaseDN>ou=people,dc=saga-u,dc=ac,dc=jp</BaseDN>
+               <Timeout>5</Timeout>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+       <AuthServer>
+               <Address>192.168.0.1</Address>
+               <Protocol>ftpsi</Protocol>
+               <Timeout>15</Timeout>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+       <AuthServer>
+               <Protocol>radius</Protocol>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+       <AuthServer>
+               <Protocol>pam</Protocol>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+       <AuthServer>
+               <Protocol>shibboleth</Protocol>
+               <UidAttribute>uid</UidAttribute>
+               <OrgAttribute>o</OrgAttribute>
+               <EppnAttribute>eppn</EppnAttribute>
+               <MailAttribute>mail</MailAttribute>
+       </AuthServer>
+
+       <AuthServer>
+               <Protocol>httpbasic</Protocol>
+               <MailDomain>og.saga-u.ac.jp</MainDomain>
+       </AuthServer>
+
+-->
+
+<!--   ####### An Example of Multiple authentication servers ######
+       If multiple auth servers are set, check these servers sequentially.
+       When denied by first server, request is sent to the next one.
+       When accepted by a server, following servers are ignored.
+
+       <AuthServer>
+               setting for first priority
+       </AuthServer>
+       <AuthServer>
+               setting for second priority
+       </AuthServer>
+       <AuthServer>
+               setting for third priority
+       </AuthServer>
+
+-->
+<!--   ######################################
+       #### Config for exceptional users ####
+ -->
+<!--   ###### about ExtraSet #######
+
+     <ExtraSet> overwritten on default settings 
+
+       You can switch parameter values by userID and extraID 
+       entered as [userID@extraID] in userID field on auth page.
+       
+       Each <ExtraSet> has conditions such as <.. ExtraId="aaa"> or 
+       <.. UserIdPattern="bbb">, or etc.
+       The conditions is compared with the string entered in 
+       userID field.
+
+       When you set the condition as <.. ExtraId="aaa">, 
+        [extraId] equal to [aaa] is matched (eg, xx@aaa).
+               
+       When you set the condition as <.. UserIdPattern="bbb">,
+        [userId] including [bbb] is matched (eg, xbbbx@xx).
+
+       When you set the condition as <.. UserExtraPattern="bbb">,
+        [userId@extraId] including [bbb] is matched (eg, xbbbx@xx, aa@xbbbx).
+
+       When you set the condition as <.. UserExtraPatternNot="bbb">,
+        string NOT including [bbb] is matched.
+
+       Pattern has the form of "POSIX Extended Regular Expression".
+       Matching is insensitive to upper/lower case.
+       
+       The <ExtraSet> having multi-conditions is used when both are true.
+       Omitted condition matched to every string. 
+
+       The first matched <ExtraSet> is used, at existing many matched set.
+
+       The paremeters in <ExtraSet> overwrite the default value.
+       When a parameter is not found in <ExtraSet>, the default is used.
+       
+       When userID is entered without extraID, ExtraId matchs to "default".
+       Thus if you want to find [user1] only in default server,
+       use as <ExtraSet ExtraId="default" UserIdPattern="^user1$">.
+
+       Example1 is used when user entered as [any_user@guest],
+       where "any_user" is any string.
+       It means that [xxx@guest] uses different auth server.
+
+       Example2 is used when [anyuser@admin].
+       It means that [xxx@adimin] can use many auth servers.
+
+       Example3 is used when [user1] or [user2].
+       It means that [user1] and [user2] emerge specific syslog(eg. mail).
+-->
+<!--    ## ExtraSet sample 1 ##
+       <ExtraSet ExtraId="guest">
+               <AuthServer>
+                       <Address>192.168.0.1</Address>
+                       <Protocol>ftp</Protocol>
+               </AuthServer>
+               <IpfwTagNumber>999</IpfwTagNumber>
+
+       </ExtraSet>
+        ## End of sample 1 ##
+-->
+<!--    ## ExtraSet sample 2 ##
+       <ExtraSet ExtraId="admin">
+               <AuthServer>
+                       <Protocol>pam</Protocol>
+               </AuthServer>
+               <AuthServer>
+                       <Address>192.168.0.1</Address>
+                       <Protocol>pop3s</Protocol>
+                       <Timeout>10</Timeout>
+               </AuthServer>
+               <AuthServer>
+                       <Address>192.168.0.2</Address>
+                       <Protocol>ftp</Protocol>
+                       <Timeout>10</Timeout>
+               </AuthServer>
+       </ExtraSet>
+        ## End of sample 2 ##  
+-->
+<!--    ## ExtraSet sample 3 ##
+       <ExtraSet ExtraId="default" UserIdPattern="^user1$|^user2$">    
+               <Syslog>
+                       <Enable>1</Enable>
+                       <Facility>local2</Facility>
+               </Syslog>
+       </ExtraSet>
+       ## Caution: if no userid is entered, set as userid="?"  ##
+        ## End of sample 3 ##
+-->
diff --git a/conf/rc.firewall.sample b/conf/rc.firewall.sample
new file mode 100644 (file)
index 0000000..c729622
--- /dev/null
@@ -0,0 +1,80 @@
+### set these to your outside interface network and netmask and ip
+oif="fxp1"
+onet="192.168.0.0"
+omask="255.255.255.0"
+oip="192.168.0.124"
+onet6="fe80::"
+oprefixlen6="64"
+oip6="fe80::202:b3ff:fe0a:c30e"
+
+### set these to your inside interface network and netmask and ip
+iif="fxp0"
+inet="192.168.1.0"
+imask="255.255.255.0"
+iip="192.168.1.1"
+inet6="2001:2f8:22:802::"
+iprefixlen6="64"
+iip6="2001:2f8:22:802::1"
+
+fwcmd="/sbin/ipfw"
+
+### reset firewall rules
+$fwcmd -q -f flush
+
+### divert packet to NATD 
+$fwcmd add 1 divert natd ip4 from any to any via ${oif}
+
+### Stop spoofing
+$fwcmd add deny all from ${inet}:${imask} to any in via ${oif}
+$fwcmd add deny all from ${onet}:${omask} to any in via ${iif}
+
+### Allow from / to myself
+$fwcmd add pass all from me to any
+$fwcmd add pass all from any to me
+
+### Allow DNS queries out in the world
+### (if DNS is on localhost, delete passDNS)
+$fwcmd add pass udp from any 53 to any
+$fwcmd add pass udp from any to any 53
+$fwcmd add pass tcp from any to any 53
+$fwcmd add pass tcp from any 53 to any
+
+### Allow RA RS NS NA Redirect...
+$fwcmd add pass ipv6-icmp from any to any
+
+# Allow IP fragments to pass through
+$fwcmd add pass all from any to any frag
+
+# Allow RIPng
+$fwcmd add pass udp from fe80::/10 521 to ff02::9 521
+$fwcmd add pass udp from fe80::/10 521 to fe80::/10 521
+
+############Taggged rules############################
+## Opengate add following rules after authentication (at Layer2 check)
+## (Need 'net.link.ether.ipfw=1' in /etc/sysctl.conf to enable L2 check)
+##   count tag 123 ip from any to any MAC any <CliMac> keep-state via ..
+##   count tag 123 ip from any to any MAC <CliMac> any keep-state via ..
+## 123 : Can be set as IpfwTagNumber of opengatesrv.conf
+## <CliMac> :MAC address of authenticated client
+
+$fwcmd add 60000 allow ip from any to any tagged 123
+
+################################################
+
+## At L2 check, throw all packets to L3 check after tagged
+$fwcmd add 60010 pass ip from any to any MAC any any
+
+### Forwarding IPv4 http connection from unauth client 
+$fwcmd add 60100 fwd localhost tcp from ${inet}:${imask} to any 80
+$fwcmd add 60100 fwd localhost tcp from ${inet}:${imask} to any 443
+
+### Allow http reply for forwarded request 
+### (it is sent out from localhost but has original source address)
+$fwcmd add 60110 pass tcp from any 80 to any out
+$fwcmd add 60120 pass tcp from any 443 to any out
+
+# TCP reset notice message for IPv6 http connection
+$fwcmd add 60130 reset tcp from any to any 80
+$fwcmd add 60140 reset tcp from any to any 443
+
+
diff --git a/conf/warningmail.sample b/conf/warningmail.sample
new file mode 100644 (file)
index 0000000..d9edb23
--- /dev/null
@@ -0,0 +1,21 @@
+From opengate@cc.saga-u.ac.jp
+Mime-Version: 1.0
+Content-Type: text/plain; charset=ISO-2022-JP
+Content-Transfer-Encoding: 7bit
+Subject: Mac Address Registration
+To: %%MAILADDRESS%%
+
+
+\e$BC<KvEPO?4|8B$N$*CN$i$;\e(B
+
+\e$B$"$J$?$,EPO?$5$l$F$$$kC<Kv\e(B[%%DEVICENAME%%]\e$B$,!"\e(B[%%LIMITDATE%%]\e$B$K$*$$$F;HMQ4|8B$H$J$j$^$9!#7QB3;HMQ$r4uK>$5$l$k>l9g$O2<5-$N%Z!<%8$G99?7$7$F$/$@$5$$!#3XFb%"%/%;%9$N$_M-8z$G$9!#$J$*99?7=hM}$O4|8B$r2a$.$F$bM-8z$G$9!#\e(B
+
+http://www.cc.saga-u.ac.jp/opengate/mup.php
+
+\e$B$3$N%a!<%k$OAw?.@lMQ%"%I%l%9$+$iAw?.$7$F$$$^$9!#JV?.$7$F$bFO$-$^$;$s!#\e(B
+
+---
+Your device [%%DEVICENAME%%] will reach the limit date at [%%LIMITDATE%%].
+Please update the registration in the following page.
+
+http://www.cc.saga-u.ac.jp/opengate/mup.php
diff --git a/doc/Changes.html b/doc/Changes.html
new file mode 100644 (file)
index 0000000..579238a
--- /dev/null
@@ -0,0 +1,218 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+       <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
+       <TITLE></TITLE>
+</HEAD>
+<BODY LANG="en-US" BGCOLOR="#fafff0" DIR="LTR">
+
+<H3>
+OpengateM History</H3>
+<DL>
+       <DT>Ver.0.1.0 at 2011.6.22 
+       </DT><DD>
+       Initial Version for daemon (opengatemd). 
+       <DT>Ver.0.2.0 at 2011.7.22 
+       </DT><DD>
+       Added mac address management web systems.
+       </DD>
+       <DT>Ver.0.3.0 at 2011.8.29 
+       </DT><DD>
+       Restructured files.
+       </DD>
+       <DT>Ver.0.4.0 at 2011.10.17 
+       </DT><DD>
+       Added various authentication protocols to web system.
+       </DD>
+       <DT>Ver.0.5.0 at 2011.11.2 
+       </DT><DD>
+       Restructured files.
+       </DD>
+       <DT>Ver.0.5.1 at 2011.11.4 
+       </DT><DD>
+       Added code to check error (opengatemmail).
+       </DD>
+       <DT>Ver.0.5.2 at 2011.11.10 
+       </DT><DD>
+       Fixed error in insertmacscript (opengatemsql).
+       </DD>
+       <DT>Ver.0.5.3 at 2011.11.21 
+       </DT><DD>
+       Added terminal status in mac check page (opengatemchk).
+       </DD>
+       <DT>Ver.0.5.4 at 2011.11.22 
+       </DT><DD>
+       Fixed error to remain useless rules (opengatemd).
+       </DD>
+       <DT>Ver.0.5.5 at 2011.11.24 
+       </DT><DD>
+       Modified the checking of useless rules (opengatemd).
+       </DD>
+       <DT>Ver.0.5.6 at 2011.12.8 
+       </DT><DD>
+       Modified the checking of useless rules (opengatemd).
+       </DD>
+       <DT>Ver.0.5.7 at 2011.12.28 
+       </DT><DD>
+       Added organization info in shibboleth auth(opengatemup/mchk/mreg).
+       </DD>
+       <DT>Ver.0.5.8 at 2012.01.18 
+       </DT><DD>
+       Added perl control. Added userid as comment on ipfw rule list(opengatemd). 
+       </DD>
+       <DT>Ver.0.5.9 at 2012.01.27 
+       </DT><DD>
+       Modified ttl check to consider valid router under the gateway(opengatemd). 
+       </DD>
+       <DT>Ver.0.5.10 at 2012.01.31 
+       </DT><DD>
+       Added message for update success(opengatemup).
+       </DD>
+       <DT>Ver.0.5.11 at 2012.02.03 
+       </DT><DD>
+       Modified ttl check(opengatemd).
+       </DD>
+       <DT>Ver.0.5.12 at 2012.02.06 
+       </DT><DD>
+       Modified packet check loop to reduce the load(opengatemd).
+       </DD>
+       <DT>Ver.0.6.0 at 2012.02.10
+       </DT><DD>
+       Added udp send from cgi to daemon(opengatemreg/mup/md).
+       </DD>
+       <DT>Ver.0.6.1 at 2012.02.14
+       </DT><DD>
+       Added mac address in cache. Changed update input form(opengatemup/md).
+       </DD>
+       <DT>Ver.0.6.2 at 2012.02.17
+       </DT><DD>
+       Removed useless files (opengatemd).
+       </DD>
+       <DT>Ver.0.7.0 at 2012.03.23
+       </DT><DD>
+       Added registration by owner without admin(opengatemown). 
+       </DD>
+       <DT>Ver.0.7.1 at 2012.04.2
+       </DT><DD>
+       Added procedures for captive portal (opengatemown). 
+       </DD>
+       <DT>Ver.0.7.2 at 2012.04.6
+       </DT><DD>
+       Modified usage log form (opengatemown/mup). 
+       </DD>
+       <DT>Ver.0.7.3 at 2012.04.12
+       </DT><DD>
+       Modified pcap filter rule in conf file(opengatemd). 
+       </DD>
+       <DT>Ver.0.7.4 at 2012.04.27
+       </DT><DD>
+       Added terminal type check at registration by owner(opengatemown).
+       </DD>
+       <DT>Ver.0.7.5 at 2012.04.28
+       </DT><DD>
+       Modified terminal type check(opengatemown).
+       </DD>
+       <DT>Ver.0.7.6 at 2012.05.02
+       </DT><DD>
+       Modified terminal type check, udp client check(opengatemown).
+       </DD>
+       <DT>Ver.0.7.7 at 2012.05.07
+       </DT><DD>
+       Modified terminal type check (opengatemown).
+       </DD>
+       <DT>Ver.0.7.8 at 2012.05.17
+       </DT><DD>
+       Modified usage log format in update page (opengatemup).
+       </DD>
+       <DT>Ver.0.7.9 at 2012.05.31
+       </DT><DD>
+       Added cache size check (opengatemd).
+       </DD>
+       <DT>Ver.0.7.10 at 2012.07.05
+       </DT><DD>
+       Added arp/ndp check (opengatemd).
+       </DD>
+       <DT>Ver.0.7.11 at 2012.07.12
+       </DT><DD>
+       Removed arp/ndp check (opengatemd).
+       Added start time of each day in log of update page (opengatemup). 
+       </DD>
+       <DT>Ver.0.7.12 at 2012.07.30
+       </DT><DD>
+       Modified code to get mac from arp (opengatemreg/mown).
+       </DD>
+       <DT>Ver.0.7.13 at 2012.07.31
+       </DT><DD>
+       Modified comments in conf file (opengatemmng/md).
+       </DD>
+       <DT>Ver.0.7.14 at 2012.09.07
+       </DT><DD>
+       Added mac db cache besides address pair cache (opengatemd).
+       </DD>
+       <DT>Ver.0.7.15 at 2012.10.09
+       </DT><DD>
+       Added session info log. added cache sync at session end (opengatemd).
+       </DD>
+       <DT>Ver.0.7.16 at 2012.10.31
+       </DT><DD>
+       Changed UDP server port to asynchronous mode (opengatemd).
+       </DD>
+       <DT>Ver.0.7.17 at 2012.11.6
+       </DT><DD>
+       Fixed error displaying error message and mail string (opengatemown).
+       </DD>
+       <DT>Ver.0.7.18 at 2012.11.8
+       </DT><DD>
+       Added string checks. added warning page (opengatemown).
+       </DD>
+       <DT>Ver.0.7.19 at 2012.11.23
+       </DT><DD>
+       Added check for addition of ipfw rule  (opengatemd).
+       </DD>
+       <DT>Ver.0.7.20 at 2012.12.19
+       </DT><DD>
+       Added sqlite3_busy_timeout to reduce db-lock error (opengatem-all).
+       </DD>
+       <DT>Ver.0.7.21 at 2012.12.24
+       </DT><DD>
+       Added check of process using same ipfw rule at closing unmatched session (opengatemd).
+       </DD>
+       <DT>Ver.0.7.22 at 2013.2.27
+       </DT><DD>
+       Modified log list in update page. Added error messages. Added
+       ipfw rule check at packet check (opengatemreg/mown/mup/md)
+       </DD>
+       <DT>Ver.0.7.23 at 2013.2.28
+       </DT><DD>
+       Modified code for getting info from shibboleth (opengatemreg/mown/mup)
+       </DD>
+       <DT>Ver.0.7.24 at 2013.3.1
+       </DT><DD>
+       Modified the setting of conf extra set (opengatemreg/mown/mup)
+       </DD>
+       <DT>Ver.0.7.25 at 2013.3.4
+       </DT><DD>
+       Added search patterns for conf extra set (opengatemreg/mown/mup)
+       </DD>
+       <DT>Ver.0.7.26 at 2013.3.5
+       </DT><DD>
+       Added mac database updating sqript samples (opengatemsql)
+       </DD>
+       <DT>Ver.0.7.27 at 2013.3.15
+       </DT><DD>
+       Changed opengatemd.db to hold open-state on daemon (opengatemd)
+       </DD>
+       <DT>Ver.0.8.0 at 2013.3.19
+       </DT><DD>
+       Changed ipfw control from ip to mac[need
+       net.link.ether.ipfw=1](opengatemd). <br>
+       Changed script to create vendor table(opengatemsql)
+       </DD>
+       <DT>Ver.0.8.1 at 2013.3.21
+       </DT><DD>
+       Fixed bug in script to create vendor table(opengatemsql)
+       </DD>
+</DL>
+
+</BODY>
+</HTML>
diff --git a/doc/GPL.txt b/doc/GPL.txt
new file mode 100644 (file)
index 0000000..b830682
--- /dev/null
@@ -0,0 +1,341 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/doc/install.txt b/doc/install.txt
new file mode 100644 (file)
index 0000000..81a7dbf
--- /dev/null
@@ -0,0 +1,2 @@
+Refer http://www.cc.saga-u.ac.jp/opengate/opengatem/index-e.html
+
diff --git a/ezxml/GNUmakefile b/ezxml/GNUmakefile
new file mode 100644 (file)
index 0000000..9299375
--- /dev/null
@@ -0,0 +1,63 @@
+# Makefile
+#
+# Copyright 2005 Aaron Voisine <aaron@voisine.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+CC = gcc
+AR = ar
+RM = rm -f
+CFLAGS = -Wall -O2
+DEBUG_CFLAGS = -O0 -g
+OBJS = ezxml.o
+LIB = libezxml.a
+TEST = ezxmltest
+ifdef NOMMAP
+CFLAGS += -D EZXML_NOMMAP
+endif
+ifdef DEBUG
+CFLAGS += $(DEBUG_CFLAGS)
+endif
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+       $(AR) rcs $(LIB) $(OBJS)
+
+nommap: CFLAGS += -D EZXML_NOMMAP
+nommap: all
+
+debug: CFLAGS += $(DEBUG_CFLAGS)
+debug: all
+
+test: CFLAGS += $(DEBUG_CFLAGS)
+test: $(TEST)
+
+$(TEST): CFLAGS += -D EZXML_TEST
+$(TEST): $(OBJS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS)
+
+ezxml.o: ezxml.h ezxml.c
+
+.c.o:
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+       $(RM) $(OBJS) $(LIB) $(TEST) *~
\ No newline at end of file
diff --git a/ezxml/Makefile b/ezxml/Makefile
new file mode 100644 (file)
index 0000000..c8a99fc
--- /dev/null
@@ -0,0 +1,62 @@
+# Makefile
+#
+# Copyright 2004, 2005 Aaron Voisine <aaron@voisine.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+CC = gcc
+AR = ar
+RM = rm -f
+CFLAGS = -Wall -O2
+OBJS = ezxml.o
+LIB = libezxml.a
+TEST = ezxmltest
+
+.if defined(NOMMAP) || make(nommap)
+CFLAGS += -D EZXML_NOMMAP
+.endif
+.if defined(DEBUG) || make(debug) || make(test)
+CFLAGS += -O0 -g
+.endif
+.if make($(TEST)) || make(test)
+CFLAGS += -D EZXML_TEST
+.endif
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+       $(AR) rcs $(LIB) $(OBJS)
+
+test: $(TEST)
+
+debug: all
+
+nommap: all
+
+$(TEST): $(OBJS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS)
+
+ezxml.o: ezxml.h ezxml.c
+
+.c.o:
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+       $(RM) $(OBJS) $(LIB) $(TEST) *~
\ No newline at end of file
diff --git a/ezxml/changelog.txt b/ezxml/changelog.txt
new file mode 100644 (file)
index 0000000..f05f918
--- /dev/null
@@ -0,0 +1,54 @@
+ezXML 0.8.6
+- fixed a bug in ezxml_add_child() that can occur when adding tags out of order
+- for consistency, ezxml_set_attr() now returns the tag given
+- added ezxml_move() and supporting functions ezxml_cut() and ezxml_insert()
+- fixed a bug where parsing an empty file could cause a segfault
+
+ezXML 0.8.5
+- fixed ezxml_toxml() to not output siblings of tag being converted
+- fixed a segfault when ezxml_set_attr() was used on a new root tag
+- added ezxml_name() function macro
+- all external functions now handle NULL ezxml_t structs without segfaulting
+
+ezXML 0.8.4
+- fixed to compile under win-doze when NOMMAP make option is set
+- fixed a bug where ezxml_toxml() could segfault if tag offset is out of bounds
+- ezxml_add_child() now works properly when tags are added out of order
+- improved error messages now include line numbers
+- fixed memory leak when entity reference is shorter than replacement text
+- added ezxml_new_d(), ezxml_add_child_d(), ezxml_set_txt_d() and 
+  ezxml_set_attr_d() function macros as wrappers that strdup() their arguments
+
+ezXML 0.8.3
+- fixed a UTF-16 decoding bug affecting larger unicode values
+- added internal dtd processing for entity declarations and default attributes
+- now correctly normalizes attribute values in compliance with the XML 1.0 spec
+- added check for correct tag nesting
+- ezxml_toxml() now generates canonical xml (apart from the namespace stuff)
+
+ezXML 0.8.2
+- fixed compiler warning about lvalue type casting
+- ezxml_get() argument list can now be terminated by an empty string tag name
+- added NOMMAP make option for systems without posix memory mapping
+- added support for UTF-16
+- fixed bug in ezxml_toxml() where UTF-8 sequences were being ampersand encoded
+- added ezxml_new(), ezxml_add_child(), ezxml_set_txt(), ezxml_set_attr(),
+  and ezxml_remove() to facilitate creating and modifying xml
+
+ezXML 0.8.1
+- fixed bug where tags of same name were not recognized as such
+- fixed a memory allocation bug in ezxml_toxml() that could cause a segfault
+- added an extra check for missing root tag
+- now allows for space between ] and > when closing <!DOCTYPE [ ... ]>
+- now allows : as tag name start char
+- added ezxml_next() and ezxml_txt() function macros
+
+ezXML 0.8
+- added ezxml_toxml() function
+- removed ezxml_print(), just use printf() with ezxml_toxml() (minor version
+  api changes will all be backwards compatible after 1.0 release)
+- added ezxml_pi() for retrieving <? ?> parsing instructions
+- whitespace in tag data is now preserved in compliance with the XML 1.0 spec
+
+ezXML 0.7
+- initial public release
diff --git a/ezxml/ezxml.c b/ezxml/ezxml.c
new file mode 100644 (file)
index 0000000..82b11fb
--- /dev/null
@@ -0,0 +1,1015 @@
+/* ezxml.c
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifndef EZXML_NOMMAP
+#include <sys/mman.h>
+#endif // EZXML_NOMMAP
+#include <sys/stat.h>
+#include "ezxml.h"
+
+#define EZXML_WS   "\t\r\n "  // whitespace
+#define EZXML_ERRL 128        // maximum error string length
+
+typedef struct ezxml_root *ezxml_root_t;
+struct ezxml_root {       // additional data for the root tag
+    struct ezxml xml;     // is a super-struct built on top of ezxml struct
+    ezxml_t cur;          // current xml tree insertion point
+    char *m;              // original xml string
+    size_t len;           // length of allocated memory for mmap, -1 for malloc
+    char *u;              // UTF-8 conversion of string if original was UTF-16
+    char *s;              // start of work area
+    char *e;              // end of work area
+    char **ent;           // general entities (ampersand sequences)
+    char ***attr;         // default attributes
+    char ***pi;           // processing instructions
+    short standalone;     // non-zero if <?xml standalone="yes"?>
+    char err[EZXML_ERRL]; // error string
+};
+
+char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
+
+// returns the first child tag with the given name or NULL if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name)
+{
+    xml = (xml) ? xml->child : NULL;
+    while (xml && strcmp(name, xml->name)) xml = xml->sibling;
+    return xml;
+}
+
+// returns the Nth tag with the same name in the same subsection or NULL if not
+// found
+ezxml_t ezxml_idx(ezxml_t xml, int idx)
+{
+    for (; xml && idx; idx--) xml = xml->next;
+    return xml;
+}
+
+// returns the value of the requested tag attribute or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr)
+{
+    int i = 0, j = 1;
+    ezxml_root_t root = (ezxml_root_t)xml;
+
+    if (! xml || ! xml->attr) return NULL;
+    while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
+    if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
+
+    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+    for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
+    if (! root->attr[i]) return NULL; // no matching default attributes
+    while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
+    return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
+}
+
+// same as ezxml_get but takes an already initialized va_list
+ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
+{
+    char *name = va_arg(ap, char *);
+    int idx = -1;
+
+    if (name && *name) {
+        idx = va_arg(ap, int);    
+        xml = ezxml_child(xml, name);
+    }
+    return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
+}
+
+// Traverses the xml tree to retrieve a specific subtag. Takes a variable
+// length list of tag names and indexes. The argument list must be terminated
+// by either an index of -1 or an empty string tag name. Example: 
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...)
+{
+    va_list ap;
+    ezxml_t r;
+
+    va_start(ap, xml);
+    r = ezxml_vget(xml, ap);
+    va_end(ap);
+    return r;
+}
+
+// returns a null terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target)
+{
+    ezxml_root_t root = (ezxml_root_t)xml;
+    int i = 0;
+
+    if (! root) return (const char **)EZXML_NIL;
+    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+    return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
+}
+
+// set an error string and return root
+ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
+{
+    va_list ap;
+    int line = 1;
+    char *t, fmt[EZXML_ERRL];
+    
+    for (t = root->s; t < s; t++) if (*t == '\n') line++;
+    snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err);
+
+    va_start(ap, err);
+    vsnprintf(root->err, EZXML_ERRL, fmt, ap);
+    va_end(ap);
+
+    return &root->xml;
+}
+
+// Recursively decodes entity and character references and normalizes new lines
+// ent is a null terminated array of alternating entity names and values. set t
+// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
+// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
+// attribute normalization. Returns s, or if the decoded string is longer than
+// s, returns a malloced string that must be freed.
+char *ezxml_decode(char *s, char **ent, char t)
+{
+    char *e, *r = s, *m = s;
+    long b, c, d, l;
+
+    for (; *s; s++) { // normalize line endings
+        while (*s == '\r') {
+            *(s++) = '\n';
+            if (*s == '\n') memmove(s, (s + 1), strlen(s));
+        }
+    }
+    
+    for (s = r; ; ) {
+        while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++;
+
+        if (! *s) break;
+        else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
+            if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
+            else c = strtol(s + 2, &e, 10); // base 10
+            if (! c || *e != ';') { s++; continue; } // not a character ref
+
+            if (c < 0x80) *(s++) = c; // US-ASCII subset
+            else { // multi-byte UTF-8 sequence
+                for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
+                b = (b - 2) / 5; // number of bytes in payload
+                *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+                while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+            }
+
+            memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
+        }
+        else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
+                 (*s == '%' && t == '%')) { // entity reference
+            for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
+                 b += 2); // find entity in entity list
+
+            if (ent[b++]) { // found a match
+                if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
+                    l = (d = (s - r)) + c + strlen(e); // new length
+                    r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
+                    e = strchr((s = r + d), ';'); // fix up pointers
+                }
+
+                memmove(s + c, e + 1, strlen(e)); // shift rest of string
+                strncpy(s, ent[b], c); // copy in replacement text
+            }
+            else s++; // not a known entity
+        }
+        else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
+        else s++; // no decoding needed
+    }
+
+    if (t == '*') { // normalize spaces for non-cdata attributes
+        for (s = r; *s; s++) {
+            if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
+            while (*s && *s != ' ') s++;
+        }
+        if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
+    }
+    return r;
+}
+
+// called when parser finds start of new tag
+void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
+{
+    ezxml_t xml = root->cur;
+    
+    if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
+    else xml->name = name; // first open tag
+
+    xml->attr = attr;
+    root->cur = xml; // update tag insertion point
+}
+
+// called when parser finds character content between open and closing tag
+void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
+{
+    ezxml_t xml = root->cur;
+    char *m = s;
+    size_t l;
+
+    if (! xml || ! xml->name || ! len) return; // sanity check
+
+    s[len] = '\0'; // null terminate text (calling functions anticipate this)
+    len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
+
+    if (! *(xml->txt)) xml->txt = s; // initial character content
+    else { // allocate our own memory and make a copy
+        xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
+                   ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
+                   : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
+        strcpy(xml->txt + l, s); // add new char content
+        if (s != m) free(s); // free s if it was malloced by ezxml_decode()
+    }
+
+    if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
+}
+
+// called when parser finds closing tag
+ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
+{
+    if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
+        return ezxml_err(root, s, "unexpected closing tag </%s>", name);
+
+    root->cur = root->cur->parent;
+    return NULL;
+}
+
+// checks for circular entity references, returns non-zero if no circular
+// references are found, zero otherwise
+int ezxml_ent_ok(char *name, char *s, char **ent)
+{
+    int i;
+
+    for (; ; s++) {
+        while (*s && *s != '&') s++; // find next entity reference
+        if (! *s) return 1;
+        if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
+        for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
+        if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
+    }
+}
+
+// called when the parser finds a processing instruction
+void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
+{
+    int i = 0, j = 1;
+    char *target = s;
+
+    s[len] = '\0'; // null terminate instruction
+    if (*(s += strcspn(s, EZXML_WS))) {
+        *s = '\0'; // null terminate target
+        s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
+    }
+
+    if (! strcmp(target, "xml")) { // <?xml ... ?>
+        if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
+            EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
+        return;
+    }
+
+    if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
+
+    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+    if (! root->pi[i]) { // new target
+        root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
+        root->pi[i] = malloc(sizeof(char *) * 3);
+        root->pi[i][0] = target;
+        root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
+        root->pi[i][2] = strdup(""); // empty document position list
+    }
+
+    while (root->pi[i][j]) j++; // find end of instruction list for this target
+    root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
+    root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
+    strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
+    root->pi[i][j + 1] = NULL; // null terminate pi list for this target
+    root->pi[i][j] = s; // set instruction
+}
+
+// called when the parser finds an internal doctype subset
+short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
+{
+    char q, *c, *t, *n = NULL, *v, **ent, **pe;
+    int i, j;
+    
+    pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
+
+    for (s[len] = '\0'; s; ) {
+        while (*s && *s != '<' && *s != '%') s++; // find next declaration
+
+        if (! *s) break;
+        else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
+            c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
+            n = s + strspn(s, EZXML_WS "%"); // find name
+            *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
+
+            v = s + strspn(s + 1, EZXML_WS) + 1; // find value
+            if ((q = *(v++)) != '"' && q != '\'') { // skip externals
+                s = strchr(s, '>');
+                continue;
+            }
+
+            for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
+            ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
+            if (*c == '%') pe = ent;
+            else root->ent = ent;
+
+            *(++s) = '\0'; // null terminate name
+            if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
+            ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
+            ent[i + 2] = NULL; // null terminate entity list
+            if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
+                if (ent[i + 1] != v) free(ent[i + 1]);
+                ezxml_err(root, v, "circular entity declaration &%s", n);
+                break;
+            }
+            else ent[i] = n; // set entity name
+        }
+        else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
+            t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
+            if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
+            if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
+            else *s = '\0'; // null terminate tag name
+            for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
+
+            while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
+                if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
+                else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+                s += strspn(s + 1, EZXML_WS) + 1; // find next token
+                c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
+                if (! strncmp(s, "NOTATION", 8))
+                    s += strspn(s + 8, EZXML_WS) + 8;
+                s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
+                if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+                s += strspn(s, EZXML_WS ")"); // skip white space separator
+                if (! strncmp(s, "#FIXED", 6))
+                    s += strspn(s + 6, EZXML_WS) + 6;
+                if (*s == '#') { // no default value
+                    s += strcspn(s, EZXML_WS ">") - 1;
+                    if (*c == ' ') continue; // cdata is default, nothing to do
+                    v = NULL;
+                }
+                else if ((*s == '"' || *s == '\'')  &&  // default value
+                         (s = strchr(v = s + 1, *s))) *s = '\0';
+                else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+                if (! root->attr[i]) { // new tag name
+                    root->attr = (! i) ? malloc(2 * sizeof(char **))
+                                       : realloc(root->attr,
+                                                 (i + 2) * sizeof(char **));
+                    root->attr[i] = malloc(2 * sizeof(char *));
+                    root->attr[i][0] = t; // set tag name
+                    root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
+                }
+
+                for (j = 1; root->attr[i][j]; j += 3); // find end of list
+                root->attr[i] = realloc(root->attr[i],
+                                        (j + 4) * sizeof(char *));
+
+                root->attr[i][j + 3] = NULL; // null terminate list
+                root->attr[i][j + 2] = c; // is it cdata?
+                root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
+                                           : NULL;
+                root->attr[i][j] = n; // attribute name 
+            }
+        }
+        else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
+        else if (! strncmp(s, "<?", 2)) { // processing instructions
+            if ((s = strstr(c = s + 2, "?>")))
+                ezxml_proc_inst(root, c, s++ - c);
+        }
+        else if (*s == '<') s = strchr(s, '>'); // skip other declarations
+        else if (*(s++) == '%' && ! root->standalone) break;
+    }
+
+    free(pe);
+    return ! *root->err;
+}
+
+// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
+// or NULL if no conversion was needed.
+char *ezxml_str2utf8(char **s, size_t *len)
+{
+    char *u;
+    size_t l = 0, sl, max = *len;
+    long c, d;
+    int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
+
+    if (be == -1) return NULL; // not UTF-16
+
+    u = malloc(max);
+    for (sl = 2; sl < *len - 1; sl += 2) {
+        c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)  //UTF-16BE
+                 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
+        if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
+            d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
+                     : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
+            c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
+        }
+
+        while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
+        if (c < 0x80) u[l++] = c; // US-ASCII subset
+        else { // multi-byte UTF-8 sequence
+            for (b = 0, d = c; d; d /= 2) b++; // bits in c
+            b = (b - 2) / 5; // bytes in payload
+            u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+            while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+        }
+    }
+    return *s = realloc(u, *len = l);
+}
+
+// frees a tag attribute list
+void ezxml_free_attr(char **attr) {
+    int i = 0;
+    char *m;
+    
+    if (! attr || attr == EZXML_NIL) return; // nothing to free
+    while (attr[i]) i += 2; // find end of attribute list
+    m = attr[i + 1]; // list of which names and values are malloced
+    for (i = 0; m[i]; i++) {
+        if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
+        if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
+    }
+    free(m);
+    free(attr);
+}
+
+// parse the given xml string and return an ezxml structure
+ezxml_t ezxml_parse_str(char *s, size_t len)
+{
+    ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
+    char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
+    int l, i, j;
+
+    root->m = s;
+    if (! len) return ezxml_err(root, NULL, "root tag missing");
+    root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
+    root->e = (root->s = s) + len; // record start and end of work area
+    
+    e = s[len - 1]; // save end char
+    s[len - 1] = '\0'; // turn end char into null terminator
+
+    while (*s && *s != '<') s++; // find first tag
+    if (! *s) return ezxml_err(root, s, "root tag missing");
+
+    for (; ; ) {
+        attr = (char **)EZXML_NIL;
+        d = ++s;
+        
+        if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
+            if (! root->cur)
+                return ezxml_err(root, d, "markup outside of root element");
+
+            s += strcspn(s, EZXML_WS "/>");
+            while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
+  
+            if (*s && *s != '/' && *s != '>') // find tag in default attr list
+                for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
+
+            for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
+                attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
+                           : malloc(4 * sizeof(char *)); // allocate space
+                attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
+                                  : malloc(2); // mem for list of maloced vals
+                strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
+                attr[l + 2] = NULL; // null terminate list
+                attr[l + 1] = ""; // temporary attribute value
+                attr[l] = s; // set attribute name
+
+                s += strcspn(s, EZXML_WS "=/>");
+                if (*s == '=' || isspace(*s)) { 
+                    *(s++) = '\0'; // null terminate tag attribute name
+                    q = *(s += strspn(s, EZXML_WS "="));
+                    if (q == '"' || q == '\'') { // attribute value
+                        attr[l + 1] = ++s;
+                        while (*s && *s != q) s++;
+                        if (*s) *(s++) = '\0'; // null terminate attribute val
+                        else {
+                            ezxml_free_attr(attr);
+                            return ezxml_err(root, d, "missing %c", q);
+                        }
+
+                        for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3);
+                        attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a
+                                                   && a[j]) ? *a[j + 2] : ' ');
+                        if (attr[l + 1] < d || attr[l + 1] > s)
+                            attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
+                    }
+                }
+                while (isspace(*s)) s++;
+            }
+
+            if (*s == '/') { // self closing tag
+                *(s++) = '\0';
+                if ((*s && *s != '>') || (! *s && e != '>')) {
+                    if (l) ezxml_free_attr(attr);
+                    return ezxml_err(root, d, "missing >");
+                }
+                ezxml_open_tag(root, d, attr);
+                ezxml_close_tag(root, d, s);
+            }
+            else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
+                *s = '\0'; // temporarily null terminate tag name
+                ezxml_open_tag(root, d, attr);
+                *s = q;
+            }
+            else {
+                if (l) ezxml_free_attr(attr);
+                return ezxml_err(root, d, "missing >"); 
+            }
+        }
+        else if (*s == '/') { // close tag
+            s += strcspn(d = s + 1, EZXML_WS ">") + 1;
+            if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
+            *s = '\0'; // temporarily null terminate tag name
+            if (ezxml_close_tag(root, d, s)) return &root->xml;
+            if (isspace(*s = q)) s += strspn(s, EZXML_WS);
+        }
+        else if (! strncmp(s, "!--", 3)) { // xml comment
+            if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
+                (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
+        }
+        else if (! strncmp(s, "![CDATA[", 8)) { // cdata
+            if ((s = strstr(s, "]]>")))
+                ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
+            else return ezxml_err(root, d, "unclosed <![CDATA[");
+        }
+        else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
+            for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' || 
+                 *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
+                 l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
+            if (! *s && e != '>')
+                return ezxml_err(root, d, "unclosed <!DOCTYPE");
+            d = (l) ? strchr(d, '[') + 1 : d;
+            if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
+        }
+        else if (*s == '?') { // <?...?> processing instructions
+            do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
+            if (! s || (! *s && e != '>')) 
+                return ezxml_err(root, d, "unclosed <?");
+            else ezxml_proc_inst(root, d + 1, s - d - 2);
+        }
+        else return ezxml_err(root, d, "unexpected <");
+        
+        if (! s || ! *s) break;
+        *s = '\0';
+        d = ++s;
+        if (*s && *s != '<') { // tag character content
+            while (*s && *s != '<') s++;
+            if (*s) ezxml_char_content(root, d, s - d, '&');
+            else break;
+        }
+        else if (! *s) break;
+    }
+
+    if (! root->cur) return &root->xml;
+    else if (! root->cur->name) return ezxml_err(root, d, "root tag missing");
+    else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
+}
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp)
+{
+    ezxml_root_t root;
+    size_t l, len = 0;
+    char *s;
+
+    if (! (s = malloc(EZXML_BUFSIZE))) return NULL;
+    do {
+        len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp));
+        if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE);
+    } while (s && l == EZXML_BUFSIZE);
+
+    if (! s) return NULL;
+    root = (ezxml_root_t)ezxml_parse_str(s, len);
+    root->len = -1; // so we know to free s in ezxml_free()
+    return &root->xml;
+}
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd)
+{
+    ezxml_root_t root;
+    struct stat st;
+    size_t l;
+    void *m;
+
+    if (fd < 0) return NULL;
+    fstat(fd, &st);
+
+#ifndef EZXML_NOMMAP
+    l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1);
+    if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) !=
+        MAP_FAILED) {
+        madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access
+        root = (ezxml_root_t)ezxml_parse_str(m, st.st_size);
+        madvise(m, root->len = l, MADV_NORMAL); // put it back to normal
+    }
+    else { // mmap failed, read file into memory
+#endif // EZXML_NOMMAP
+        l = read(fd, m = malloc(st.st_size), st.st_size);
+        root = (ezxml_root_t)ezxml_parse_str(m, l);
+        root->len = -1; // so we know to free s in ezxml_free()
+#ifndef EZXML_NOMMAP
+    }
+#endif // EZXML_NOMMAP
+    return &root->xml;
+}
+
+// a wrapper for ezxml_parse_fd that accepts a file name
+ezxml_t ezxml_parse_file(const char *file)
+{
+    int fd = open(file, O_RDONLY, 0);
+    ezxml_t xml = ezxml_parse_fd(fd);
+    
+    if (fd >= 0) close(fd);
+    return xml;
+}
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
+                      size_t *max, short a)
+{
+    const char *e;
+    
+    for (e = s + len; s != e; s++) {
+        while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE);
+
+        switch (*s) {
+        case '\0': return *dst;
+        case '&': *dlen += sprintf(*dst + *dlen, "&amp;"); break;
+        case '<': *dlen += sprintf(*dst + *dlen, "&lt;"); break;
+        case '>': *dlen += sprintf(*dst + *dlen, "&gt;"); break;
+        case '"': *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\""); break;
+        case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n"); break;
+        case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t"); break;
+        case '\r': *dlen += sprintf(*dst + *dlen, "&#xD;"); break;
+        default: (*dst)[(*dlen)++] = *s;
+        }
+    }
+    return *dst;
+}
+
+// Recursively converts each tag to xml appending it to *s. Reallocates *s if
+// its length excedes max. start is the location of the previous tag in the
+// parent tag's character content. Returns *s.
+char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
+                    size_t start, char ***attr)
+{
+    int i, j;
+    char *txt = (xml->parent) ? xml->parent->txt : "";
+    size_t off = 0;
+
+    // parent character content up to this tag
+    *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+    *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+    for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+        if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+        while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+            *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+        ezxml_ampencode(xml->attr[i + 1], -1, s, len, max, 1);
+        *len += sprintf(*s + *len, "\"");
+    }
+
+    for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
+    for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
+        if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
+            continue; // skip duplicates and non-values
+        while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
+            *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+        ezxml_ampencode(attr[i][j + 1], -1, s, len, max, 1);
+        *len += sprintf(*s + *len, "\"");
+    }
+    *len += sprintf(*s + *len, ">");
+
+    *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
+                      : ezxml_ampencode(xml->txt, -1, s, len, max, 0);  //data
+    
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+    *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
+
+    while (txt[off] && off < xml->off) off++; // make sure off is within bounds
+    return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
+                          : ezxml_ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml)
+{
+    ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
+    ezxml_root_t root = (ezxml_root_t)xml;
+    size_t len = 0, max = EZXML_BUFSIZE;
+    char *s = strcpy(malloc(max), ""), *t, *n;
+    int i, j, k;
+
+    if (! xml || ! xml->name) return realloc(s, len + 1);
+    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+
+    for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
+        for (k = 2; root->pi[i][k - 1]; k++);
+        for (j = 1; (n = root->pi[i][j]); j++) {
+            if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
+            while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+                s = realloc(s, max += EZXML_BUFSIZE);
+            len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n);
+        }
+    }
+
+    xml->parent = xml->ordered = NULL;
+    s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr);
+    xml->parent = p;
+    xml->ordered = o;
+
+    for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
+        for (k = 2; root->pi[i][k - 1]; k++);
+        for (j = 1; (n = root->pi[i][j]); j++) {
+            if (root->pi[i][k][j - 1] == '<') continue; // not post-root
+            while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+                s = realloc(s, max += EZXML_BUFSIZE);
+            len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
+        }
+    }
+    return realloc(s, len + 1);
+}
+
+// free the memory allocated for the ezxml structure
+void ezxml_free(ezxml_t xml)
+{
+    ezxml_root_t root = (ezxml_root_t)xml;
+    int i, j;
+    char **a, *s;
+
+    if (! xml) return;
+    ezxml_free(xml->child);
+    ezxml_free(xml->ordered);
+
+    if (! xml->parent) { // free root tag allocations
+        for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
+            if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
+        free(root->ent); // free list of general entities
+
+        for (i = 0; (a = root->attr[i]); i++) {
+            for (j = 1; a[j++]; j += 2) // free malloced attribute values
+                if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
+            free(a);
+        }
+        if (root->attr[0]) free(root->attr); // free default attribute list
+
+        for (i = 0; root->pi[i]; i++) {
+            for (j = 1; root->pi[i][j]; j++);
+            free(root->pi[i][j + 1]);
+            free(root->pi[i]);
+        }            
+        if (root->pi[0]) free(root->pi); // free processing instructions
+
+        if (root->len == -1) free(root->m); // malloced xml data
+#ifndef EZXML_NOMMAP
+        else if (root->len) munmap(root->m, root->len); // mem mapped xml data
+#endif // EZXML_NOMMAP
+        if (root->u) free(root->u); // utf8 conversion
+    }
+
+    ezxml_free_attr(xml->attr); // tag attributes
+    if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
+    if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
+    free(xml);
+}
+
+// return parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml)
+{
+    while (xml && xml->parent) xml = xml->parent; // find root tag
+    return (xml) ? ((ezxml_root_t)xml)->err : "";
+}
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name)
+{
+    static char *ent[] = { "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
+                           "apos;", "&#39;", "amp;", "&#38;", NULL };
+    ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)), 
+                                             '\0', sizeof(struct ezxml_root));
+    root->xml.name = (char *)name;
+    root->cur = &root->xml;
+    strcpy(root->err, root->xml.txt = "");
+    root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
+    root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL);
+    return &root->xml;
+}
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
+{
+    ezxml_t cur, prev, head;
+
+    xml->next = xml->sibling = xml->ordered = NULL;
+    xml->off = off;
+    xml->parent = dest;
+
+    if ((head = dest->child)) { // already have sub tags
+        if (head->off <= off) { // not first subtag
+            for (cur = head; cur->ordered && cur->ordered->off <= off;
+                 cur = cur->ordered);
+            xml->ordered = cur->ordered;
+            cur->ordered = xml;
+        }
+        else { // first subtag
+            xml->ordered = head;
+            dest->child = xml;
+        }
+
+        for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
+             prev = cur, cur = cur->sibling); // find tag type
+        if (cur && cur->off <= off) { // not first of type
+            while (cur->next && cur->next->off <= off) cur = cur->next;
+            xml->next = cur->next;
+            cur->next = xml;
+        }
+        else { // first tag of this type
+            if (prev && cur) prev->sibling = cur->sibling; // remove old first
+            xml->next = cur; // old first tag is now next
+            for (cur = head, prev = NULL; cur && cur->off <= off;
+                 prev = cur, cur = cur->sibling); // new sibling insert point
+            xml->sibling = cur;
+            if (prev) prev->sibling = xml;
+        }
+    }
+    else dest->child = xml; // only sub tag
+
+    return xml;
+}
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
+{
+    ezxml_t child;
+
+    if (! xml) return NULL;
+    child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0',
+                            sizeof(struct ezxml));
+    child->name = (char *)name;
+    child->attr = EZXML_NIL;
+    child->txt = "";
+
+    return ezxml_insert(child, xml, off);
+}
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
+{
+    if (! xml) return NULL;
+    if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
+    xml->flags &= ~EZXML_TXTM;
+    xml->txt = (char *)txt;
+    return xml;
+}
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
+{
+    int l = 0, c;
+
+    if (! xml) return NULL;
+    while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
+    if (! xml->attr[l]) { // not found, add as new attribute
+        if (! value) return xml; // nothing to do
+        if (xml->attr == EZXML_NIL) { // first attribute
+            xml->attr = malloc(4 * sizeof(char *));
+            xml->attr[1] = strdup(""); // empty list of malloced names/vals
+        }
+        else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
+
+        xml->attr[l] = (char *)name; // set attribute name
+        xml->attr[l + 2] = NULL; // null terminate attribute list
+        xml->attr[l + 3] = realloc(xml->attr[l + 1],
+                                   (c = strlen(xml->attr[l + 1])) + 2);
+        strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
+        if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM;
+    }
+    else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
+
+    for (c = l; xml->attr[c]; c += 2); // find end of attribute list
+    if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
+    if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
+    else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
+
+    if (value) xml->attr[l + 1] = (char *)value; // set attribute value
+    else { // remove attribute
+        if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
+        memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+        xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
+        memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+                (c / 2) - (l / 2)); // fix list of which name/vals are malloced
+    }
+    xml->flags &= ~EZXML_DUP; // clear strdup() flag
+    return xml;
+}
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
+{
+    if (xml) xml->flags |= flag;
+    return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml)
+{
+    ezxml_t cur;
+
+    if (! xml) return NULL; // nothing to do
+    if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
+
+    if (xml->parent) { // not root tag
+        cur = xml->parent->child; // find head of subtag list
+        if (cur == xml) xml->parent->child = xml->ordered; // first subtag
+        else { // not first subtag
+            while (cur->ordered != xml) cur = cur->ordered;
+            cur->ordered = cur->ordered->ordered; // patch ordered list
+
+            cur = xml->parent->child; // go back to head of subtag list
+            if (strcmp(cur->name, xml->name)) { // not in first sibling list
+                while (strcmp(cur->sibling->name, xml->name))
+                    cur = cur->sibling;
+                if (cur->sibling == xml) { // first of a sibling list
+                    cur->sibling = (xml->next) ? xml->next
+                                               : cur->sibling->sibling;
+                }
+                else cur = cur->sibling; // not first of a sibling list
+            }
+
+            while (cur->next && cur->next != xml) cur = cur->next;
+            if (cur->next) cur->next = cur->next->next; // patch next list
+        }        
+    }
+    xml->ordered = xml->sibling = xml->next = NULL;
+    return xml;
+}
+
+#ifdef EZXML_TEST // test harness
+int main(int argc, char **argv)
+{
+    ezxml_t xml;
+    char *s;
+    int i;
+
+    if (argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]);
+
+    xml = ezxml_parse_file(argv[1]);
+    printf("%s\n", (s = ezxml_toxml(xml)));
+    free(s);
+    i = fprintf(stderr, "%s", ezxml_error(xml));
+    ezxml_free(xml);
+    return (i) ? 1 : 0;
+}
+#endif // EZXML_TEST
diff --git a/ezxml/ezxml.h b/ezxml/ezxml.h
new file mode 100644 (file)
index 0000000..3e02078
--- /dev/null
@@ -0,0 +1,167 @@
+/* ezxml.h
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EZXML_H
+#define _EZXML_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EZXML_BUFSIZE 1024 // size of internal memory buffers
+#define EZXML_NAMEM   0x80 // name is malloced
+#define EZXML_TXTM    0x40 // txt is malloced
+#define EZXML_DUP     0x20 // attribute name and value are strduped
+
+typedef struct ezxml *ezxml_t;
+struct ezxml {
+    char *name;      // tag name
+    char **attr;     // tag attributes { name, value, name, value, ... NULL }
+    char *txt;       // tag character content, empty string if none
+    size_t off;      // tag offset from start of parent tag character content
+    ezxml_t next;    // next tag with same name in this section at this depth
+    ezxml_t sibling; // next tag with different name in same section and depth
+    ezxml_t ordered; // next tag, same section and depth, in original order
+    ezxml_t child;   // head of sub tag list, NULL if none
+    ezxml_t parent;  // parent tag, NULL if current tag is root tag
+    short flags;     // additional information
+};
+
+// Given a string of xml data and its length, parses it and creates an ezxml
+// structure. For efficiency, modifies the data by adding null terminators
+// and decoding ampersand sequences. If you don't want this, copy the data and
+// pass in the copy. Returns NULL on failure.
+ezxml_t ezxml_parse_str(char *s, size_t len);
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd);
+
+// a wrapper for ezxml_parse_fd() that accepts a file name
+ezxml_t ezxml_parse_file(const char *file);
+    
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp);
+
+// returns the first child tag (one level deeper) with the given name or NULL
+// if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name);
+
+// returns the next tag of the same name in the same section and depth or NULL
+// if not found
+#define ezxml_next(xml) ((xml) ? xml->next : NULL)
+
+// Returns the Nth tag with the same name in the same section at the same depth
+// or NULL if not found. An index of 0 returns the tag given.
+ezxml_t ezxml_idx(ezxml_t xml, int idx);
+
+// returns the name of the given tag
+#define ezxml_name(xml) ((xml) ? xml->name : NULL)
+
+// returns the given tag's character content or empty string if none
+#define ezxml_txt(xml) ((xml) ? xml->txt : "")
+
+// returns the value of the requested tag attribute, or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr);
+
+// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a
+// variable length list of tag names and indexes. The argument list must be
+// terminated by either an index of -1 or an empty string tag name. Example: 
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...);
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml);
+
+// returns a NULL terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target);
+
+// frees the memory allocated for an ezxml structure
+void ezxml_free(ezxml_t xml);
+    
+// returns parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml);
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name);
+
+// wrapper for ezxml_new() that strdup()s name
+#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM)
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off);
+
+// wrapper for ezxml_add_child() that strdup()s name
+#define ezxml_add_child_d(xml, name, off) \
+    ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM)
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt);
+
+// wrapper for ezxml_set_txt() that strdup()s txt
+#define ezxml_set_txt_d(xml, txt) \
+    ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM)
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value);
+
+// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL
+#define ezxml_set_attr_d(xml, name, value) \
+    ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value))
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag);
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml);
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off);
+
+// Moves an existing tag to become a subtag of dest at the given offset from
+// the start of dest's character content. Returns the moved tag.
+#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off)
+
+// removes a tag along with all its subtags
+#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _EZXML_H
diff --git a/ezxml/ezxml.html b/ezxml/ezxml.html
new file mode 100644 (file)
index 0000000..6c17852
--- /dev/null
@@ -0,0 +1,121 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head><title>ezXML</title></head>
+  <body>
+    <h1>ezXML - XML Parsing C Library</h1>
+    <h3>version 0.8.6</h3>
+    <p>
+      ezXML is a C library for parsing XML documents inspired by
+      <a href="http://www.php.net/SimpleXML">simpleXML</a> for
+      PHP. As the name implies, it's easy to use. It's ideal for parsing XML
+      configuration files or REST web service responses. It's also fast and
+      lightweight (less than 20k compiled). The latest version is available
+      here:
+      <a href="http://prdownloads.sf.net/ezxml/ezxml-0.8.6.tar.gz?download"
+        >ezxml-0.8.6.tar.gz</a>
+    </p>
+
+    <b>Example Usage</b>
+    <p>
+      Given the following example XML document:
+    </p>
+    <code>
+      &lt;?xml version="1.0"?&gt;<br />
+      &lt;formula1&gt;<br />
+      &nbsp;&nbsp;&lt;team name="McLaren"&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&lt;driver&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Kimi
+      Raikkonen&lt;/name&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;points&gt;112&lt;/points&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&lt;/driver&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&lt;driver&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Juan Pablo
+      Montoya&lt;/name&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;points&gt;60&lt;/points&gt;<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&lt;/driver&gt;<br />
+      &nbsp;&nbsp;&lt;/team&gt;<br />
+      &lt;/formula1&gt;
+    </code>
+    <p>
+      This code snippet prints out a list of drivers, which team they drive for,
+      and how many championship points they have:
+    </p>
+    <code>
+      ezxml_t f1 = ezxml_parse_file("formula1.xml"), team, driver;<br />
+      const char *teamname;<br />
+      &nbsp;<br />
+      for (team = ezxml_child(f1, "team"); team; team = team->next) {<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;teamname = ezxml_attr(team, "name");<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;for (driver = ezxml_child(team, "driver"); driver;
+      driver = driver->next) {<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%s, %s: %s\n",
+      ezxml_child(driver, "name")->txt, teamname,<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+      &nbsp;&nbsp;ezxml_child(driver, "points")->txt);<br />
+      &nbsp;&nbsp;&nbsp;&nbsp;}<br />
+      }<br />
+      ezxml_free(f1);
+    </code>
+    <p>
+      Alternately, the following would print out the name of the second driver
+      on the first team:
+    </p>
+    <code>
+      ezxml_t f1 = ezxml_parse_file("formula1.xml");<br />
+      &nbsp;<br />
+      printf("%s\n", ezxml_get(f1, "team", 0, "driver", 1, "name", -1)->txt);
+      <br />ezxml_free(f1);
+    </code>
+    <p>
+      The -1 indicates the end of the argument list. That's pretty much all
+      there is to it. Complete API documentation can be found in ezxml.h.
+    </p>
+
+    <b>Known Limitations</b>
+    <ul>
+      <li>
+       ezXML is not a validating parser.
+       <br />&nbsp;
+      </li>
+      <li>
+       Loads the entire XML document into memory at once and does not allow for
+       documents to be passed in a chunk at a time. Large XML files can still
+       be handled though through <code>ezxml_parse_file()</code> and 
+       <code>ezxml_parse_fd()</code>, which use mmap to map the file to a
+       virtual address space and rely on the virtual memory system to page in
+       data as needed.
+       <br />&nbsp;
+      </li>
+      <li>
+       Does not currently recognize all possible well-formedness errors. It
+       should correctly handle all well-formed XML documents and will either
+       ignore or halt XML processing on well-formedness errors. More
+       well-formedness checking will be added in subsiquent releases.
+       <br />&nbsp;
+      </li>
+      <li>
+       In making the character content of tags easy to access, there is no
+       way provided to keep track of the location of sub tags relative to the
+       character data. Example:
+       <p>
+         <code>&lt;doc&gt;line one&lt;br/&gt;<br />line two&lt;/doc&gt;</code>
+       </p>
+       <p>
+         The character content of the doc tag is reported as
+         <code>"line one\nline two"</code>, and <code>&lt;br/&gt;</code> is
+         reported as a sub tag, but the location of <code>&lt;br/&gt;</code>
+         within the character data is not. The function
+         <code>ezxml_toxml()</code> will convert an ezXML structure back to XML
+         with sub tag locations intact.
+       </p>
+      </li>
+    </ul>
+    
+    <b>Licensing</b>
+    <p>
+      ezXML was written by Aaron Voisine and is distributed under the terms of
+      the <a href="license.txt">MIT license</a>.
+    </p>
+  </body>
+</html>
diff --git a/ezxml/ezxml.txt b/ezxml/ezxml.txt
new file mode 100644 (file)
index 0000000..1dcd5ad
--- /dev/null
@@ -0,0 +1,84 @@
+ezXML - XML Parsing C Library
+version 0.8.5
+
+ezXML is a C library for parsing XML documents inspired by simpleXML for PHP.
+As the name implies, it's easy to use. It's ideal for parsing XML configuration
+files or REST web service responses. It's also fast and lightweight (less than
+20k compiled). The latest verions is available here:
+http://prdownloads.sf.net/ezxml/ezxml-0.8.6.tar.gz?download
+
+Example Usage
+
+Given the following example XML document:
+
+<?xml version="1.0"?>
+<formula1>
+  <team name="McLaren">
+    <driver>
+      <name>Kimi Raikkonen</name>
+      <points>112</points>
+    </driver>
+    <driver>
+      <name>Juan Pablo Montoya</name>
+      <points>60</points>
+    </driver>
+  </team>
+</formula1>
+
+This code snippet prints out a list of drivers, which team they drive for,
+and how many championship points they have:
+
+ezxml_t f1 = ezxml_parse_file("formula1.xml"), team, driver;
+const char *teamname;
+
+for (team = ezxml_child(f1, "team"); team; team = team->next) {
+    teamname = ezxml_attr(team, "name");
+    for (driver = ezxml_child(team, "driver"); driver; driver = driver->next) {
+        printf("%s, %s: %s\n", ezxml_child(driver, "name")->txt, teamname,
+               ezxml_child(driver, "points")->txt);
+    }
+}
+ezxml_free(f1);
+
+Alternately, the following would print out the name of the second driver on the
+first team:
+
+ezxml_t f1 = ezxml_parse_file("formula1.xml");
+
+printf("%s\n", ezxml_get(f1, "team", 0, "driver", 1, "name", -1)->txt);
+ezxml_free(f1);
+
+The -1 indicates the end of the argument list. That's pretty much all
+there is to it. Complete API documentation can be found in ezxml.h.
+
+Known Limitations
+
+- ezXML is not a validating parser
+
+- Loads the entire XML document into memory at once and does not allow for
+  documents to be passed in a chunk at a time. Large XML files can still be
+  handled though through ezxml_parse_file() and ezxml_parse_fd(), which use mmap
+  to map the file to a virtual address space and rely on the virtual memory
+  system to page in data as needed.
+
+- Does not currently recognize all possible well-formedness errors. It should
+  correctly handle all well-formed XML documents and will either ignore or halt
+  XML processing on well-formedness errors. More well-formedness checking will
+  be added in subsiquent releases.
+
+- In making the character content of tags easy to access, there is no way
+  provided to keep track of the location of sub tags relative to the character
+  data. Example:
+
+  <doc>line one<br/>
+  line two</doc>
+
+  The character content of the doc tag is reported as "line one\nline two", and
+  <br/> is reported as a sub tag, but the location of <br/> within the
+  character data is not. The function ezxml_toxml() will convert an ezXML
+  structure back to XML with sub tag locations intact.
+
+Licensing
+
+ezXML was written by Aaron Voisine <aaron@voisine.org> and is distributed under
+the terms of the MIT license, described in license.txt.
diff --git a/ezxml/license.txt b/ezxml/license.txt
new file mode 100644 (file)
index 0000000..80e4e88
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/html/en/macauth.html b/html/en/macauth.html
new file mode 100644 (file)
index 0000000..47fa0fd
--- /dev/null
@@ -0,0 +1,55 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title></title>
+</head>
+<body bgcolor="#EEFFEE">
+<center>
+
+<h2>Management of MAC Address Registration</h2>
+
+<p><a href="%%CGINAME%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">Japanese Page</a></p>
+
+<P><font size=+1>This is the page to manage MAC address of your
+terminals. If you register this terminal, you can use the network
+without password entry.</font></P>
+
+<P><font size=+1>To proceed, you are requested to be authenticated.
+</font></P>
+
+<P><font size=+1>You will be authenticated with your user ID and
+password.  If you do not know your user ID and/or password, please consult CNC.
+</font></P>
+
+<P>
+Please enter your user ID and password in the box below, then press SEND.
+</P>
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<P>
+<form method="POST" action="%%CGINAME%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">
+<INPUT TYPE="HIDDEN" NAME="redirected_url" VALUE="%%REDIRECTEDURL%%">
+
+<TABLE BORDER=0>
+<TR NOWRAP>
+<TD><strong>User ID: </strong></TD><TD><INPUT TYPE="TEXT" SIZE=20 NAME="userid"></TD>
+</TR><TR NOWRAP>
+<TD><strong>Password: </strong></TD><TD><INPUT TYPE="PASSWORD" SIZE=20 NAME="password"></TD>
+</TR><TR NOWRAP>
+<TD></TD><TD><INPUT TYPE="SUBMIT" VALUE="  SEND  "></TD>
+</TR>
+</TABLE>
+</form>
+</P>
+
+<p><font size=+1>If you have any questions, 
+please contact network administrator.
+</center>
+
+<div align=right>Saga University</div>
+</body>
+</html>
+
diff --git a/html/en/macchk.html b/html/en/macchk.html
new file mode 100644 (file)
index 0000000..7982e2a
--- /dev/null
@@ -0,0 +1,70 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+<script type="text/JavaScript" src="/opengate/macchk.js"></script>
+</head>
+<body onload="setParameters('%%CHECKCGI%%', %%TIMEOUT%%)">
+
+<h3>MAC Address Check</h3>
+
+<p>
+<a href=%%CHECKCGI%%?lang=ja>Japanese Page</a>
+</p>
+<p>UserId: %%USERID%%</p>
+
+<form name='checkform' id='checkform'>
+<table border='1'>
+  <tr>
+    <td>Select</td>
+    <td>MAC Address</td>
+    <td>NIC Vendor</td>
+    <td>IPv4 Address</td>
+    <td>IPv6 Address</td>
+    <td>InUse</td>
+    <td>OnDB</td>
+  </tr>
+%%MACCHECKLIST%%
+</table>
+<input type='button' name='open' value=' Open ' onclick='openNet();'>  
+<input name='timer' size="4" >
+<input type='button' name='close' value=' Close ' onclick='closeNet();' disabled> 
+</form>
+</p>
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+<p>
+<form name='regform' id='regform' method='get' action='%%REGISTERCGI%%'>
+<input name='macaddr'><input type='submit' value='Register'> <br>
+<input type='radio' name='lang' value='en' checked>English  
+<input type='radio' name='lang' value='ja'>Japanese<br>
+</form>
+</p>
+<p>
+<a href=opengatemup.cgi?lang=en>Update Page</a>
+</p>
+<hr>
+<p>
+How to use
+<ol>
+<li>Connect the target terminal to the access point of this page, and
+try network access to confirm that the network for the terminal is closed.
+<li>Load this page. If you already loaded, reload it.
+<li>The above is the list of addresses using this access point. The top of the list is the one detected most recently.
+<li>Choose an address in the list and push the "open" button. When a server replies, a timer starts.
+<li>Try to use the network at the target terminal.
+<li>If the network is not available, push "close" button and try other address.
+<li>If the network is available, push "close" button and confirm that the network is not available. Then push "register" button to jump to the registration page.
+</ol>
+</p>
+<p>
+Warning
+<ul>
+<li>When the timer does not start, contact an administrator, as the server might be malfunction.
+<li>The network is closed soon, even if you do not push the "close" button.
+However, it is desirable to close the network early with the "close" button.
+</ul>
+</p>
+</body>
+</html>
diff --git a/html/en/macdeny.html b/html/en/macdeny.html
new file mode 100644 (file)
index 0000000..395ab23
--- /dev/null
@@ -0,0 +1,14 @@
+    
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html">
+<title></title>
+</head>
+<body align="center">
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+</body>
+</html>
diff --git a/html/en/macfwd.html b/html/en/macfwd.html
new file mode 100644 (file)
index 0000000..58ffe0b
--- /dev/null
@@ -0,0 +1,20 @@
+<HTML>
+<HEAD>
+
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1">
+<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+<META HTTP-EQUIV="Refresh" CONTENT="1; URL=https://%%JUMPCGIURL%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">
+<TITLE>OpengateM Start</TITLE>
+</HEAD>
+<BODY>
+You will automatically enter to the page for <i>Network Authentication</i>
+by OpengateM.
+<P>
+If you cannot move to the page automatically, click the following.
+<P>
+<a href="https://%%JUMPCGIURL%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">Network Authentication(SSL)</a><br>
+<a href="http://%%JUMPCGIURL%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">Network Authentication(NonSSL)</a>
+<hr>
+Saga University
+</BODY>
+</HTML>
diff --git a/html/en/macreg.html b/html/en/macreg.html
new file mode 100644 (file)
index 0000000..10e385f
--- /dev/null
@@ -0,0 +1,66 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+</head>
+<body align="center">
+<p><font size="5">MAC Address Registration</font></p>
+
+<p>
+<a href="%%REGISTERCGI%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%" >Japanese Page</a>
+</p>
+
+<p>UserId: %%USERID%%</p>
+
+<form method="post" action="%%REGISTERCGI%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">
+<table border="1">
+  <tr align="middle">
+    <td>MAC Address</td>
+    <td>Device Name</td>
+    <td>Mail Address</td>
+  </tr>
+  <tr align=middle>
+  <td><input size=30 value='%%MACADDR%%' name=macaddr readonly></td>
+  <td><input size=30 value='%%DEVICE%%' name=device style ='BACKGROUND-COLOR: yellow'></td>
+  <td><input size=30 value='%%MAILADDR%%'name=mailaddr style ='BACKGROUND-COLOR: yellow'></td>
+  </tr>
+</table>
+
+<p><input type="submit" value=" Register "></p>
+</form>
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<ol>
+<li>After registration, you can use network without password in this
+month (next month, when registered in the latter half of the month).</li>
+<li>Before the limit date, mail will be sent to the above mail
+address.</li> 
+<li>Please enter the name of your device in the above yellow
+area(e.g., iPadX, X-01A, TabletAZ).</li>
+<li>You can register 5 terminals.</li>
+<li>After registration, exit this browser to reset authentication state.</li>
+</ol>
+
+<p><font size=+1>Registered Terminals</font></p>
+<p>
+<table border='1'>
+  <tr align=middle>
+    <td>MAC Address</td>
+    <td>Device Name</td>
+    <td>Entry Date</td>
+    <td>Limit Date</td>
+    <td>Stauts</td>
+    <td>Mail Address</td>
+  </tr>
+%%MACREGLIST%%
+</table>
+</p>
+
+<p>
+<a href=opengatemup.cgi?lang=en>Update Page</a>
+</p>
+</body>
+</html>
diff --git a/html/en/macreturn.html b/html/en/macreturn.html
new file mode 100644 (file)
index 0000000..93c7b67
--- /dev/null
@@ -0,0 +1,43 @@
+<HTML>
+<HEAD>
+
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1">
+<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+<META HTTP-EQUIV="Refresh" CONTENT="%%WAITTIME%%;
+URL=%%REDIRECTEDURL%%">
+
+<script type="text/javascript">
+<!--
+var seconds;
+
+function startTimer(timeout){
+  seconds=timeout;
+  setTimeout('onTimeout()', 1000);
+}
+
+function onTimeout(){
+  seconds--;
+  document.getElementById("timer1").innerHTML = seconds;
+  if(seconds<=0) window.location.href='%%REDIRECTEDURL%%';
+  else setTimeout('onTimeout()', 1000);
+}
+// -->
+</script>
+
+</HEAD>
+<BODY onload='startTimer(%%WAITTIME%%)'>
+<P>
+You will automatically return to the previous page. Please wait for a
+while.
+<font size=+1>[<span id="timer1">%%WAITTIME%%</span>]</font>
+</P>
+<P>
+If you cannot move to the page automatically, click the following. Or restart the browser.
+</P>
+<P>
+<a href="%%REDIRECTEDURL%%">NEXT</a>
+</P>
+<hr>
+Saga University
+</BODY>
+</HTML>
diff --git a/html/en/macupdate.html b/html/en/macupdate.html
new file mode 100644 (file)
index 0000000..395856a
--- /dev/null
@@ -0,0 +1,68 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+</head>
+<body align="center">
+
+<p><font size="5">Update of MAC address registration </font></p>
+
+<p><a href="%%CGINAME%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">Japanese Page</a></p>
+
+
+<p>user ID: %%USERID%%</p>
+
+<form method="post" action="%%CGINAME%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">
+<table border="1">
+<tr align="middle">
+<td>Renew</td>
+<td>Pause</td>
+<td>Delete</td>
+<td>MAC Address</td>
+<td>Device Name</td>
+<td>Registration Date</td>
+<td>Limit Date</td>
+<td>Status</td>
+</tr>
+%%MACLIST%%
+</table>
+<p><input type="submit" value=" Send "></p>
+</form>
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+<p>
+
+<p>Check <strong>"Renew"</strong> to renew the registration (resume
+and extend the limit date). 
+To prevent hijacking, please confirm your usage log at update.
+</p>
+<p>
+<strong>"Pause"</strong> sets the limit-date to now to pause the
+usage. If you want to reuse the device, check "Renew". 
+</p>
+<p>
+Check <strong>"Delete"</strong> to delete the registration. If you
+may use this terminal in the future, please use "Pause".
+</p>
+<p>
+The status "I" indicates that the device is set as Inactive by some
+reason. Please contact to the administrator.
+</p>
+
+<p><font size="5"> usage log </font></p>
+<p>
+<table border="1">
+<tr align="middle">
+<td> MAC Address </td>
+<td> Device Name </td>
+<td> Start Time </td>
+<td> Week </td>
+<td> Gateway </td>
+
+</tr>
+%%USAGELOG%%
+</table>
+</p>
+</body>
+</html>
diff --git a/html/en/warning.php b/html/en/warning.php
new file mode 100644 (file)
index 0000000..d3343e3
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+  <head>\r
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">\r
+    <title>warning</title>\r
+  </head>\r
+  <body>\r
+    <h2>Trial of authentication system OpengateM for tablets and\r
+      smartphones</h2>\r
+    We are developing authentication system for tablets and the\r
+    smartphones that are bother to use Opengate, and now trying to serve\r
+    it on the wireless LAN of our campus. We are happy if you try\r
+    it.&nbsp; If there is malfunction, please contact us.&nbsp; We may\r
+    stop the service without notice.<br>\r
+    <br>\r
+    To use the system, please register your terminal in \r
+\r
+<?php \r
+$lang=""; $redirectedurl="";\r
+if(isset($_GET['lang']))$lang=$_GET['lang'];\r
+if(isset($_GET['redirectedurl'])) $redirectedurl=$_GET['redirectedurl'];\r
+echo "<a href=/cgi-bin/opengate/opengatemown.cgi?",\r
+"lang=",$lang,"&redirectedurl=",$redirectedurl,">"?>\r
+\r
+the registration page</a>.&nbsp;\r
+    Normal Windows and MacOS terminals are not permitted, because the\r
+    Opengate is usable.<br>\r
+    <br>\r
+    The registration expires at the end of this or next month.&nbsp; As\r
+    a warning email will be sent one week and one day before expiration,\r
+    please update the registration by using URL in the email. Or you can\r
+    update registration by using the link on Opengate page same as\r
+    registration.&nbsp; To prevent unjust use, please check your usage\r
+    history at updating.<br>\r
+    <br>\r
+    Contact:&nbsp; Yoshiaki Watanabe: <i>watanaby(at)is.saga-u.ac.jp</i>,&nbsp;\r
+    Makoto Otani: <i>otani(at)cc.saga-u.ac.jp</i><br>\r
+    <br>\r
+  </body>\r
+</html>\r
diff --git a/html/index.html.var b/html/index.html.var
new file mode 100644 (file)
index 0000000..4ee9b11
--- /dev/null
@@ -0,0 +1,10 @@
+URI: /cgi-bin/opengate/opengatemfwd.cgi?lang=en
+Content-language: en
+Content-type: text/html
+
+URI: /cgi-bin/opengate/opengatemfwd.cgi?lang=ja
+Content-language: ja
+Content-type: text/html
+
+URI: /cgi-bin/opengate/opengatemfwd.cgi?lang=en
+Content-type: text/html
diff --git a/html/ja/macauth.html b/html/ja/macauth.html
new file mode 100644 (file)
index 0000000..6cd2d81
--- /dev/null
@@ -0,0 +1,55 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+</head>
+<body bgcolor="#EEFFEE">
+<center>
+
+<h2>利用者端末MACアドレス登録管理</h2>
+
+<p><a href="%%CGINAME%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">English Page</a></p>
+
+
+<P><font size=+1>ここは利用者端末のMACアドレスを登録管理するページです。
+端末を登録するとパスワード入力なしでネットワークを利用できます。
+</font></P>
+
+<P><font size=+1>登録管理に進むために利用資格の確認を行ってください。</font></P>
+
+<P><font size=+1>利用資格の確認には、ユーザ名とパスワードが必要です。自分のユーザ名やパスワードが解らない場合は、総合情報基盤センターに尋ねてください。</font></P>
+
+<P>
+下の入力欄に、ユーザIDとパスワードを入力して、「送信」ボタンを押して下さい。
+</P>
+
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<P>
+<form method="POST" action="%%CGINAME%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">
+<INPUT TYPE="HIDDEN" NAME="redirected_url" VALUE="%%REDIRECTEDURL%%">
+
+<TABLE BORDER=0>
+<TR NOWRAP>
+<TD><strong>ユーザID:</strong></TD><TD><INPUT TYPE="TEXT" SIZE=20 NAME="userid"></TD>
+</TR><TR NOWRAP>
+<TD><strong>パスワード:</strong></TD><TD><INPUT TYPE="PASSWORD" SIZE=20 NAME="password"></TD>
+</TR><TR NOWRAP>
+<TD></TD><TD><INPUT TYPE="SUBMIT" VALUE="  送  信  "></TD>
+</TR>
+</TABLE>
+</form>
+</P>
+<p>
+<font size=+1>不明な点などがありましたら、ネットワーク管理者にお尋ねく
+ださい。</font></p>
+</center>
+
+
+<div align=right>佐賀大学</div>
+
+</body>
+</html>
diff --git a/html/ja/macchk.html b/html/ja/macchk.html
new file mode 100644 (file)
index 0000000..8e65e51
--- /dev/null
@@ -0,0 +1,73 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+<script type="text/JavaScript" src="/opengate/macchk.js"></script>
+</head>
+<body onload="setParameters('%%CHECKCGI%%', %%TIMEOUT%%)">
+
+<h3>MACアドレス調査</h3>
+
+<p>
+<a href="%%CHECKCGI%%?lang=en" >English Page</a>
+</p>
+<p>ユーザID:%%USERID%%</p>
+
+<form name='checkform' id='checkform'>
+<table border='1'>
+  <tr>
+    <td>選択</td>
+    <td>MACアドレス</td>
+    <td>NICベンダー</td>
+    <td>IPv4アドレス</td>
+    <td>IPv6アドレス</td>
+    <td>使用中</td>
+    <td>登録済</td>
+  </tr>
+%%MACCHECKLIST%%
+</table>
+<input type='button' name='open' value='開放' onclick='openNet();'>  
+<input name='timer' size="4" >
+<input type='button' name='close' value='閉鎖' onclick='closeNet();' disabled> 
+</form>
+<p></p>
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<p>
+<form name='regform' id='regform' method='get' action='%%REGISTERCGI%%'>
+<input name='macaddr'><input type='submit' value='登録'> <br>
+<input type='radio' name='lang' value='ja' checked>日本語  
+<input type='radio' name='lang' value='en'>英語<br>
+</form>
+</p>
+
+<p>
+<a href=opengatemup.cgi?lang=ja>登録更新ページ</a>
+</p>
+
+<hr>
+<p>
+使用方法
+<ol>
+<li>登録を希望する端末で、この端末と同じアクセスポイントに接続して、ネッ
+トワークアクセスを試み、ネットワークが閉鎖していることを確認する。
+<li>このページを表示する。確認前に表示しているときはリロードを行う。
+<li>上記の表は、同一アクセスポイントを最近利用した端末のアドレス一覧である。リストの先頭が最も最近に検出した端末である。
+<li>登録希望端末と予想されるアドレスを選択して「開放」ボタンを押す。
+<li>サーバが応答して、ネットワークを開放すると、タイマーが始動する。
+<li>タイマー作動中に、登録希望端末でネットワークを利用してみる。
+<li>利用が不可であれば、「閉鎖」ボタンで閉鎖して、別のアドレスを試す。
+<li>利用が可能であれば、「閉鎖」ボタンで閉鎖して、利用が不可に戻ることを確認し、「登録」ボタンで登録ページへ移行する。
+</ol>
+</p>
+<p>
+注意事項
+<ul>
+<li>タイマーが始動しない場合はサーバ不調の可能性があるので、管理者に連絡すること。
+<li>「閉鎖」ボタンを押さなくてもネットワークは時間切れで閉鎖される。開放のままページ移行しても問題ない。しかし「閉鎖」ボタンで早期に閉鎖することが望ましい。
+</ul>
+</p>
+</body>
+</html>
diff --git a/html/ja/macdeny.html b/html/ja/macdeny.html
new file mode 100644 (file)
index 0000000..f9deedb
--- /dev/null
@@ -0,0 +1,14 @@
+       
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title></title>
+</head>
+<body align="center">
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+</body>
+</html>
diff --git a/html/ja/macfwd.html b/html/ja/macfwd.html
new file mode 100644 (file)
index 0000000..5855d7f
--- /dev/null
@@ -0,0 +1,19 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=UTF-8">
+<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+<META HTTP-EQUIV="Refresh" CONTENT="1; URL=https://%%JUMPCGIURL%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">
+
+<TITLE>OpengateM Start</TITLE>
+</HEAD>
+<BODY>
+OpengateMによる「ネットワーク利用者認証」のページへ自動移動します。
+<P>
+自動移動できない方はこちらをクリックして下さい。
+<P>
+<a href="https://%%JUMPCGIURL%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">ネットワーク利用者認証(SSL)</a><br>
+<a href="http://%%JUMPCGIURL%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">ネットワーク利用者認証(NonSSL)</a><br>
+<HR>
+佐賀大学
+</BODY>
+</HTML>
diff --git a/html/ja/macreg.html b/html/ja/macreg.html
new file mode 100644 (file)
index 0000000..73f1357
--- /dev/null
@@ -0,0 +1,67 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+</head>
+<body align="center">
+<p><font size="5">MACアドレス登録</font></p>
+
+<p>
+<a href="%%REGISTERCGI%%?lang=en&redirectedurl=%%REDIRECTEDURL%%" >English Page</a>
+</p>
+
+<p>ユーザID:%%USERID%%</p>
+
+<form method="post" action="%%REGISTERCGI%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">
+<table border="1">
+  <tr align="middle">
+    <td>MACアドレス</td>
+    <td>機器名</td>
+    <td>メールアドレス</td>
+  </tr>
+  <tr align=middle>
+  <td><input  size=30 value='%%MACADDR%%' name=macaddr readonly></td>
+  <td><input  size=30 value='%%DEVICE%%' name=device style ='BACKGROUND-COLOR: yellow'></td>
+  <td><input  size=30 value='%%MAILADDR%%'name=mailaddr style ='BACKGROUND-COLOR: yellow'></td>
+  </tr>
+</table>
+
+<p><input type="submit" value=" 登録 "></p>
+</form>
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<ol>
+<li>端末を登録すると今月末(月の後半登録では翌月末)までパスワード入力なしで利用できます。</li>
+<li>期限前には、上記メールアドレスにメールが届きます。</li> 
+<li>機器名には端末を識別できる名前を入れてください。
+漢字は不可です(例:iPadX, X-01A, TabletAZ)。 </li>
+<li>登録は一人当り5台までです。</li>
+<li>登録が終ったら認証状態をリセットするためにブラウザを終了して下さい。
+</li>
+</ol>
+
+<p><font size=+1>既登録端末</font></p>
+<p>
+<table border='1'>
+  <tr align=middle>
+    <td>MAC アドレス</td>
+    <td>機器名</td>
+    <td>登録日</td>
+    <td>期限日</td>
+    <td>状態</td>
+    <td>メールアドレス</td>
+  </tr>
+%%MACREGLIST%%
+</table>
+</p>
+
+
+<p>
+<a href=opengatemup.cgi?lang=ja>登録更新ページ</a>
+</p>
+
+</body>
+</html>
diff --git a/html/ja/macreturn.html b/html/ja/macreturn.html
new file mode 100644 (file)
index 0000000..28fba65
--- /dev/null
@@ -0,0 +1,39 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=UTF-8">
+<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+<META HTTP-EQUIV="Refresh" CONTENT="%%WAITTIME%%; URL=%%REDIRECTEDURL%%">
+
+<script type="text/javascript">
+<!--
+var seconds;
+
+function startTimer(timeout){
+  seconds=timeout;
+  setTimeout('onTimeout()', 1000);
+}
+
+function onTimeout(){
+  seconds--;
+  document.getElementById("timer1").innerHTML = seconds;
+  if(seconds<=0) window.location.href='%%REDIRECTEDURL%%';
+  else setTimeout('onTimeout()', 1000);
+}
+// -->
+</script>
+
+</HEAD>
+<BODY onload='startTimer(%%WAITTIME%%)'>
+<P>
+自動的に元のページへ移動します。しばらくお待ちください。
+<font size=+1>[<span id="timer1">%%WAITTIME%%</span>]</font>
+</P>
+<P>自動移動できない方は下のリンクをクリックして下さい。またはブラウザ
+を再起動してみてください。</P>
+<P>
+<font size=+1><a href="%%REDIRECTEDURL%%">次へ</a></font>
+</P>
+<HR>
+佐賀大学
+</BODY>
+</HTML>
diff --git a/html/ja/macupdate.html b/html/ja/macupdate.html
new file mode 100644 (file)
index 0000000..7afb18c
--- /dev/null
@@ -0,0 +1,61 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title></title>
+</head>
+<body align="center">
+<p><font size="5">MACアドレス登録更新</font></p>
+
+<p><a href="%%CGINAME%%?lang=en&redirectedurl=%%REDIRECTEDURL%%">English Page</a></p>
+
+
+<p>ユーザID:%%USERID%%</p>
+
+<form method="post" action="%%CGINAME%%?lang=ja&redirectedurl=%%REDIRECTEDURL%%">
+<table border="1">
+  <tr align="middle">
+    <td>更新</td>
+    <td>休止</td>
+    <td>削除</td>
+    <td>MACアドレス</td>
+    <td>機器名</td>
+    <td>登録日時</td>
+    <td>期限日時</td>
+    <td>状態</td>
+  </tr>
+%%MACLIST%%
+</table>
+
+<p><input type="submit" value=" 送信 "></p>
+</form>
+
+<p><font color="red">
+%%ERRORLIST%%
+</font></p>
+
+<p><strong>「更新」</strong>をチェックすると、機器の登録を更新して利用
+期限を延長します。不正利用を防ぐため、更新時には、下の利用履歴が妥当か確認して下さい。</p>
+
+<p><strong>「休止」</strong>をチェックすると、利用期限を早めて利用不可にします。再び利用するときには更新処理をしてください。
+</p>
+<p><strong>「削除」</strong>をチェックすると、機器の登録を削除します。
+再び利用する可能性が有るときは、休止を利用下さい。
+</p>
+<p>状態が'I'となっている機器は無効とされています。理由は管理者に問い合わせ下さい。</p>
+
+
+<p><font size="5">利用履歴</font></p>
+<p>
+<table border="1">
+  <tr align="middle">
+    <td> MACアドレス</td>
+    <td> 機器名</td>
+    <td> 開始時間</td>
+    <td> 曜日</td>
+    <td> ゲートウェイ</td>
+  </tr>
+%%USAGELOG%%
+</table>
+</p>
+</body>
+</html>
diff --git a/html/ja/warning.php b/html/ja/warning.php
new file mode 100644 (file)
index 0000000..bec2ff1
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> \r
+<html>\r
+  <head>\r
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">\r
+    <title>warning</title>\r
+  </head>\r
+  <body>\r
+    <h2>タブレット・スマートフォン用の認証システムOpengateMの試験運用</h2>\r
+    <br>\r
+    <br>\r
+    Opengateが使いにくいタブレットやスマートフォン用に認証システムを開\r
+発中です。学内の無線LANにおいて試験運用を行っていますので、\r
+お試しいただければ幸いです。不具合等があれば連絡下さい。\r
+なお、予告なくサービスを休止・中断することがあります。<br>\r
+    <br>\r
+利用するには、\r
+\r
+<?php \r
+$lang=""; $redirectedurl="";\r
+if(isset($_GET['lang']))$lang=$_GET['lang'];\r
+if(isset($_GET['redirectedurl'])) $redirectedurl=$_GET['redirectedurl'];\r
+echo "<a href=/cgi-bin/opengate/opengatemown.cgi?",\r
+"lang=",$lang,"&redirectedurl=",$redirectedurl,">"?>\r
+\r
+登録ページ</a>\r
+で端末を登録してください。ただし、通常のWindowsやMacOS端末はOpengate認証が\r
+使えるので現状では登録を制限しています。<br>\r
+    <br>\r
+利用登録は当月または翌月の月末に期限切れとなります。期限の1週間前と\r
+1日前に、警告メールが送られてきますので、メール内に記載されたURL\r
+で更新処理を行ってください。または期限切れ端末でネットワークアクセスを\r
+するとOpengate認証が出ますので、登録時と同じリンクを辿って\r
+更新を行ってください。なお、不正利用防止のために、更新時にはページに\r
+記載された利用履歴の確認をお願いします。<br>\r
+    <br>\r
+連絡先:渡辺義明:watanaby(at)is.saga-u.ac.jp、\r
+大谷 誠:otani(at)cc.saga-u.ac.jp<br>\r
+    <br>\r
+</body> </html>\r
diff --git a/html/macchk.js b/html/macchk.js
new file mode 100644 (file)
index 0000000..44d3b1a
--- /dev/null
@@ -0,0 +1,76 @@
+//<!--
+var seconds;
+var status;
+var macaddr;
+var httpObj;
+var cginame;
+var timeout;
+
+function createXMLHttpRequest() {
+  try { return new ActiveXObject("Msxml2.XMLHTTP");    } catch(e) {}
+  try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
+  try { return new XMLHttpRequest();                   } catch(e) {}
+  return null;
+}
+
+function ajaxRequest(status){
+  if((httpObj=createXMLHttpRequest())!=null){
+    try{  
+      httpObj.open('post', cginame ,false);
+      httpObj.setRequestHeader('content-type',
+       'application/x-www-form-urlencoded,charset=utf-8');
+      httpObj.send('status='+status+'&macaddr='+macaddr);
+      if(status=='open') startTimer();
+      else stopTimer();
+    }catch(e){ }
+  }
+}
+
+function openNet(){
+  document.checkform.open.disabled=true;
+  document.checkform.close.disabled=false;
+  getMacAddr();
+  document.regform.macaddr.value=macaddr;
+  ajaxRequest('open');
+}
+
+function closeNet(){
+  document.checkform.open.disabled=false;
+  document.checkform.close.disabled=true;
+  ajaxRequest('close');
+}
+
+function startTimer(){
+  seconds=timeout;
+  setTimeout('onTimeout()', 1000);
+}
+
+function stopTimer(){
+  seconds=0;
+}
+
+function onTimeout(){
+  document.checkform.timer.value=seconds;
+  seconds--;
+  if(seconds<0) closeNet();
+  else setTimeout('onTimeout()', 1000);
+}
+
+function getMacAddr(){
+  if(document.checkform.macaddr==undefined) macaddr='';
+  else if(document.checkform.macaddr.length==undefined)
+    macaddr=document.checkform.macaddr.value;
+  else{
+    for(var i=0; i<document.checkform.macaddr.length; i++){
+      if(document.checkform.macaddr[i].checked){
+        macaddr=document.checkform.macaddr[i].value;
+      }
+    }
+  }
+}
+
+function setParameters(cginameArg, timeoutArg){
+  cginame=cginameArg;
+  timeout=timeoutArg;
+}
+//-->
diff --git a/mdsrc/Makefile b/mdsrc/Makefile
new file mode 100644 (file)
index 0000000..03da134
--- /dev/null
@@ -0,0 +1,113 @@
+################ Change following ########################
+##  some other parameters exist in opengatemd.h  ########
+##########################################################
+CONFIGPATH = /etc/opengate        ## directory of config file
+INSTALLBINPATH = /usr/local/bin   ## install dir of executable file
+MAKEDIR != pwd                 ## save present directory
+
+.if exists(/usr/local/include/mysql)
+CFLAGSMYSQL = -I/usr/local/include/mysql -pipe -fno-strict-aliasing
+LIBMYSQL = -L/usr/local/lib/mysql -lmysqlclient  -pthread -lz -lm
+.endif
+
+.if exists(/usr/local/include/sqlite3.h)
+LIBSQLITE = -lsqlite3 -lpthread
+.endif
+
+## This is memory leak check tool for debugging
+#LIBCCMALLOC = -lccmalloc -L/usr/local/lib
+
+CFLAGS= -g -O4 -Wall -I/usr/local/include ${CFLAGSMYSQL}
+
+LIBS = -lezxml -lpcap -L../ezxml -L/usr/local/lib  ${LIBSQLITE} ${LIBMYSQL} ${LIBCCMALLOC}
+
+OBJS = util.o error.o getparam.o managementdb.o workdb.c ipfw.o pcap.o packetcache.o macdbcache.o session.o ttlcheck.o udpserv.o
+HDRS = opengatemd.h
+
+MDMAINPROGO = opengatemd.o
+MDMAINPROG = opengatemd
+
+LIBOPT = ezxml
+
+CLEANFILES = *.o *~ *.core a.out \\#*
+
+all:   ${MDMAINPROG} ${LIBOPT}
+
+opengatemd:    ${OBJS} ${MDMAINPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${MDMAINPROGO} ${LIBS}
+
+ezxml: 
+               ${MAKE} -C ../ezxml
+clean:
+               rm -f ${MDMAINPROG} ${CLEANFILES}
+               ${MAKE} clean -C ../ezxml
+               rm -f ../*/*~  ../*~ ../*/*/*~
+
+install:       install-md-prg install-conf rm-lockfile
+
+rm-lockfile:   #
+               rm -f /tmp/opengatemd.lock
+               rm -f /tmp/opengate.lock
+
+install-md-prg:        ${MDMAINPROG}
+               ## Install program and Set S bit ##
+.if !exists(${INSTALLBINPATH})
+               mkdir ${INSTALLBINPATH}
+.endif
+               cp ${MDMAINPROG} ${INSTALLBINPATH}/${MDMAINPROG}
+               chmod 4755 ${INSTALLBINPATH}/${MDMAINPROG}
+               cp ../rc.d/${MDMAINPROG} /etc/rc.d/${MDMAINPROG}
+               chmod 555 /etc/rc.d/${MDMAINPROG}
+               #
+
+install-conf:
+               ## Copy Config files ##
+.if !exists(${CONFIGPATH})
+               mkdir ${CONFIGPATH}
+.endif
+               cp  ../conf/opengatemd.conf.sample ${CONFIGPATH}
+               cp  ../conf/rc.firewall.sample ${CONFIGPATH}
+               cp  ../conf/ipfwctrlmd.pl.sample ${CONFIGPATH}
+               #
+               #------------------------------------------------------#
+               # COPY above x.sample to x and EDIT it.                #
+               #   Eg. 'cp opengatemd.conf.sample  opengatemd.conf'   #
+               #------------------------------------------------------#
+
+opengatemd.o:  ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+util.o:                ${HDRS}
+
+mamagementdb.o:        ${HDRS}
+.if !exists(/usr/local/include/mysql)
+               ${CC} ${CFLAGS} -DMYSQL_NOT_INSTALLED -c $<
+.endif
+
+workdb.o:      ${HDRS}
+.if !exists(/usr/local/include/sqlite3.h)
+               ${CC} ${CFLAGS} -DSQLITE3_NOT_INSTALLED -c $<
+.endif
+
+error.o:       ${HDRS}
+
+getparam.o:    ${HDRS}
+
+ipfw.o:                ${HDRS}
+
+pcap.o:                ${HDRS}
+
+packetcache.o: ${HDRS}
+
+macdbcache.o:  ${HDRS}
+
+session.o:     ${HDRS}
+
+ttlcheck.o:    ${HDRS}
+
+getmac.o:      ${HDRS}
+
+queue.o:       ${HDRS}
+
+udpserv.o:     ${HDRS}
+
diff --git a/mdsrc/error.c b/mdsrc/error.c
new file mode 100644 (file)
index 0000000..1cfdfa1
--- /dev/null
@@ -0,0 +1,130 @@
+/**********************************************************/
+/* output error message to syslog or stdout               */
+/*  from UNIX NETWORK PROGRAMMING,Vol.1,Second Edition,   */
+/*      By W. Richard Stevens, Published By Prentice Hall */
+/*       ftp://ftp.kohala.com/pub/rstevens/unpv12e.tar.gz */
+/**********************************************************/
+
+#include "opengatemd.h"
+#include       <stdarg.h>              /* ANSI C header file */
+#include       <syslog.h>              /* for syslog() */
+
+int            daemon_proc;
+
+static void    err_doit(int, int, const char *, va_list);
+
+/*************************************************/
+/* Nonfatal error related to a system call.
+ * Print a message and return. */
+/*************************************************/
+void errToSyslog(int i)
+{
+  daemon_proc=i;
+}
+
+void
+err_ret(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_INFO, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/*************************************************/
+/* Fatal error related to a system call.
+ * Print a message and terminate. */
+/*************************************************/
+void
+err_sys(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_ERR, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+/*************************************************/
+/* Fatal error related to a system call.
+ * Print a message, dump core, and terminate. */
+/*************************************************/
+void
+err_dump(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_ERR, fmt, ap);
+       va_end(ap);
+       abort();                /* dump core and terminate */
+       exit(1);                /* shouldn't get here */
+}
+
+/*************************************************/
+/* Nonfatal error unrelated to a system call.
+ * Print a message and return. */
+/*************************************************/
+void
+err_msg(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(0, LOG_INFO, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/*************************************************/
+/* Fatal error unrelated to a system call.
+ * Print a message and terminate. */
+/*************************************************/
+void
+err_quit(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(0, LOG_ERR, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+
+/*************************************************/
+/* Print a message and return to caller.
+ * Caller specifies "errnoflag" and "level". */
+/*************************************************/
+static void
+err_doit(int errnoflag, int level, const char *fmt, va_list ap)
+{
+       int             errno_save, n;
+       char    buf[BUFFMAXLN];
+
+       errno_save = errno;             /* value caller might want printed */
+#ifdef HAVE_VSNPRINTF
+       vsnprintf(buf, sizeof(buf), fmt, ap);   /* this is safe */
+#else
+       vsprintf(buf, fmt, ap);                                 /* this is not safe */
+#endif
+       n = strlen(buf);
+       if (errnoflag)
+               snprintf(buf+n, sizeof(buf)-n, ": %s", strerror(errno_save));
+       strcat(buf, "\n");
+
+       if (daemon_proc) {
+               syslog(level, buf);
+       } else {
+               fflush(stdout);         /* in case stdout and stderr are the same */
+               fputs(buf, stderr);
+               fflush(stderr);
+       }
+       return;
+}
+
+
+
diff --git a/mdsrc/getparam.c b/mdsrc/getparam.c
new file mode 100644 (file)
index 0000000..859c41e
--- /dev/null
@@ -0,0 +1,557 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module for getting parameters from conf file
+
+Copyright (C) 2006 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+
+Programmed by Yoshiaki WATANABE
+
+**************************************************/
+#include "opengatemd.h"
+#include "../ezxml/ezxml.h"
+
+#define CONFIG_VERSION "0.6.0"
+#define SEPARATOR "/"
+
+int debug=0;
+static ezxml_t xmlRoot=NULL;
+static ezxml_t xmlExtraSet=NULL;
+static ezxml_t xmlAuthServer=NULL;
+static ezxml_t xml=NULL;
+static ezxml_t xmlSave=NULL;
+
+char *getConfValueExtra(char *name);
+char *getConfValue(char *name);
+char *convertToFacilityRaw(char *pValue);
+int selectNextAuthServer(void);
+char *GetConfAuthServer(char *name);
+
+/*** dummys ***/
+void PutMessageToClient(char* buff){
+    err_msg("ERR at %s#%d: %s",__FILE__,__LINE__,buff);
+}
+char* getProgramName(void){
+  return "";
+}
+
+
+/**************************************************/
+/* Prepare Conf file to use                       */
+/* this is called before syslog setup             */
+/**************************************************/
+int openConfFile(void)
+{
+  char buff[BUFFMAXLN];
+  char *s;
+  char *errMsg;
+
+  /* parse file and make tree */
+  if((xmlRoot = ezxml_parse_file(CONFIGFILE))==NULL){
+
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, " is not found. Call the administrator.</H3><BR>",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* to check error, convert to xml */
+  s=ezxml_toxml(xmlRoot);  free(s);
+  
+  /* if failed, show error message */
+  errMsg=(char *)ezxml_error(xmlRoot);
+
+  if(*errMsg!='\0'){
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, " is illegal. Call the administrator.</H3><HR>",BUFFMAXLN);
+    strncat(buff, "XML parser message: ", BUFFMAXLN);
+    strncat(buff, errMsg, BUFFMAXLN);
+    strncat(buff, "<HR>", BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* check the config file version */ 
+  if(isNull(ezxml_attr(xmlRoot, "ConfigVersion"))||
+     (strcmp(CONFIG_VERSION, ezxml_attr(xmlRoot, "ConfigVersion"))!=0)){
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE, BUFFMAXLN);
+    strncat(buff, " has mismatch version.<br> Please update it with ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE, BUFFMAXLN);
+    strncat(buff, ".sample.",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* check the syslog */
+  if(atoi(GetConfValue("Syslog/Enable")) &&
+     atoi(GetConfValue("Syslog/Facility"))==0){
+
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: correct SYSLOG setting(local0-local7) is not found in Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, ". Call the administrator.</H3><BR>",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  return 0;
+}
+
+/**************************************************/
+/*  initialize the Config                         */
+/**************************************************/
+void initConf(void)
+{
+  /* as debug flag is used many times, put it in gloval variable */
+  debug=atoi(getConfValue("Debug"));
+}
+
+/**************************************************/
+/* Finish Conf file usage                         */
+/**************************************************/
+void closeConfFile(void)
+{
+  if(xmlRoot!=NULL)ezxml_free(xmlRoot);
+}
+
+/**************************************************/
+/* Setup pointer to the matched ExtraSet          */ 
+/**************************************************/
+void setupConfExtra(char * userId,char *extraId)
+{
+  char* progName;
+
+  /* init as no ExtraSet */
+  xmlExtraSet=NULL;
+
+  /* search the matching extra set (first match is employed) */
+  for(xml=ezxml_child(xmlRoot, "ExtraSet"); xml; xml=xml->next){
+    
+    /* if ExtraId is exist, check it */
+    if(!isNull(ezxml_attr(xml, "ExtraId"))){
+
+      /* if not match, go to next ExtraSet */
+      /* ('default' indicated in conf matchs to Null-extraId) */
+      if(isNull(extraId)){
+       if(strcmp("default", ezxml_attr(xml, "ExtraId"))!=0)continue;
+      }else{
+       if(strcmp(extraId, ezxml_attr(xml, "ExtraId"))!=0)continue;
+      }
+    }
+
+    /* if userID pattern is exist, check it */
+    if(!isNull(ezxml_attr(xml, "UserIdPattern"))){
+
+      /* if not matched, go to next ExtraSet */
+      if(RegExMatch(userId, ezxml_attr(xml, "UserIdPattern"))==FALSE) continue;
+    }
+
+    /* found matched ExtraSet */
+    break;
+  }
+
+  /* if found a matched ExtraSet, save the pointer */
+  if(xml!=NULL) xmlExtraSet=xml;
+
+  /* change syslog setting */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  progName=getProgramName();
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* reset config setting */
+  InitConf();
+}
+
+/***********************************************/
+/* regular expression matching                 */
+/*  inStr : string to match                    */
+/*  regEx : regular expression                 */
+/***********************************************/
+int regExMatch(const char *inStr, const char *regEx)
+{
+  regex_t reg;
+  int errcode;
+  int match;
+  char errbuff[WORDMAXLN];
+
+  /* compile regex */
+  if((errcode=regcomp(&reg, regEx, REG_NOSUB|REG_EXTENDED|REG_ICASE))!=0){
+    regerror(errcode, &reg, errbuff, WORDMAXLN);
+    err_msg("ERR at %s#%d: regex message=%s",__FILE__,__LINE__,errbuff);
+    match=FALSE;
+  }
+  
+  /* if compile is success, check the input string */
+  else{
+    if(regexec(&reg, inStr, (size_t)0, NULL, 0)==0) match=TRUE;
+    else match=FALSE;
+  }
+
+  regfree(&reg);
+
+  return match;
+}
+
+/**************************************************/
+/*  get a value for name from Conf file           */
+/*  the name[aa/bb/cc] means the path             */
+/*  if ID is set, extraSet value is overlayed */
+/**************************************************/
+char *getConfValue(char *name)
+{
+  char *pValue;
+  char *pValueExtra;
+  char *pStr;
+  char buff[BUFFMAXLN];
+
+  /* AuthServer setting is done in other routine */
+  if(strstr(name,"AuthServer/")==name) return GetConfAuthServer(name);
+
+  /* copy name to work area */
+  strncpy(buff,name,BUFFMAXLN);
+
+  /* get first token */
+  pStr=strtok(buff, SEPARATOR);
+
+  /* set search start to root of tree */
+  xml=xmlRoot;
+
+  /* search the tree node for the name */
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get, write error message */
+  if(pValue==NULL){
+    err_msg("ERR at %s#%d: cannot get %s from conf file",__FILE__,__LINE__,name);
+  }
+
+  /* get value in extra set matched to ID */
+  /* if name is matched in first level, reset all child setting */
+  /* in this section, many parameters are not set */
+  if(!isNull(pValueExtra=getConfValueExtra(name))){
+    pValue=pValueExtra;
+  }
+
+  /* if syslog facility, the id is converted to raw value */
+  if(strcmp(name,"Syslog/Facility")==0){
+    pValue=convertToFacilityRaw(pValue);
+  }
+
+  /* return found value */
+  return pValue;
+}
+
+/************************************************/
+/* get the value in extra set matched to ID     */
+/************************************************/
+char *getConfValueExtra(char *name)
+{
+  char *pStr;
+  char buff[BUFFMAXLN];
+  ezxml_t xml;
+
+  if(xmlExtraSet==NULL) return "";
+
+  /* extract first token in name */
+  strncpy(buff,name,BUFFMAXLN);
+  pStr=strtok(buff, SEPARATOR);  
+
+  /* get a first level matched node in extra set */
+  /* the first level is not included in the following loop */
+  /* as to prevent partial overlay of sub level value */
+  xml=ezxml_child(xmlExtraSet, pStr);
+  if(xml==NULL) return "";
+
+  /* search the node matched to name */
+  pStr=strtok(NULL, SEPARATOR);
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* return the found value */
+  return ezxml_txt(xml);
+}
+
+
+/***************************************************/
+/*  get a value for AuthServer param from Conf file*/
+/*  the name[AuthServer/bb/cc] means the path      */
+/***************************************************/
+char *getConfAuthServer(char *name)
+{
+  char *pValue;
+  char *pStr;
+  char buff[BUFFMAXLN];
+  ezxml_t xml;
+
+  /* copy name to work area */
+  strncpy(buff,name,BUFFMAXLN);
+
+  /* get first token */
+  pStr=strtok(buff, SEPARATOR);
+
+  /* it must be AuthServer. if not return */
+  if(strcmp(pStr, "AuthServer")!=0)return NULL;
+
+  /* if authserver pointer is not set, set it */
+  if(xmlAuthServer==NULL){
+    if(!selectNextAuthServer()) return NULL;
+  }
+
+  /* set search start to the saved pointer */
+  xml=xmlAuthServer;
+
+  /* search the tree node for the name */
+  pStr=strtok(NULL, SEPARATOR);
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get Protocol, write error message */
+  if(isNull(pValue)
+     && (strcmp(name,"AuthServer/Protocol")==0) ){
+    err_msg("ERR at %s#%d: cannot get %s from conf file",__FILE__,__LINE__,name);
+  }
+
+  /* return found value */
+  return pValue;
+}
+
+/**********************************/
+/* select next authserver setting */
+/**********************************/
+int selectNextAuthServer(void){
+
+  ezxml_t xmlTmp; /* temporary variable */
+
+  /* first call (initialize) */
+  /* xmlAuthPointer is the static variable to save authserver pointer */
+  if(xmlAuthServer==NULL){
+
+    /* if not set, search the first authserver pointer */
+     xmlAuthServer=ezxml_child(xmlRoot, "AuthServer");
+     
+     /* if authserver is found in extra set, pointer is moved to it */ 
+     if(xmlExtraSet!=NULL){
+       xmlTmp=ezxml_child(xmlExtraSet, "AuthServer");
+       if(xmlTmp!=NULL){
+        xmlAuthServer=xmlTmp;
+       }
+     }
+  }
+
+  /* successive calls */
+  /* pointer is moved to next */
+  else{
+    xmlAuthServer=ezxml_next(xmlAuthServer);
+  }
+
+  /* if not found return False */
+  if(xmlAuthServer==NULL){
+    return FALSE;
+  }else{
+    return TRUE;
+  }
+}
+
+/**********************************************
+reset pointer for auth server list
+**********************************************/
+void resetAuthServerPointer(void){
+  xmlAuthServer=NULL;
+}
+
+/***********************************************/
+/* Convart the syslog facility id to raw value */
+/***********************************************/
+char *convertToFacilityRaw(char *pValue)
+{
+  static char facility[WORDMAXLN];
+  int rawValue;
+
+  if     (strcmp(pValue, "local0")==0) rawValue=LOG_LOCAL0;
+  else if(strcmp(pValue, "local1")==0) rawValue=LOG_LOCAL1;
+  else if(strcmp(pValue, "local2")==0) rawValue=LOG_LOCAL2;
+  else if(strcmp(pValue, "local3")==0) rawValue=LOG_LOCAL3;
+  else if(strcmp(pValue, "local4")==0) rawValue=LOG_LOCAL4;
+  else if(strcmp(pValue, "local5")==0) rawValue=LOG_LOCAL5;
+  else if(strcmp(pValue, "local6")==0) rawValue=LOG_LOCAL6;
+  else if(strcmp(pValue, "local7")==0) rawValue=LOG_LOCAL7;
+  else rawValue=0;
+
+  snprintf(facility, WORDMAXLN, "%d", rawValue);
+
+  return facility;
+}
+
+/**************************************************/
+/*  get the first value as previous call           */
+/*  (next node of the lowest level of tree)       */  
+/**************************************************/
+char *getFirstConfValue(char* name)
+{
+   char *pValue;
+   pValue=GetConfValue(name);
+
+  /* save the pointer now */
+   xmlSave=xml;
+
+  /* return found value */
+  return pValue;
+}
+
+/**************************************************/
+/*  get the next value as previous call           */
+/*  (next node of the lowest level of tree)       */  
+/**************************************************/
+char *getNextConfValue(void)
+{
+  char *pValue;
+
+  /* recover previous pointer */
+  xml=xmlSave;
+
+  /* get next node */
+  if(xml==NULL) return "";
+  xml = ezxml_next(xml);
+
+  /* save for next call */
+  xmlSave=xml;
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get, write error message */
+  if(pValue==NULL) return "";
+
+  /* return found value */
+  return pValue;
+}
+
+
+/***********************************************/
+/***********************************************/
+int OpenConfFile(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>openConfFile( )");
+  ret = openConfFile();
+  if(debug>1) err_msg("DEBUG:(%d)<=openConfFile( )",ret);
+  return ret;
+}
+
+void CloseConfFile(void){
+  if(debug>1) err_msg("DEBUG:=>closeConfFile( )");
+  closeConfFile();
+  if(debug>1) err_msg("DEBUG:<=closeConfFile( )");
+}
+
+void SetupConfExtra(char *userId, char *extraId){
+  if(debug>1) err_msg("DEBUG:=>setupConfExtra(%s,%s)",userId, extraId);
+  setupConfExtra(userId, extraId);
+  if(debug>1) err_msg("DEBUG:<=setupConfExtra( )");
+}
+
+char *GetConfValue(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfValue(%s)",name);
+  ret=getConfValue(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfValue( )",ret);
+  return ret;
+}
+
+char *GetConfValueExtra(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfValueExtra(%s)",name);
+  ret=getConfValueExtra(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfValueExtra( )",ret);
+  return ret;
+}
+
+char *GetConfAuthServer(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfAuthServer(%s)",name);
+  ret=getConfAuthServer(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfAuthServer( )",ret);
+  return ret;
+}
+
+int SelectNextAuthServer(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>selectNextAuthServer( )");
+  ret=selectNextAuthServer();
+  if(debug>1) err_msg("DEBUG:(%d)<=selectNextAuthServer( )",ret);
+  return ret;
+}
+
+void InitConf(void){
+  if(debug>1) err_msg("DEBUG:=>initConf( )");
+  initConf();
+  if(debug>1) err_msg("DEBUG:<=initConf( )");
+}
+
+int RegExMatch(const char *inStr, const char *regEx){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>regExMatch(%s,%s)", inStr, regEx);
+  ret=regExMatch(inStr, regEx);
+  if(debug>1) err_msg("DEBUG:(%d)<=regExMatch( )",ret);
+  return ret;
+}
+  
+void ResetAuthServerPointer(void){
+  if(debug>1) err_msg("DEBUG:=>resetAuthServerPointer( )");
+  resetAuthServerPointer();
+  if(debug>1) err_msg("DEBUG:<=resetAuthServerPointer( )");
+}
+
+char *GetFirstConfValue(char* name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getFirstConfValue( )");
+  ret=getFirstConfValue(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getFirstConfValue( )",ret);
+  return ret;
+}
+
+char *GetNextConfValue(void){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getNextConfValue( )");
+  ret=getNextConfValue();
+  if(debug>1) err_msg("DEBUG:(%s)<=getNextConfValue( )",ret);
+  return ret;
+}
+
diff --git a/mdsrc/ipfw.c b/mdsrc/ipfw.c
new file mode 100644 (file)
index 0000000..40ed51e
--- /dev/null
@@ -0,0 +1,539 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module for Controlling ipfw 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+static void sigFunc(int signo);
+
+/******************************************************************
+ open gate for clientAddr
+     return=-2..+2: error
+     return=ruleNumber. if overlapped ip return=(-1)*ruleNumber
+******************************************************************/
+int openClientGate(char *macAddress, char* userId, char* extraId)
+{
+  int fd=0;
+  int retNum=-1;
+  struct stat st;
+  char* lockFile;
+  int lockFileExist=TRUE;
+  char userIdLong[WORDMAXLN];
+  char clientAddr[WORDMAXLN]="?";
+  char ruleNumber[WORDMAXLN];
+
+  Sigfunc *defaultSigFunc;
+
+  /* prepare userid-long as [userid@extraid] */
+  strncpy(userIdLong, userId, WORDMAXLN);
+  if(!isNull(extraId)){
+    strncat(userIdLong, "@", WORDMAXLN);
+    strncat(userIdLong, extraId, WORDMAXLN);
+  }
+
+  /* exclusive exec of ipfw to avoid overlapped rule number */
+  /**** prepare ****/
+  /* if not found lock is ignored */
+  lockFile=GetConfValue("LockFile");
+  if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
+  else lockFileExist=TRUE;
+
+  /* if lock file exists, exec lock */
+  if(lockFileExist){
+    /* open lockfile */
+    fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+    if(fd==-1){
+      err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
+      return -1;
+    } 
+
+    /* set timeout */
+    if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
+      err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
+      Close(fd);
+      return 1;
+    }
+    alarm(atoi(GetConfValue("LockTimeout")));
+    
+    /* lock */
+    if(Lock(fd)<0){
+      err_msg("ERR at %s#%d: lock error/timeout",__FILE__,__LINE__);
+      Close(fd);
+      return -1;
+    }
+
+    /* reset timeout */
+    signal(SIGALRM, defaultSigFunc);
+    alarm(0);
+  }
+
+  /**** read rules ****/
+  if((retNum=GetRuleNumber(macAddress))<0){
+    /* fail then unlock */
+    if(lockFileExist){
+      Unlock(fd);
+      Close(fd);
+    }
+    return retNum; /* perhaps aleady registered addr is -retNum */
+  }
+
+  /* to string */
+  snprintf(ruleNumber, WORDMAXLN, "%d", retNum);
+
+  /**** write rules ****/
+  /* branch by perl script control flag */
+  if(atoi(GetConfValue("IpfwScript/Enable"))){
+    /********** use perl script to control firewall ************/
+
+    if(Systeml(1, GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
+              ruleNumber,clientAddr,userIdLong,macAddress,"-",
+              GetConfValue("IpfwTagNumber"),GetConfValue("Pcap/Device"),
+              (char *)0) != 0){
+      err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
+      retNum=1;  /* abnormal */
+    }
+  }
+
+  else{
+    /********** direct control of firewall **********************/
+    /********** add outgoing ipfw rule for the client *************/
+    if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
+              "count","tag",GetConfValue("IpfwTagNumber"),
+              "ip","from","any","to","any","MAC","any",macAddress,
+              "via",GetConfValue("Pcap/Device"),"keep-state",
+              "//", userIdLong, (char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
+      retNum=1;  /* abnormal */
+    }
+    
+    if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
+              "count","tag",GetConfValue("IpfwTagNumber"),
+              "ip","from","any","to","any","MAC",macAddress,"any",
+              "via",GetConfValue("Pcap/Device"),"keep-state",
+              "//", userIdLong, (char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
+      retNum=1; /* abnormal */
+    }
+  }
+
+  /* unlock */
+  if(lockFileExist){
+    Unlock(fd);
+    Close(fd);
+  }
+  
+  return retNum;
+}
+
+
+/******************************************************************
+ close gate for clientAddr for the rule number                  
+******************************************************************/
+void closeClientGate(int ruleNumber)
+{
+  int count;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* count rule */
+  count=CountRuleNumber(ruleNumber);
+
+  if(count>0){
+    /* exec ipfw del */
+    /* [ipfw del rule] deletes all rule of the rule number at one call */
+    if(Systeml(1, GetConfValue("IpfwPath"),"delete",ruleNumberStr,(char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw del error",__FILE__,__LINE__);
+    }
+  }
+}
+
+/**************************************
+ get unused ipfw rule number       
+ return value ret>0: acquired rule number that can be used 
+              ret=-1: no rule number available 
+              ret=-2: some system error occured 
+              ret=-num: the mac address is already registered in rule 'num' 
+**************************************/
+int getRuleNumber(char *macAddress)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int num,newNum,readinNum;
+  int ipfwmin;
+  int ipfwmax;
+  int ipfwinterval;
+  int portStatus;
+  int fileStatus;
+  char* p;
+
+  enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
+
+  /* exec ipfw list and open pipe */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
+      err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* search unused rule number in the list read from pipe */
+  /* check duplication of clientAddr to existing rules */
+
+  newNum=-1;
+  readinNum=0;
+  portStatus=NOTFOUND;
+  fileStatus=NORMAL;
+
+  /* get rule range from config */
+  ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
+  ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
+  ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
+
+  /* each port is checked whether it can be used for new rule or not */
+  for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
+
+    /* skip rules smaller than num */
+    while(readinNum<num){
+      if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
+       if(feof(fpipe)==1) fileStatus=EOF; 
+       else fileStatus=ABNORMAL;
+       break;
+      }
+      if( sscanf(buf, "%d", &readinNum) !=1 ){
+       err_msg("ERR at %s#%d: abnormal ipfw response[ %s ]",
+               __FILE__,__LINE__, buf);
+       fileStatus=ABNORMAL; /* abnormal responsem exit internal loop */
+       break;
+      }
+    }
+
+    if(fileStatus==ABNORMAL){
+      /* abnormal file proc, exit external loop */ 
+      break;
+    }
+
+    if(fileStatus==EOF){
+      /* EOF before reading a rule that is larger or equal to num */
+      /* it means that num can be used for new client */
+      portStatus=FOUND;
+      newNum=num;
+      break;
+    }
+
+    /* at this point, readinNum is larger or equal to num */
+    /* check number duplication */
+    if(readinNum==num){
+
+      /* if macAddress is found in the rule, then exit, else check next rule */
+      /* following code checks the existence of "space+macAddress+space|etc" */
+      if(((p=(char*)strstr(buf+1,macAddress))!=NULL)
+        && isspace(*(p-1))
+        && !isalnum(*(p+strlen(macAddress)))){
+       newNum=num;
+       portStatus=DUP;
+       break;
+      }else{
+       continue;
+      }
+    }
+    /* at this point, readNum is larger than num */
+    /* it means that num can be used for new client */
+    newNum=num;
+    portStatus=FOUND;
+
+    break;
+  }
+  
+  /* close pipe */
+  Pclose(fpipe);
+    
+  if(fileStatus==ABNORMAL){
+    err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
+    return -2;
+  }
+  if(portStatus==NOTFOUND){
+    err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
+    return -1;
+  }
+  if(portStatus==DUP){
+    return -newNum;
+  }
+
+  return newNum;
+}
+
+/*******************************
+ get packet count from ipfw  
+*******************************/
+int getPacketCount(int ruleNumber)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int rule;
+  int packets,packetsSum;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* exec proc */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"-a","list",ruleNumberStr,(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw -a list error",__FILE__,__LINE__);
+  }
+
+  /* search unused number in the list read from pipe */
+  packetsSum=0;
+    
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+    sscanf(buf, "%d %d", &rule, &packets);   /* get packet count */
+    packetsSum+=packets;
+  }
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return packetsSum;
+}
+
+/**********************************************
+ get rule count registed to a rule number   
+**********************************************/
+int countRuleNumber(int ruleNumber)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int ruleCount;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* exec proc */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",ruleNumberStr,(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* count line read from pipe */
+  ruleCount = 0;
+  while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return ruleCount;
+}
+
+/**********************************************
+ function called by signal int              
+**********************************************/
+static void sigFunc(int signo)
+{
+  return;
+}
+
+
+/**********************************************
+get rule numbers table from ipfw rule set
+**********************************************/
+int getRuleTableFromIpfw(DB* ruleTable){
+
+  DBT hashKey;
+  DBT hashVal;
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int ruleNumber;
+  char macAddress[ADDRMAXLN];
+  char *p;
+  int ipfwmin;
+  int ipfwmax;
+  int ipfwinterval;
+  int resultFlag=FALSE;
+  
+  /* exec ipfw list and open pipe */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* get rule range from config */
+  ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
+  ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
+  ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
+  
+  /* get ipfw rule line from pipe */
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+
+    /* get ruleNumber(=leftmost number) */
+    /* 10000 count tag 123 ip from any to any MAC 11:22:33:44:55:66 any .... */
+    /* 10000 count tag 123 ip from any to any MAC any 11:22:33:44:55:66 .... */
+    if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
+
+    /* check the rule number range */
+    if(ruleNumber < ipfwmin)continue;
+    if(ruleNumber > ipfwmax)break;
+
+    /* get macAddress(=after [MAC]) in the line */
+    if((p=(char*)strstr(buf, "MAC"))==NULL) continue;
+    if( sscanf((p+3), "%s", macAddress) != 1 ) continue;
+    if( (strchr(macAddress,':')==NULL) )continue;
+      
+    /* put to the hash table */
+    resultFlag=TRUE;
+    hashVal.data = &ruleNumber;
+    hashVal.size = sizeof(int);    
+    hashKey.data = macAddress;
+    hashKey.size = strlen(macAddress)+1;
+    if(ruleTable->put(ruleTable, &hashKey, &hashVal, 0) == -1) {
+      err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+    }
+  }
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return resultFlag;
+}
+
+
+/**********************************************
+is the macAddress found in ipfw rules
+**********************************************/
+int isMacAddressFoundInIpfw(char* macAddress){
+
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int ruleNumber;
+  char macAddressInRule[ADDRMAXLN];
+  char *p;
+  int ipfwmin;
+  int ipfwmax;
+  int ipfwinterval;
+  int found=FALSE;
+  
+  /* exec ipfw list and open pipe */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* get rule range from config */
+  ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
+  ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
+  ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
+  
+  /* get ipfw rule line from pipe */
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+
+    /* get ruleNumber(=leftmost number) */
+    /* 10000 count tag 123 ip from any to any MAC 11:22:33:44:55:66 any .... */
+    /* 10000 count tag 123 ip from any to any MAC any 11:22:33:44:55:66 .... */
+    if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
+
+    /* check the rule number range */
+    if(ruleNumber < ipfwmin)continue;
+    if(ruleNumber > ipfwmax)break;
+
+    /* get macAddress(=after [MAC]) in the line */
+    if((p=(char*)strstr(buf, "MAC"))==NULL) continue;
+    if( sscanf((p+3), "%s", macAddressInRule) != 1 ) continue;
+    if( (strchr(macAddressInRule,':')==NULL) )continue;
+
+    /* compare the address with the argument */
+    /* if matched, exit loop */
+    if(strncmp(macAddress, macAddressInRule, ADDRMAXLN)==0){
+      found=TRUE;
+      break;
+    }
+  }
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return found;
+}
+
+
+/*********************************************
+ routines for debugging output
+**********************************************/
+int GetRuleNumber(char *macAddress)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>getRuleNumber(%s)",macAddress);
+  ret=getRuleNumber(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber( )",ret);
+
+  return ret;
+}
+
+int OpenClientGate(char *macAddress, char* userId, char* extraId)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>openClientGate(%s,%s,%s)",macAddress,userId,extraId);
+  ret=openClientGate(macAddress,userId,extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=openClientGate( )",ret);
+
+  return ret;
+}
+
+void CloseClientGate(int ruleNumber)
+{
+  if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
+  closeClientGate(ruleNumber);
+  if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
+}
+
+
+int GetPacketCount(int ruleNumber)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
+  ret=getPacketCount(ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
+
+  return ret;
+}
+
+int CountRuleNumber(int ruleNumber)
+{
+  int ret;
+  
+  if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
+  ret=countRuleNumber(ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
+  
+  return ret;
+}
+
+int GetRuleTableFromIpfw(DB* ruleTable){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
+  ret=getRuleTableFromIpfw(ruleTable);
+  if(debug>1) err_msg("DEBUG:(%d)<=getRuleTableFromIpfw( )", ret);
+  return ret;
+}
+
+int IsMacAddressFoundInIpfw(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isMacAddressFoundInIpfw(%s)", macAddress);
+  ret=isMacAddressFoundInIpfw(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isMacAddressFoundInIpfw( )", ret);
+  return ret;
+}
diff --git a/mdsrc/macdbcache.c b/mdsrc/macdbcache.c
new file mode 100644 (file)
index 0000000..384887c
--- /dev/null
@@ -0,0 +1,224 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module to control cache for MAC address DB
+
+  the cache holds the temporary copy of DB to speedup checking.
+  Only the allowable MAC addresses are hold.
+
+  As ip address check by database is time consuming procedure,
+  the recently checked mac addresses are cached.
+  Implemented with HashTable.
+  HashTable:
+    Key= MAC Address
+    Val= userId, extraId and cache time.
+    If MAC address is found in table and time is new, skip DB access.
+    If time is old, remove the cached item.
+
+Copyright (C) 2012 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+/* HashTable to store MacAddress->userId,extraId,Time */
+static DB* macHashDb;
+
+/* Cache Timeout(seconds) (read from conf file) */
+static int macCacheTimeout;
+
+void dumpHashTable(DB* table);
+
+/****************************************
+add item to Mac cache 
+****************************************/
+int addMacCacheItem(char* macAddress, char* userId, char* extraId) {
+
+  DBT hashKey;
+  DBT hashVal;
+  char hashValueStr[BUFFMAXLN];
+
+  /* check address format */
+  if(isNull(macAddress)) return FALSE;
+  if(!ReFormatMacAddr(macAddress)) return FALSE;
+
+  /** setup hash key **/
+  /* hash key : string of mac address  */  
+  hashKey.data = macAddress;
+  hashKey.size = strlen(macAddress) + 1;
+
+  /** setup hash value **/
+  /* hash value : string "<unixtime>SPACE<userId>SPACE<extraId>" */
+  snprintf(hashValueStr,BUFFMAXLN,"%d %s %s",time(NULL),userId,extraId);
+  hashVal.data = hashValueStr;
+  hashVal.size = strlen(hashValueStr) + 1;    
+  if(macHashDb->put(macHashDb, &hashKey, &hashVal, 0) == -1) {
+    err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/****************************************
+query userid and extraid for mac address
+if the entry time is old, return false
+****************************************/
+int queryMacFromMacCache(char* macAddress, char* userId, char* extraId){
+
+  DBT hashKey;
+  DBT hashVal;
+  time_t entryTime;
+  int ret;
+
+  /* set default */
+  entryTime=0;
+  userId[0]=extraId[0]='\0';
+
+  /* if null or illegal form, return */
+  if(isNull(macAddress)) return FALSE;
+  if(!ReFormatMacAddr(macAddress)) return FALSE;
+
+  /***** get hashed item matched to the indicated mac */
+  hashKey.data = macAddress;
+  hashKey.size = strlen(macAddress) + 1;
+  memset(&hashVal, 0, sizeof(DBT));
+  ret=macHashDb->get(macHashDb, &hashKey, &hashVal, 0);
+
+  /* get is failed, return false */
+  if(ret!=0) return FALSE;
+
+  /* get is successed */
+  /* pick up the hash values */
+  ret=sscanf(hashVal.data,"%d %s %s",&entryTime,userId,extraId);
+
+  /* entryTime and userId should be obtained, but extraId is not */
+  if(ret<=1) return FALSE;
+
+  /* if entry time is older than timeout, return false */
+  if( entryTime + macCacheTimeout < time(NULL) ) return FALSE;
+
+  return TRUE;
+}
+
+/****************************************
+initialize Mac Cache
+****************************************/
+void initMacCache(void) {
+
+  /* prepare hash table */
+  if((macHashDb = dbopen(NULL, O_CREAT | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
+    err_msg("ERR at %s#%d: fail to open mac hash table",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* set counter and timeout parameter */
+  if(isNull(GetConfValue("MacCacheTimeout"))){
+    err_msg("ERR at %s#%d: cannot get MacCacheTimeout from conf file",__FILE__,__LINE__);
+    macCacheTimeout=0;
+  }else{
+    macCacheTimeout=atoi(GetConfValue("MacCacheTimeout"));
+  }  
+}
+
+/****************************************
+Memory free for Mac Cache
+****************************************/
+void freeMacCache(void) {
+
+  macHashDb->close(macHashDb);
+}
+
+/****************************************
+delete item from Mac cache matched to the mac address
+****************************************/
+int delMacCacheItem(char* macAddress) {
+
+  DBT hashKey;
+  
+  /* if null or illegal form, return */
+  if(isNull(macAddress)) return FALSE;
+  if(!ReFormatMacAddr(macAddress)) return FALSE;
+
+  /* delete the item from Hash Table */
+  hashKey.data = macAddress;
+  hashKey.size = strlen(macAddress) + 1;
+  macHashDb->del(macHashDb, &hashKey, 0);
+
+  return TRUE;
+}
+
+/************************************
+debug routine for hash table
+************************************/
+void dumpHashTable(DB* table){
+  DBT hashKey;
+  DBT hashVal;
+  int ret;
+
+  memset(&hashKey, 0, sizeof(DBT));
+  memset(&hashVal, 0, sizeof(DBT));
+  ret=table->seq(table, &hashKey, &hashVal, R_FIRST);
+  while(ret==0){
+
+    err_msg("%s:%s", (char*)hashKey.data, (char*)hashVal.data);
+
+    /* get next entry */
+    ret=table->seq(table, &hashKey, &hashVal, R_NEXT);
+  }
+}
+
+/****************************************************
+ routines for debugging putput
+ ***************************************************/
+
+void InitMacCache(void) {
+  if(debug>1) err_msg("DEBUG:=>initmacCache( )");
+  initMacCache();
+  if(debug>1) err_msg("DEBUG:<=initMacCache( )");
+}
+
+void FreeMacCache(void) {
+  if(debug>1) err_msg("DEBUG:=>freemacCache()");
+  freeMacCache();
+  if(debug>1) err_msg("DEBUG:<=freeMacCache()");
+}
+
+int AddMacCacheItem(char* macAddress, char* userId, char* extraId) {
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>addMacCacheItem(%s,%s,%s)", macAddress,userId,extraId);
+  ret = addMacCacheItem(macAddress,userId,extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=addMacCacheItem( )",ret);
+  return ret;
+}
+
+int QueryMacFromMacCache(char* macAddress, char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>queryMacFromMacCache(%s)", macAddress);
+  ret = queryMacFromMacCache(macAddress, userId, extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=queryMacFromMacCache(,%s,%s)",ret,userId,extraId);
+  return ret;
+}
+
+int DelMacCacheItem(char* macAddress) {
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delMacCacheItem(%s)", macAddress);
+  ret = delMacCacheItem(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=delMacCacheItem( )",ret);
+  return ret;
+}
+
diff --git a/mdsrc/managementdb.c b/mdsrc/managementdb.c
new file mode 100644 (file)
index 0000000..16545c6
--- /dev/null
@@ -0,0 +1,210 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module to control management database
+
+ list of mac addresses
+ list of usage log
+ implemented with MySql 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+#include <mysql.h>
+
+
+MYSQL mysql;
+
+/******************************************
+initialize management db
+******************************************/
+int initMngDb(void){
+
+  /* set parameters */
+  char *server = GetConfValue("MySqlDb/Server");
+  char *user =  GetConfValue("MySqlDb/User");
+  char *password = GetConfValue("MySqlDb/Password");
+  char *database = GetConfValue("MySqlDb/Database");
+  my_bool reconnect;
+
+/* initialize mysql */
+  mysql_library_init(-1,NULL,NULL);
+  if(mysql_init(&mysql)==NULL){
+     err_msg("ERR at %s#%d: mysql init: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     terminateProg(0);
+  }
+
+  /* Connect to database */
+  if (!mysql_real_connect(&mysql, server,
+                          user, password, database, 0, NULL, 0)) {
+    err_msg("ERR at %s#%d: mysql connect: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+    terminateProg(0);
+  }
+
+  /* set auto-reconnect true */
+  reconnect = TRUE;
+  mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);  
+
+  return TRUE;
+}
+
+/******************************************
+close management db
+******************************************/
+void closeMngDb(void){
+  mysql_close(&mysql);
+  mysql_library_end();
+}
+
+/******************************************
+query data from management db
+input=macAddress,output=others
+******************************************/
+int queryMacFromMngDb(char* macAddress, char* userId, char* extraId){
+  MYSQL_RES *res;
+  MYSQL_ROW row;
+  int found=FALSE;
+  char queryStr[BUFFMAXLN];
+
+  /* set default values userId="?", extraId=""  */
+  userId[0]='?'; userId[1]='\0'; extraId[0]='\0';
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "select userId,extraId from macaddrs "
+          "where macAddress='%s' and status='A' and limitDate>now()",
+          macAddress);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  res = mysql_use_result(&mysql);
+  
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if not found, return false */
+  if(row==NULL)  found=FALSE;
+
+  /* if found */
+  else {
+    strcpy(userId, row[0]);
+    strcpy(extraId,row[1]);
+    found=TRUE;
+  }
+
+  mysql_free_result(res);
+  return found;
+}
+
+/******************************************
+put open log to management db 
+******************************************/
+int putOpenToMngDb(char* macAddress, char* ipAddress){
+
+  char queryStr[BUFFMAXLN];
+  struct utsname uts;
+
+  /* get domain name */
+  uname(&uts);
+
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "insert into sessionmd "
+          "(macAddress, ipAddress, gatewayName, openTime, closeTime) "
+          "values ('%s','%s','%s', now(), 0)",
+          macAddress, ipAddress, uts.nodename);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  return TRUE;
+}
+
+/******************************************
+put close log to management db
+******************************************/
+int putCloseToMngDb(char* macAddress){
+
+  char queryStr[BUFFMAXLN];
+
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "update sessionmd set closeTime=now() "
+          "where macAddress='%s' and closeTime=0", macAddress);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  return TRUE;
+
+}
+
+/********************************************
+ routines for debugging output
+********************************************/
+int QueryMacFromMngDb(char* macAddress, char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>queryMacFromMngDb(%s)", macAddress);
+  ret = queryMacFromMngDb(macAddress, userId, extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=queryMacFromMngDb(,%s,%s)",ret,userId,extraId);
+  return ret;
+}
+int InitMngDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initMngDb()");
+  ret=initMngDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=closeMngDb()",ret);
+  return ret;
+}
+void CloseMngDb(void){
+  if(debug>1) err_msg("DEBUG:=>closeMngDb()");
+  closeMngDb();
+  if(debug>1) err_msg("DEBUG:<=closeMngDb()");
+}
+
+int PutCloseToMngDb(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putCloseToMngDb(%s)", macAddress);
+  ret = putCloseToMngDb(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=putCloseToMngDb()",ret);
+  return ret;
+}
+int PutOpenToMngDb(char* macAddress, char* ipAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putOpenToMngDb(%s,%s)", macAddress, ipAddress);
+  ret = putOpenToMngDb(macAddress, ipAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=putOpenToMngDb()",ret);
+  return ret;
+}
+
diff --git a/mdsrc/opengatemd.c b/mdsrc/opengatemd.c
new file mode 100644 (file)
index 0000000..f1ef896
--- /dev/null
@@ -0,0 +1,507 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+daemon main module 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+/*************************************
+This program uses following data structures 
+to maintain the state of each terminal.
+
+   1. Packet Check Cache
+       To speed up the packet check process, the address checked once 
+         is ignored for a while.
+       The cache (key: MAC address) is used to decide 
+         the necessity of checking.
+       The cache is maintained the information of arrived packets 
+         by using hash-table and queue in the memory of local machine.
+   2. Session Table
+       The table (key: MAC address) maintains temporal information 
+         of terminals allowing the use of network now. 
+       The data are stored in the DB of local machine.
+   3. MAC address Table
+       The table (key: MAC address) maintains MAC addresses of terminals
+         and the owners' information.
+       The data are stored in the DB of a central machine
+         and accessed via network.
+   4. Cache of MAC address Table
+       As the network DB access is time-consuming, the access cache 
+         (key: MAC address) is maintained in the memory of local machine.
+
+MAC address is used as main key for the user terminal.
+IP address is kept only for information (firstly detected address only)
+*************************************/
+
+#include       "opengatemd.h"
+
+void sigHupHandler(int sig);
+void sigIoHandler(int sig);
+void sigTermHandler(int sig);
+
+int sigHupArrived=FALSE;
+int sigIoArrived=FALSE;
+
+/*********************/
+/*  main routine     */
+/*********************/
+int  main(int argc, char **argv)
+{
+  char ipAddress[ADDRMAXLN];  /* packet source ip address */
+  char macAddress[ADDRMAXLN]; /* packet source mac address */
+  unsigned char macAddressRaw[ADDRMAXLN];/* mac addr in raw form */
+  unsigned char ipAddressRaw[ADDRMAXLN];/* ip addr in raw form */
+  /* above is network raw binary, MAC(6bytes) and IP(4or16Bytes) */
+  int ipAddrLen;               /* ip address byte length 4 or 16 */         
+  char userId[USERMAXLN];     /* user id related to the mac address */
+  char extraId[USERMAXLN];    /* optional id for the user */
+  int macFound;               /* flag: mac address is resistered in db */
+  int sessionFound;           /* flag: session for the address exists */
+  int consoleMode=FALSE;      /* flag: start with console mode option */
+  int endServiceMode=FALSE;   /* flag: start with end service option */
+  int reloadServiceMode=FALSE;/* flag: start with reload option */ 
+  int stopServiceMode=FALSE;  /* flag: start with stop service option */ 
+  int showVersionMode=FALSE;  /* flag: show version */
+  int helpMode=FALSE;         /* flag: start with help mode */
+  int ttl;                    /* packet ttl(time to live) or hlim(hop limit) */
+  int i;                      /* for loop control */
+  int uselessCheckTime=0;     /* the last time for useless check */
+  int checkInterval;          /* useless session check interval */
+  int isNatOrRouter=FALSE;    /* the packet is sent from nat/router */
+  char macAddrInUdp[ADDRMAXLN]; /* mac address sent from udp port */
+  int ret;
+  char clientIpAddress[ADDRMAXLN]; /* udp client ip address */
+
+  /* analyze arguments */
+  for(i=1; i<argc; i++){
+    if(*argv[i]=='-' && *(argv[i]+1)=='c') consoleMode=TRUE;
+    else if(*argv[i]=='-' && *(argv[i]+1)=='e') endServiceMode=TRUE;
+    else if(*argv[i]=='-' && *(argv[i]+1)=='r') reloadServiceMode=TRUE;
+    else if(*argv[i]=='-' && *(argv[i]+1)=='s') stopServiceMode=TRUE;
+    else if(*argv[i]=='-' && *(argv[i]+1)=='v') showVersionMode=TRUE;
+    else helpMode=TRUE;
+  }
+
+  /* if unknown args, show help and exit */
+  if(helpMode){
+    ShowHelp(argv[0]);
+    terminateProg(0);
+  }
+
+  /* if '-v' option, show makedir and exit */  
+  if(showVersionMode){
+    printf("makedir: %s\n", MAKEDIR);
+    terminateProg(0);
+  }
+
+  /* drop root privilege */
+  seteuid(getuid());
+
+  /* prepare config file */
+  if(OpenConfFile()==-1) terminateProg(0);
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(GetConfValue("MacCheckDaemon"), LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize config */
+  InitConf();
+
+  /* if reloadServiceMode, send HUP to resident daemon */
+  if(reloadServiceMode) ReloadDaemon();
+
+  /* if stopServiceMode, stop resident deamon and this process */
+  if(stopServiceMode){
+    KillDaemon();
+    terminateProg(0);
+  }
+
+  /* if endServiceMode, stop deamon and close sessions after setup */
+  if(endServiceMode) KillDaemon();
+
+  /* get runmode from command argument and set as daemon */
+  if(consoleMode)  errToSyslog(FALSE);    /* console mode (no syslog) */
+  else   Daemonize();                     /* daemon mode (fork&exit) */
+
+  /* set lock file to prevent overlapped execution */
+  if(!LockDaemonLockFile()){
+    terminateProg(0);
+  }
+
+  /* set signal functions */
+  signal(SIGHUP, sigHupHandler);
+  signal(SIGTERM, sigTermHandler);
+
+  /* initializing */
+  InitPcap();
+  InitCache();
+  InitMacCache();
+  InitWorkDb();
+  if(!InitMngDb()) terminateProg(0);
+  InitTtlCheck();
+  PrepareUdpPort(sigIoHandler); /* UDP port runs as asynchronous */
+
+  /* if endService is indicated, close all sessions, and exit */
+  if(endServiceMode){
+    DelAllSessions();
+    terminateProg(0);
+  }
+  
+  /* set check interval and remove residue sessions that are useless */
+  checkInterval=atoi(GetConfValue("UselessCheckInterval"));
+  uselessCheckTime=time(NULL);
+  DelUselessSessions();
+
+  /*** enter packet inspection loop ***/
+  while(1){
+
+    /* if sig-hup flag is on, reload this program */
+    if(sigHupArrived)execlp(argv[0], argv[0], NULL);
+
+    /* if mac addresses are received from management proc by udp, 
+       remove the addresses from caches */
+    if(sigIoArrived){
+      sigIoArrived=FALSE;
+      while(GetDataFromUdpPort(macAddrInUdp, ADDRMAXLN, clientIpAddress)>0){
+       if(IsUdpClientTrusted(clientIpAddress)){
+         DelCacheItem(macAddrInUdp);
+         DelMacCacheItem(macAddrInUdp);
+       }
+      }
+    }      
+
+    /* get one packet from pcap */
+    ret=GetNextPacketFromPcap(macAddressRaw, ipAddressRaw, &ipAddrLen, &ttl);
+
+    /* if no packet */
+    if(ret==0){
+
+      /* check useless sessions at some interval */
+      if( time(NULL) - uselessCheckTime > checkInterval ){
+       uselessCheckTime = time(NULL);
+       DelUselessSessions();
+      }
+
+      /* and return to loop top */
+      continue;
+    }
+
+    /* ignore not-ip packet */
+    if(ret==-1) continue;
+
+    /* ignore local packet */
+    if(ttl<=1) continue;
+   
+    /* ignore the packet checked recently */
+    if( IsRecentlyCheckedAddress(macAddressRaw) ) continue;
+
+    /**** only cache timeout packets proceeds to below ****/
+
+    /* convert address from network-raw form to presentation form */
+    ConvertMacFromRawToDisplay(macAddressRaw,macAddress);
+    if(!ConvertIpFromRawToDisplay(ipAddressRaw,ipAddrLen,ipAddress)) continue;
+
+    /* check nat/router and save info to db */
+    isNatOrRouter=IsSentViaNatOrRouter(ipAddress, macAddress, ttl);
+    if(isNatOrRouter) PutLogAtNatOrRouter(isNatOrRouter,ipAddress,macAddress,ttl);
+    PutMacInfoToWorkDb(macAddress, ttl, isNatOrRouter);
+
+    /*** get the states of the terminal in data structures ***/
+    /* search the address in session table */
+    sessionFound = IsMatchedSessionFound(macAddress);
+
+    /* search the address in MAC DB cache */ 
+    macFound = QueryMacFromMacCache(macAddress, userId, extraId);
+
+    /* if not found in MAC DB cache, search DB and add it to cache */
+    if(!macFound){
+      macFound = QueryMacFromMngDb(macAddress, userId, extraId);
+      if(macFound) AddMacCacheItem(macAddress, userId, extraId);
+    }
+
+    /*** depending the states, add/del/renew the session ***/
+    /* if valid mac and no session, start session */
+    if(macFound && !sessionFound){
+       AddSession(macAddress, ipAddress, userId, extraId);
+    }
+
+    /* if no mac and started session, stop session */
+    if(!macFound && sessionFound){
+      DelSession(macAddress);
+    }
+
+    /* if valid mac and started session, renew check time */
+    if(macFound && sessionFound){
+
+      /* in normal case, ipfw rule exists. */
+      if(IsMacAddressFoundInIpfw(macAddress)) RenewSession(macAddress);
+
+      /* when no ipfw rule exists, reset the session */
+      else{
+       DelSession(macAddress);
+       AddSession(macAddress, ipAddress, userId, extraId);     
+      }
+    }
+
+    /*  check useless sessions at some interval */
+    if( time(NULL) - uselessCheckTime > checkInterval ){
+      uselessCheckTime = time(NULL);
+      DelUselessSessions();
+    }
+  }
+
+  /* clear data structures (can't reach here, but coded for debugging) */
+  FreeCache();
+  FreeMacCache();
+  ClosePcap();
+  CloseConfFile();
+  CloseMngDb();
+
+  terminateProg(0);
+  return 0;
+}
+
+/********************************
+ open and lock proc lock file 
+ to prevent overlapped daemon exec
+********************************/
+int lockDaemonLockFile(void){
+  
+  static int lockFd;
+  char str[WORDMAXLN];
+  /* open process lock file */
+  lockFd = open(GetConfValue("DaemonLockFile"), O_RDWR|O_CREAT, 0644);
+  
+  /* if cannot open or cannot lock, return false */
+  if(lockFd<0){
+    err_msg("ERR at %s#%d: cannot open daemon lock file:%s",__FILE__,__LINE__,
+           lockFd);
+    return FALSE;
+  }
+  if(lockf(lockFd, F_TLOCK, 0)<0) return FALSE;
+
+  /* record pid */
+  snprintf(str, WORDMAXLN, "%d", getpid());
+  write(lockFd, str, strlen(str)+1);
+
+  /* normally locked */
+  return TRUE;
+}
+
+
+/******************************
+daemonize the process
+******************************/
+void daemonize(void){
+
+  int pid;
+  int i;
+
+  /* detach from parent */
+  pid = fork();
+  if(pid < 0){
+   err_msg("ERR at %s#%d: cannot fork",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* parent process exits */
+  if(pid > 0) exit(0);
+
+  /* child process runs from here */
+  /* set new prosess group */
+  setsid();
+
+  /* close all file descriptors */
+  for(i=getdtablesize(); i>=0; i--) close(i);
+
+  /* connect stdin/out/err to null */
+  i=open("/dev/null", O_RDWR); dup(i); dup(i);
+
+  /* set newly created file permission */
+  /* umask(033);   */
+
+  if(debug>0) err_msg("INFO: Deamon started");
+}
+
+/****************************************
+show help message
+****************************************/
+void showHelp(char* procName){
+   printf("\n");
+   printf("firewall control by mac address\n");
+   printf(" see detail in Opengate Homepage\n");
+   printf("\n");
+   printf(" format: %s [arg] \n", procName);
+   printf(" arg : -c = run on console (default is daemon)\n");
+   printf("     : -e = close all sessions and end service\n");
+   printf("     : -r = reload deamon\n");
+   printf("     : -s = stop deamon (not close sessions)\n");
+   printf("     : -v = show make dir to check version\n");
+ }
+
+/*********************************
+signal handler for SIGIO
+*********************************/
+void sigIoHandler(int sig){
+
+  sigIoArrived=TRUE;
+}
+
+/*********************************
+signal handler for SIGHUP
+*********************************/
+void sigHupHandler(int sig){
+
+  if(debug>0)err_msg("INFO: Deamon receives HUP signal");
+  sigHupArrived=TRUE;
+}
+
+/*********************************
+signal handler for SIGTERM
+*********************************/
+void sigTermHandler(int sig){
+
+  if(debug>0)err_msg("INFO: Deamon receives TERM signal");
+  terminateProg(0);
+}
+
+/*********************************
+kill daemon process
+*********************************/
+void killDaemon(void){
+  FILE* file=NULL;
+  struct stat st;
+  int pid=0;
+  char* lockFileMd;
+
+  /* get lock file name */
+  lockFileMd=GetConfValue("DaemonLockFile");
+
+  /* if lock file is not exists, skip */
+  if(stat(lockFileMd, &st)!=0){
+    ;
+  }
+
+  /* read pid from the file */
+  else if((file=fopen(lockFileMd, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot open proc lock file:%s",__FILE__,__LINE__
+           ,lockFileMd);
+  }
+
+  else if(fscanf(file, "%d", &pid)==0){
+    err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
+           ,lockFileMd);
+  }
+  if(file!=NULL) fclose(file);
+
+  /* send kill signal to the pid process */
+  if(pid!=0){
+    seteuid(0);   /* get root privilege */
+    kill(pid, SIGKILL);
+    seteuid(getuid());   /* drop root privilege */
+  }
+
+  /* remove the lockfile */
+  remove(lockFileMd);
+}
+
+/*********************************
+reload daemon process
+*********************************/
+void reloadDaemon(void){
+  FILE* file=NULL;
+  struct stat st;
+  int pid=0;
+  char* lockFileMd;
+
+  /* get lock file name */
+  lockFileMd=GetConfValue("DaemonLockFile");
+
+  /* if lock file is not exists, skip */
+  if(stat(lockFileMd, &st)!=0){
+    ;
+  }
+
+  /* read pid from the file */
+  else if((file=fopen(lockFileMd, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot open proc lock file:%s",__FILE__,__LINE__
+           ,lockFileMd);
+  }
+
+  else if(fscanf(file, "%d", &pid)==0){
+    err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
+           ,lockFileMd);
+  }
+  if(file!=NULL)fclose(file);
+
+  /* send hup signal to the pid process */
+  if(pid!=0){
+    seteuid(0);   /* get root privilege */
+    kill(pid, SIGHUP);
+    seteuid(getuid());   /* drop root privilege */
+  }
+}
+
+/*************************************
+put out end message and exit 
+*************************************/
+void terminateProg(int ret){
+
+  /* close opengatemd.db */
+  FinalizeWorkDb();
+
+  if(debug>0) err_msg("INFO: Terminated");
+  exit(ret);
+}
+
+
+/************************************
+ routines for debugging output
+ ***********************************/
+int LockDaemonLockFile(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>lockDaemonLockFile( )");
+  ret = lockDaemonLockFile();
+  if(debug>1) err_msg("DEBUG:(%d)<=lockDaemonLockFile( )",ret);
+  return ret;
+}
+
+void Daemonize(void){
+  if(debug>1) err_msg("DEBUG:=>daemonize( )");
+  daemonize();
+  if(debug>1) err_msg("DEBUG:<=daemonize( )");
+}
+
+void ShowHelp(char* procName){
+  if(debug>1) err_msg("DEBUG:=>showHelp(%s)", procName);
+  showHelp(procName);
+  if(debug>1) err_msg("DEBUG:<=showhelp( )");
+}
+void KillDaemon(void){
+  if(debug>1) err_msg("DEBUG:=>killDaemon( )");
+  killDaemon();
+  if(debug>1) err_msg("DEBUG:<=killDaemon( )");
+}
+void ReloadDaemon(void){
+  if(debug>1) err_msg("DEBUG:=>reloadDaemon( )");
+  reloadDaemon();
+  if(debug>1) err_msg("DEBUG:<=reloadDaemon( )");
+}
diff --git a/mdsrc/opengatemd.h b/mdsrc/opengatemd.h
new file mode 100644 (file)
index 0000000..fe38713
--- /dev/null
@@ -0,0 +1,229 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+daemon header file
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <poll.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/signal.h>
+#include <regex.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <limits.h>
+#include <db.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <sys/utsname.h>
+#include <netdb.h>
+
+typedef        void    Sigfunc(int);   /* for signal handlers */
+
+
+/***************** constants ***********************/
+
+/* Configuration file for opengate */ 
+#define CONFIGFILE "/etc/opengate/opengatemd.conf"
+
+#define ADDRMAXLN 128      /* maximum address string length */
+#define USERMAXLN 128      /* maximum userid string length */
+#define BUFFMAXLN 1024      /* maximum buffer string length */
+#define WORDMAXLN 64       /* maximum word length */
+#define FILTERMAXLN 128   /* pcap filter max length */
+
+#define IPV6ADDRLN 16
+#define IPV4ADDRLN 4
+#define MACADDRLN 6
+
+#define TRUE 1
+#define FALSE 0
+#define DENY   0
+#define ACCEPT 1
+#define ERROR -1
+
+#define NONAT 0
+#define NAT 1
+#define ROUTER 2
+
+#define AVOID_OVERLAP 0
+#define ALLOW_OVERLAP 1
+
+extern int debug;
+
+/**********prototypes***************************************/
+
+/* opengatemd.c */
+void ShowHelp(char* procName);
+int LockDaemonLockFile(void);
+void Daemonize(void);
+void KillDaemon(void);
+void ReloadDaemon(void);
+void terminateProg(int ret);
+
+/* ipfw.c */
+int OpenClientGate(char *macAddress, char* userId, char* extraId);
+int GetRuleNumber(char *macAddress);
+void CloseClientGate(int ruleMumber);
+int GetPacketCount(int ruleNumber);
+int CountRuleNumber(int ruleNumber);
+int GetRuleTableFromIpfw(DB* ruleTable);
+int IsMacAddressFoundInIpfw(char* macAddress);
+
+/* util.c */
+int Lock(int fd);
+int Unlock(int fd);
+FILE *Popenl(int rootPriv, const char *type, const char *path, ...);
+int Systeml(int roorPriv, const char *path, ...);
+int Pclose(FILE *stream);
+int isNull(const char *pStr);
+int Open(const char *pathname, int oflag, mode_t mode);
+int Close(int fd);
+pid_t Fork(void);
+int Pipe(int *fds);
+Sigfunc * Signal(int signo, Sigfunc *func);
+void * Malloc(size_t size);
+
+/* error.c */
+void err_ret(const char *fmt, ...);
+void err_sys(const char *fmt, ...);
+void err_dump(const char *fmt, ...);
+void err_msg(const char *fmt, ...);
+void err_quit(const char *fmt, ...);
+void errToSyslog(int i);
+
+/* getparam.c */
+int OpenConfFile(void);
+void CloseConfFile(void);
+void SetupConfExtra(char *userId, char *extraId);
+char *GetConfValue(char *name);
+char *GetConfValueExtra(char *name);
+char *GetConfAuthServer(char *name);
+int SelectNextAuthServer(void);
+void InitConf(void);
+int RegExMatch(const char *inStr, const char *regEx);
+void ResetAuthServerPointer(void);
+char *GetFirstConfValue(char* name);
+char *GetNextConfValue(void);
+
+/* pcap.c */
+int InitPcap(void);
+int GetNextPacketFromPcap(unsigned char* macAddressRaw, unsigned char* ipAddressRaw, int* pIpAddrLen, int* pTtl);
+void ClosePcap(void);
+int GetMyMacAddress(char* macAddress);
+int ConvertIpFromRawToDisplay(unsigned char* ipAddressRaw, int ipAddrLen, char* ipAddress);
+void ConvertMacFromRawToDisplay(unsigned char* macAddressRaw, char* macAddress);
+
+/* packetcache.c */
+void InitCache(void);
+int IsRecentlyCheckedAddress(unsigned char* macAddressRaw);
+void FreeCache(void);
+int DelCacheItem(char* macAddress);
+int DelOldestCacheItem(void);
+int ReFormatMacAddr(char* macAddr);
+
+/* managementdb.c */
+int InitMngDb(void);
+int QueryMacFromMngDb(char* macAddress, char* userid, char* extraid);
+void CloseMngDb(void);
+int PutCloseToMngDb(char* macAddress);
+int PutOpenToMngDb(char* macAddress, char* ipAddress);
+
+/* workdb.c */
+int SetupSqliteBusyTimeoutValue(void);
+int InitWorkDb(void);
+int FinalizeWorkDb(void);
+int InsertSessionToWorkDb(char* macAddress, char* userId, char* extraId, 
+                       char* ipAddress, int ruleNumber);
+int DelSessionFromWorkDb(char* macAddress);
+int GetSessionFromWorkDb(char* macAddress, char* userId, char* extraId, 
+                        int* openTime, int* checkTime, char *ipAddress,
+                          int* ruleNumber);
+int UpdateCheckTimeInWorkDb(char* macAddress);
+int DelUselessSessionsInWorkDb(int delayed);
+int GetSessionTableFromWorkDb(DB* sessionTable);
+int PutMacInfoToWorkDb(char* macAddress, int ttl, int isNat);
+int GetMacInfoFromWorkDb(char* macAddress, char* detectTimeStr, int* pTtl);
+int IsActiveRuleInWorkDb(int ruleNumber);
+
+/* session.c */
+int AddSession(char* macAddress, char* ipAddress, char* userId, char* extraId);
+void DelSession(char* macAddress);
+void RenewSession(char* macAddress);
+void DelUselessSessions(void);
+void DelAllSessions(void);
+int CloseSession(void* pParam, int argc, char *argv[], char* colName[]);
+int IsMatchedSessionFound(char* macAddress);
+void CloseUnmatchSessions(void);
+void WriteOpenToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress);
+void WriteCloseToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int openTime);
+void WriteSessionInfoToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int ruleNumber);
+void RemoveSessionUnmatchedToIpfwRule(DB* ruleTable, DB* sessionTable);
+void RemoveIpfwRuleUnmatchedToSession(DB* ruleTable, DB* sessionTable);
+int IsProcessFoundForTheRule(int ruleNumber);
+
+/* ttlcheck.c */
+int InitTtlCheck(void);
+int IsSentViaNatOrRouter(char* ipAddress, char* macAddress, int ttl);
+void PutLogAtNatOrRouter(int isNatOrRouter, char* ipAddress, char* macAddress, int ttl);
+
+/* udpserv.c */
+int PrepareUdpPort(void (*handler)(int));
+int GetDataFromUdpPort(char* buf, int bufLen, char* clientIpAddress);
+int IsUdpClientTrusted(char* clientIpAddress);
+int IsMyIpAddress(char* ipAddress);
+int EnableAsyncIo(int sockfd, void (*handler)(int));
+
+/* macdbcache.c */
+void InitMacCache(void);
+void FreeMacCache(void);
+int QueryMacFromMacCache(char* macAddress, char* userId, char* extraId);
+int DelMacCacheItem(char* macAddress);
+int AddMacCacheItem(char* macAddress, char* userId, char* extraId);
+
diff --git a/mdsrc/packetcache.c b/mdsrc/packetcache.c
new file mode 100644 (file)
index 0000000..00ea80e
--- /dev/null
@@ -0,0 +1,529 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module to control packet check cache
+
+  to skip checking every packets.
+  All detected mac addresses are cached.
+
+  As checking packet is time consuming procedure,
+  the recently checked addresses are cached and skiped.
+  Implemented with HashTable and Queue.
+  HashTable:
+    Key= MAC Addresses
+    Val= checked time
+    If address is included in table and time is new, skip checking.
+  Queue:
+    Address odrered by checked time.
+    If an old item is found in table, elder items are removed from table.
+    The queue controls the remove sequence.
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+#define CACHESIZE 1000000 /* mac&ip cache size */
+
+int InitQueueForCache(void);
+int EnQueueForCache(unsigned char* addrRaw, int addrLen);
+int DeQueueForCache(unsigned char* addrRaw, int* pAddrLen);
+int ListQueueForCache(void);
+void FreeQueueForCache(void);
+
+/* Queue to store MacAddress in time order */
+struct queueNode{
+  int addrLen;
+  unsigned char addrRaw[MACADDRLN];
+  struct queueNode *next;
+};
+static struct queueNode* queueTail=NULL;
+static struct queueNode* queueHead=NULL;
+
+/* HashTable key=MacAddress and value=DetectTime */
+static DB* hashDb;
+
+/* Cache Timeout(seconds) : packet checking interval */
+static int cacheTimeout;
+
+/* number of items in the cache */
+static int cacheItemCount=0;
+
+/**********************************
+This cache is made from HashTable and Queue.
+HashTable for quick access, and Queue for ordering.
+Same data are stored in the two data structures.
+If you add/delete items in cache, treat both structures.
+Don't add/delete items from one structure only. 
+***********************************/
+
+/****************************************
+Is the macAddress checked recently or not
+ input=macAddress return TRUE if checked recently
+****************************************/
+int isRecentlyCheckedAddress(unsigned char* macAddressRaw){
+
+  int timeNow;
+  unsigned char storedAddrRaw[ADDRMAXLN];
+  int storedAddrLen;
+  int ret;
+  int* pTime;
+  DBT hashKey;
+  DBT hashVal;
+
+  /* get present time */
+  timeNow=time(NULL);
+
+  /***** get item matched to the mac from hash table */
+  hashKey.data = macAddressRaw;
+  hashKey.size = MACADDRLN;
+  memset(&hashVal, 0, sizeof(DBT));
+  ret=hashDb->get(hashDb, &hashKey, &hashVal, 0);
+
+  /* getting from hash is successed */
+  if(ret==0){
+
+    /* pick up the pointer to the value */
+    pTime=(int*)(hashVal.data);
+
+    /* if data is null, return NO */
+    if(pTime==NULL) return FALSE;
+
+    /* if ignoring addresses(exceptional setting), return YES */
+    if(*pTime==0) return TRUE;
+
+    /* if recently checked data, return YES */
+    if( (timeNow-*pTime) < cacheTimeout ) return TRUE;
+
+    /***** if timeover, elder items are removed from queue and hashTable */
+    /* dequeue data from queue head and inspect the address */
+    /* until present address is found. */
+    while(DeQueueForCache(storedAddrRaw, &storedAddrLen)){
+      hashKey.data=storedAddrRaw;
+      hashKey.size = storedAddrLen;
+      hashDb->del(hashDb, &hashKey, 0);
+      if(memcmp(macAddressRaw,storedAddrRaw,storedAddrLen)==0)break;
+    }
+
+    /* insert last item after renewing the time */
+    EnQueueForCache(storedAddrRaw, storedAddrLen);
+    hashVal.data = &timeNow;
+    hashVal.size = sizeof(int);    
+    if(hashDb->put(hashDb, &hashKey, &hashVal, 0) == -1) {
+      err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+
+    /* and return NO */
+    return FALSE;
+  }
+
+  /* if getting from hash is failed, insert address and return NO */
+  if(ret==1){
+
+    /*************** begin adding item to Cache ***/
+    /* insert to hash table */
+    hashVal.data = &timeNow;
+    hashVal.size = sizeof(int);    
+    if(hashDb->put(hashDb, &hashKey, &hashVal, 0) == -1) {
+      err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+    /* insert to queue */
+    EnQueueForCache(macAddressRaw, MACADDRLN);
+    /*************** end adding item to Cache ***/
+
+    /* if cache size is over, remove oldest one */
+    if(cacheItemCount>CACHESIZE) DelOldestCacheItem();
+    return FALSE;
+  }
+
+  /* else error exit */
+  err_msg("ERR at %s#%d: fail to get hash table item",__FILE__,__LINE__);
+  return FALSE;
+}
+
+/****************************************
+initialize packet check Cache
+ The Cache is formed with in HashTable and Queue
+ HashTable=to search an item quickly
+ Queue    =to list items in FIFO order
+****************************************/
+void initCache(void) {
+
+  /* prepare hash table */
+  if((hashDb = dbopen(NULL, O_CREAT | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
+    err_msg("ERR at %s#%d: fail to open hash table",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* prepare queue */
+  InitQueueForCache();
+
+  /* set timeout parameter */
+  cacheTimeout=atoi(GetConfValue("CacheTimeout"));
+}
+
+/****************************************
+memory free for packet check Cache
+****************************************/
+void freeCache(void) {
+
+  hashDb->close(hashDb);
+  FreeQueueForCache();
+}
+
+
+/****************************************
+delete item from packet check cache matched to the mac address
+****************************************/
+int delCacheItem(char* macAddress) {
+  int found=FALSE;
+  DBT hashKey;
+  unsigned char macAddressRaw[MACADDRLN];
+  unsigned char* pRawMac;
+  struct queueNode *temp;
+  struct queueNode *prev;
+
+  /*** set the raw values */
+  /* if mac is null, return fail */
+  if(isNull(macAddress)) return FALSE;
+
+  /* convert mac to raw form */
+  if((pRawMac=(unsigned char*)ether_aton(macAddress)) != NULL){
+    memcpy(macAddressRaw, pRawMac, MACADDRLN);
+  }else return FALSE;
+
+  /*** scan queue to find matched address */
+  /* set search point to the head of mac-ip cache */
+  if(queueHead==NULL) return FALSE;
+  prev=queueHead;
+  temp=queueHead->next;
+
+  /* scan from queue head to tail */
+  while(temp->next!=NULL){
+
+    /* compare indicated value and queue value */
+    if(memcmp(macAddressRaw, (temp->addrRaw), MACADDRLN)==0){
+
+      /* set found flag */
+      found=TRUE;
+
+      /* delete the item from Hash Table */
+      hashKey.data = temp->addrRaw;
+      hashKey.size = temp->addrLen;
+      hashDb->del(hashDb, &hashKey, 0);
+
+      /* delete the item from Queue */
+      prev->next=temp->next;
+      free(temp);
+      temp=prev;
+    }
+
+    /* move to next item */
+    prev=temp;
+    temp=temp->next;
+  }
+  return found;
+}
+
+/****************************************
+delete oldest item from packet cache 
+****************************************/
+int delOldestCacheItem(void) {
+  DBT hashKey;
+  unsigned char addrRaw[ADDRMAXLN];
+  int addrLen=0;
+  
+  /* delete oldest item(=head) from queue */
+  if(DeQueueForCache(addrRaw, &addrLen)){
+
+    /* delete the item from Hash Table */
+    hashKey.data = addrRaw;
+    hashKey.size = addrLen;
+    hashDb->del(hashDb, &hashKey, 0);
+    
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/*********************************************
+initialize Queue
+ Queue
+ HeadNode - DataNode - DataNode - TailNode
+ (dummy)                           (dummy)
+  ^queueHead                        ^queueTail
+* this queue is internal struct of packet cache 
+*********************************************/
+int initQueueForCache(void){
+
+  unsigned char addrRaw[MACADDRLN];
+  int addrLen;
+
+  /* if not exist, prepare head and tail */
+  if(queueHead==NULL){
+    queueHead=(struct queueNode*)malloc(sizeof(struct queueNode));
+    if(queueHead==NULL){
+      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+    queueTail=(struct queueNode*)malloc(sizeof(struct queueNode));
+    if(queueTail==NULL){
+      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+    bzero(queueHead->addrRaw, MACADDRLN);
+    queueHead->addrLen=0;
+    bzero(queueTail->addrRaw, MACADDRLN);
+    queueTail->addrLen=0;
+    queueHead->next=queueTail;
+    queueTail->next=NULL;
+  }
+  
+  /* if exist, reset all */
+  else{
+    while(DeQueueForCache(addrRaw,&addrLen))
+      ;
+  }
+
+  /* reset item count */
+  cacheItemCount=0;
+
+  return TRUE;
+}
+
+/****************************************
+Add data to the tail of Queue
+ input=addr
+****************************************/
+int enQueueForCache(unsigned char* addrRaw, int addrLen){
+  struct queueNode *newNode;
+
+  /* if not prepared, error */
+  if(queueHead==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* check length */
+  if(addrLen>MACADDRLN){
+    err_msg("ERR at %s#%d: queue data is too long",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* add item after the tail and set it as new tail*/
+  newNode=(struct queueNode*)malloc(sizeof(struct queueNode));
+  if(newNode==NULL){
+    err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+  memcpy(queueTail->addrRaw, addrRaw, addrLen);
+  queueTail->addrLen=addrLen;
+  queueTail->next=newNode;
+  queueTail=newNode;
+  bzero(queueTail->addrRaw,MACADDRLN);
+  queueTail->addrLen=0;
+  queueTail->next=NULL;
+
+  /* increment item count */
+  cacheItemCount++;
+
+  return TRUE;
+}
+
+/****************************************
+Get and remove address data from the head of Queue
+output
+ addrRaw:binary string of Mac (length=MACADDRLN)
+ pAddrLen: pointer to the aquired string length 
+****************************************/
+int deQueueForCache(unsigned char* addrRaw, int* pAddrLen){
+
+  /* set null string as default */
+  bzero(addrRaw, MACADDRLN);
+
+  /* if not prepared, error */
+  if(queueHead==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;
+  }
+  else if(queueHead->next==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;  
+  }
+
+  /* if no data, return false */
+  else if(queueHead->next==queueTail){
+    return FALSE;
+  }
+
+  /* get item from the head */
+  else {
+    struct queueNode *temp;
+    temp=queueHead->next;
+    queueHead->next=temp->next;
+    memcpy(addrRaw, temp->addrRaw, temp->addrLen);
+    *pAddrLen=temp->addrLen;
+    free(temp);
+
+    /* decrement item count */
+    cacheItemCount--;
+  }
+
+  return TRUE;
+}
+
+/****************************************
+Listing Queue (for debugging)
+****************************************/
+int listQueueForCache(void){
+
+  struct queueNode *temp;
+  int i;
+
+  printf("Queue items\n");
+  if(queueHead==NULL) return FALSE;
+  temp=queueHead->next;
+  while(temp->next!=NULL){
+    for(i=0;i<temp->addrLen;i++){
+      printf("%x ", temp->addrRaw[i]);
+    }
+    printf("\n");
+    temp=temp->next;
+  }
+  printf("---\n");
+  return TRUE;
+}
+
+/****************************************
+memory free for Queue
+****************************************/
+void freeQueueForCache(void){
+  unsigned char addrRaw[MACADDRLN];
+  int addrLen;
+  while(DeQueueForCache(addrRaw,&addrLen));
+  free(queueHead);
+  free(queueTail);
+}
+
+/************************************/
+/* arp form is reformed to ndp form */ 
+/* format macAddr for ndp or arp    */
+/* match the form of two program    */
+/* mac addr by arp 00:01:12:0b:..   */
+/* mac addr by ndp 0:1:12:b:..      */
+/* DO NOT CALL IT WITH CONST STRING */
+/************************************/
+int reFormatMacAddr(char* macAddr)
+{
+  int m1,m2,m3,m4,m5,m6;
+  if(sscanf(macAddr, "%x:%x:%x:%x:%x:%x", &m1,&m2,&m3,&m4,&m5,&m6)!=6) return FALSE;
+  snprintf(macAddr, ADDRMAXLN,"%02x:%02x:%02x:%02x:%02x:%02x", m1,m2,m3,m4,m5,m6);
+  return TRUE;
+}
+
+
+/****************************************************
+ routines for debugging putput
+ ***************************************************/
+
+void InitCache(void) {
+  if(debug>1) err_msg("DEBUG:=>initCache( )");
+  initCache();
+  if(debug>1) err_msg("DEBUG:<=initCache( )");
+}
+
+void FreeCache(void) {
+  if(debug>1) err_msg("DEBUG:=>freeCache()");
+  freeCache();
+  if(debug>1) err_msg("DEBUG:<=freeCache()");
+}
+
+int IsRecentlyCheckedAddress(unsigned char* macAddressRaw){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isRecentlyCheckedAddress(%x)", macAddressRaw[0]);
+  ret = isRecentlyCheckedAddress(macAddressRaw);
+  if(debug>1) err_msg("DEBUG:(%d)<=isRecentlyCheckedAddress( )",ret);
+  return ret;
+}
+
+int DelCacheItem(char* macAddress) {
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delCacheItem(%s)", macAddress);
+  ret = delCacheItem(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=delCacheItem( )",ret);
+  return ret;
+}
+
+int DelOldestCacheItem(void) {
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delOldestCacheItem( )");
+  ret = delOldestCacheItem();
+  if(debug>1) err_msg("DEBUG:(%d)<=delOldestCacheItem( )",ret);
+  return ret;
+}
+
+int InitQueueForCache(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initQueueForCache( )");
+  ret = initQueueForCache();
+  if(debug>1) err_msg("DEBUG:(%d)<=initQueueForCache( )",ret);
+  return ret;
+}
+
+int EnQueueForCache(unsigned char* addrRaw, int addrLen){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>enQueueForCache(%x,%d)", addrRaw[0],addrLen);
+  ret = enQueueForCache(addrRaw,addrLen);
+  if(debug>1) err_msg("DEBUG:(%d)<=enQueueForCache( )",ret);
+  return ret;
+}
+
+int DeQueueForCache(unsigned char* addrRaw, int* pAddrLen){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>deQueueForCache( )");
+  ret = deQueueForCache(addrRaw,pAddrLen);
+  if(debug>1) err_msg("DEBUG:(%d)<=deQuqueForCache(%x,%d)",ret, addrRaw[0],*pAddrLen);
+  return ret;
+
+}
+int ListQueueForCache(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>listQueueForCache( )");
+  ret = listQueueForCache();
+  if(debug>1) err_msg("DEBUG:(%d)<=listQueueForCache( )",ret);
+  return ret;
+
+}
+
+void FreeQueueForCache(void){
+  if(debug>1) err_msg("DEBUG:=>freeQueueForCache()");
+  freeQueueForCache();
+  if(debug>1) err_msg("DEBUG:<=freequeueForCache()");
+
+}
+
+int ReFormatMacAddr(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>reFormatMacAddr(%s)", macAddr);
+  ret=reFormatMacAddr(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=reFormatMacAddr(%s)", ret, macAddr);
+  return ret;
+}
diff --git a/mdsrc/pcap.c b/mdsrc/pcap.c
new file mode 100644 (file)
index 0000000..e9ce6a3
--- /dev/null
@@ -0,0 +1,302 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module for  capturing packets with libpcap
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+#include <pcap.h>
+
+pcap_t *handle;                        /* pcap handle */
+
+/*******************************
+initialize libpcap
+*******************************/
+int initPcap(void){
+  char myMacAddress[ADDRMAXLN];                      /* mac of pcap device */
+  char errbuf[PCAP_ERRBUF_SIZE];                    /* Error string */
+  struct bpf_program fp;                            /* The compiled filter */
+  char filterExpr[FILTERMAXLN];                      /* filter expression */
+  bpf_u_int32 mask;                                 /* my netmask */
+  bpf_u_int32 net;                                  /* my IP */
+  int snaplen=atoi(GetConfValue("Pcap/SnapLength")); /* packet snap length */ 
+  int timeout=atoi(GetConfValue("Pcap/Timeout"));    /* pcap get timeout */
+  int promiscuous=atoi(GetConfValue("Pcap/Promiscuous")); /* promiscuous mode */
+  char* dev=GetConfValue("Pcap/Device");             /* pcap device */
+
+  /* set filter expression.  conf value might be [(not ether src %s) and ...] */
+  GetMyMacAddress(myMacAddress);
+  snprintf(filterExpr, FILTERMAXLN, GetConfValue("Pcap/Filter"), myMacAddress);
+
+  /* Find the properties for the device */
+  if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
+    err_msg("ERR at %s#%d: can't get netmask: %s",__FILE__,__LINE__,errbuf);
+    net = 0;
+    mask = 0;
+  }
+
+  /* Open pcap */
+  seteuid(0);   /* get root privilege */
+  handle = pcap_open_live(dev, snaplen, promiscuous, timeout, errbuf);
+  seteuid(getuid());   /* drop root privilege */
+  if (handle == NULL) {
+    err_msg("ERR at %s#%d: can't open device %s: %s",__FILE__,__LINE__,dev,errbuf);
+    terminateProg(0);
+  }
+  
+  /* If the link layer is not Ehternet, exit */
+  if(pcap_datalink(handle)!=DLT_EN10MB){
+    err_msg("ERR at %s#%d: Link layer is not ethernet",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* Compile and apply the filter */
+  if (pcap_compile(handle, &fp, filterExpr, 0, net) == -1) {
+    err_msg("ERR at %s#%d: can't compile pcap filter",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+  if (pcap_setfilter(handle, &fp) == -1) {
+    err_msg("ERR at %s#%d: can't set pcap filter",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  pcap_freecode(&fp);
+  return 0;
+}
+
+/*******************************
+get next packet from pcap 
+ret=0:no packet,1:ip packet,-1:other packet
+*******************************/
+int getNextPacketFromPcap(unsigned char* macAddressRaw, unsigned char* ipAddressRaw, int* pIpAddrLen, int* pTtl){
+  struct pcap_pkthdr header;   /* The header captured by pcap */
+  const u_char *packet;                /* The actual packet */
+  struct ip *ipv4h; 
+  struct ip6_hdr *ipv6h; 
+  struct ether_header *ethhdr;
+  int ret=0;
+
+  /* initialize to null string */
+  bzero(macAddressRaw,MACADDRLN);
+  bzero(ipAddressRaw,IPV6ADDRLN);
+  *pTtl=0;
+  *pIpAddrLen=0;
+
+  /* Grab a packet */
+  if((packet = pcap_next(handle, &header)) == NULL)return 0; /* 0=no packet*/
+
+  /* Get IpAddress and MacAddress from the packet */
+  if (header.caplen < sizeof(struct ip) + sizeof(struct ether_header)) { 
+    return -1; /* -1=not ip packet */
+  } 
+  
+  /* get mac address from ether header */
+  ethhdr = (struct ether_header *)packet; 
+  memcpy(macAddressRaw, ethhdr->ether_shost, MACADDRLN);
+
+  /* get ip address from ip header */
+  switch (ntohs(ethhdr->ether_type)) { 
+    case ETHERTYPE_IP: 
+      *pIpAddrLen=IPV4ADDRLN;
+      ipv4h = (struct ip *)(packet + sizeof(struct ether_header)); 
+      memcpy( ipAddressRaw, &ipv4h->ip_src, IPV4ADDRLN);
+      *pTtl = ipv4h->ip_ttl;
+      ret=1; /* 1=success */
+      break;
+
+    case ETHERTYPE_IPV6: 
+      *pIpAddrLen=IPV6ADDRLN;
+      ipv6h = (struct ip6_hdr *)(packet + sizeof(struct ether_header)); 
+      memcpy(ipAddressRaw, &ipv6h->ip6_src, IPV6ADDRLN);
+      *pTtl = ipv6h->ip6_ctlun.ip6_un1.ip6_un1_hlim;
+      ret=1; /* 1=success */
+      break; 
+
+    default:
+      ret=-1; /* -1=not ip packet */
+      break;
+  } 
+  return ret;
+}
+
+/**************************
+close pcap
+**************************/
+void closePcap(void){
+
+  /* And close the session */
+  pcap_close(handle);
+
+}
+
+/********************************************
+ get mac address for the pcap device
+********************************************/
+int getMyMacAddress(char* macAddress){
+    struct ifaddrs* ifapHead;
+    int          found = FALSE;
+    struct ifaddrs* ifap;
+    struct sockaddr_dl* sdl = NULL;
+    char*       pcapDev;
+
+    /* set default value */
+    strncpy(macAddress, "00:00:00:00:00:00", ADDRMAXLN);
+
+    /* get pcap device name from conf file */
+    pcapDev = GetConfValue("Pcap/Device");
+    if(isNull(pcapDev)) return FALSE;
+
+    /* get ifaddrs */
+    if (getifaddrs(&ifapHead) != 0){
+      err_msg("ERR at %s#%d: getifaddrs failed",__FILE__,__LINE__);
+      return FALSE;
+    }
+
+    /* search pcap device */
+    for (ifap = ifapHead; ifap!=NULL; ifap = ifap->ifa_next) {
+      if ((ifap->ifa_addr->sa_family == AF_LINK) 
+         && (strcmp(ifap->ifa_name, pcapDev) == 0)) {
+       found=TRUE;
+       break;
+      }
+    }
+
+    /* if not found, error return */
+    if(!found){
+      err_msg("ERR at %s#%d: cannot find interface %s",
+             __FILE__,__LINE__, pcapDev);
+      if(ifapHead) freeifaddrs(ifapHead);
+      return FALSE;
+    }
+
+    /* if found, convert to [12:34:56:78:9a:bc] */
+    sdl = (struct sockaddr_dl *)ifap->ifa_addr;
+    if(sdl != NULL){
+      ConvertMacFromRawToDisplay((unsigned char*)LLADDR(sdl), macAddress);
+    }
+    if(ifapHead) freeifaddrs(ifapHead);
+
+    return TRUE;
+}
+
+/*****************************
+convert IP address from network raw form to display form 
+*****************************/
+int convertIpFromRawToDisplay(unsigned char* ipAddressRaw, int ipAddrLen, char* ipAddress){
+  int ret;
+  char zeroAddress[IPV6ADDRLN]={0};  
+  
+  /* convert ip address from network form to presentation form */
+  switch (ipAddrLen) { 
+  case IPV4ADDRLN: 
+    inet_ntop(AF_INET, ipAddressRaw, ipAddress, ADDRMAXLN);
+    if(memcmp(ipAddressRaw, zeroAddress, IPV4ADDRLN)==0) ret=FALSE;
+    else ret=TRUE;
+    break;
+    
+  case IPV6ADDRLN: 
+    inet_ntop(AF_INET6, ipAddressRaw, ipAddress, ADDRMAXLN);
+    if(memcmp(ipAddressRaw, zeroAddress, IPV6ADDRLN)==0) ret=FALSE;
+    else ret=TRUE;
+    break;
+    
+  default:
+    ipAddress[0]='\0';
+    ret=FALSE;
+    break;
+  }
+  return ret;
+}
+
+/*****************************
+convert IP address from network raw form to display form 
+*****************************/
+void convertMacFromRawToDisplay(unsigned char* macAddressRaw, char* macAddress){
+  strncpy(macAddress, ether_ntoa((struct ether_addr*)macAddressRaw), ADDRMAXLN);
+}
+
+/***********************************************
+ routines for debugging output 
+**********************************************/
+int InitPcap(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initPcap( )");
+  ret = initPcap();
+  if(debug>1) err_msg("DEBUG:(%d)<=initPcap( )",ret);
+  return ret;
+}
+int GetNextPacketFromPcap(unsigned char* macAddressRaw, unsigned char* ipAddressRaw, int* pIpAddrLen, int* pTtl){
+  int ret;
+  if(debug>2) err_msg("DEBUG:=>getNextPacketFromPcap( )");
+  ret = getNextPacketFromPcap(macAddressRaw, ipAddressRaw, pIpAddrLen, pTtl);
+  if(debug>2) err_msg("DEBUG:(%d)<=getNextPacketFromPcap(%x,%x,%d,%d)",ret,macAddressRaw[0],ipAddressRaw,*pIpAddrLen,*pTtl);
+  return ret;
+}
+
+void ClosePcap(void){
+  if(debug>1) err_msg("DEBUG:=>closePcap( )");
+  closePcap();
+  if(debug>1) err_msg("DEBUG:<=closePcap( )");
+}
+
+
+int GetMyMacAddress(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getMyMacAddress( )");
+  ret = getMyMacAddress(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=getMyMacAddress(%s)",ret,macAddress);
+  return ret;
+}
+
+int ConvertIpFromRawToDisplay(unsigned char* ipAddressRaw, int ipAddrLen, char* ipAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>convertIpFromRawtoDisplay(%x,%d,)",ipAddressRaw[0],ipAddrLen);
+  ret=convertIpFromRawToDisplay(ipAddressRaw, ipAddrLen, ipAddress);
+  if(debug>1) err_msg("DEBUG:<=convertIpFromRawToDisplay(,,%s)",ipAddress);
+  return ret;
+}
+
+void ConvertMacFromRawToDisplay(unsigned char* macAddressRaw, char* macAddress){
+  if(debug>1) err_msg("DEBUG:=>closePcap(%x)",macAddressRaw[0]);
+  convertMacFromRawToDisplay(macAddressRaw, macAddress);
+  if(debug>1) err_msg("DEBUG:<=closePcap(%s)",macAddress);
+}
+
+/**************test main********************
+int testmain(){
+
+  char ipAddress[ADDRMAXLN];
+  char macAddress[ADDRMAXLN];
+  int count=0;
+  int len,ttl;
+
+  initPcap();
+  
+  while(count<50){
+    if(getNextPacketFromPcap(macAddress, ipAddress, &len, &ttl)){
+      count++;
+      printf("MAC[%s],IP[%s]\n", macAddress, ipAddress);
+    }
+  }
+
+  closePcap();
+  return 0;
+}
+******************************************/
diff --git a/mdsrc/session.c b/mdsrc/session.c
new file mode 100644 (file)
index 0000000..3625f44
--- /dev/null
@@ -0,0 +1,566 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+   module for Controlling sessions 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+/*******************************
+add session for the mac address
+add ipfw-rule and table-entry, write db and log 
+*******************************/
+int addSession(char* macAddress, char* ipAddress, char* userId, char* extraId){
+  int ruleNumber;
+  static int nSerialError=0; /* number of serial errors for addition */
+  int failToAdd=FALSE;
+  char ipAddressInDb[ADDRMAXLN];
+  int openTime;
+  int checkTime;
+  int ruleNumberInDb;
+
+  /* open firewall */
+  ruleNumber=OpenClientGate(macAddress, userId, extraId);
+
+  /* check error */
+  if(-2<=ruleNumber && ruleNumber<=2) failToAdd=TRUE;
+
+  /* if mac is already registered in ipfw rule */
+  if(ruleNumber < -2){
+    
+    /* if mac is active session in work db, do nothing */
+    if(GetSessionFromWorkDb(macAddress, userId, extraId, &openTime,
+                           &checkTime, ipAddressInDb, &ruleNumberInDb)){ 
+      return FALSE;
+    }
+    /* if not active session in work db, invert sign and goto write db */
+    else{
+      ruleNumber=-ruleNumber;
+    }
+  }
+
+  /* if addtion is failed, retry on next packet (clear cache for checking) */
+  /* as to prevent error loop, retry count is limitted */ 
+  if( failToAdd || !IsMacAddressFoundInIpfw(macAddress) ){
+    nSerialError++;
+    if(nSerialError<1) DelCacheItem(macAddress);
+    err_msg("ERR at %s#%d: ipfw rule addition is failed(%d-%d)",
+             __FILE__,__LINE__, failToAdd, nSerialError);
+    return FALSE;
+  }
+  nSerialError=0;
+
+  /* write to session db */
+  InsertSessionToWorkDb(macAddress, userId, extraId, ipAddress, ruleNumber);
+
+  /* write open log to syslog */
+  WriteOpenToSyslog(userId, extraId, ipAddress, macAddress);
+
+  /* write log to management db */
+  PutOpenToMngDb(macAddress, ipAddress);
+  return TRUE;
+}
+
+/*******************************
+delete session for the mac address
+(del ipfw-rule and table-entry, write db and log) 
+*******************************/
+void delSession(char* macAddress){
+  char userId[USERMAXLN]="";
+  char extraId[USERMAXLN]="";
+  char ipAddress[ADDRMAXLN]="";
+  int openTime=0;
+  int ruleNumber=0;
+  int checkTime=0;
+  int success;
+
+  /* get information from session table in work db */
+  success=GetSessionFromWorkDb(macAddress, userId, extraId, &openTime, 
+                                &checkTime, ipAddress, &ruleNumber);
+
+  /* close firewall and refresh the cache */
+  if(success) CloseClientGate(ruleNumber);
+
+  /* del from cache */
+  DelCacheItem(macAddress);
+  
+  /* del from session from session table in work db */
+  DelSessionFromWorkDb(macAddress);
+
+  /* write close log to syslog */
+  WriteCloseToSyslog(userId, extraId, ipAddress, macAddress, openTime);
+  if(debug>0) WriteSessionInfoToSyslog(userId, extraId, ipAddress, 
+                                      macAddress, ruleNumber);
+
+  /* write close log to management db */
+  PutCloseToMngDb(macAddress);
+}
+
+/*******************************
+renew session for the ip address
+(renew time in table entry) 
+*******************************/
+void renewSession(char* macAddress){
+
+  /* renew the check time */
+  UpdateCheckTimeInWorkDb(macAddress);
+}
+
+/*******************************
+search db to find ip that is not used for a long time
+del ipfw rule, del table entry, write db/log 
+*******************************/
+void delUselessSessions(void){
+
+  /* scan db to remove old sessions */
+  DelUselessSessionsInWorkDb(TRUE);
+
+  /* scan ipfw rule to close unmatched db row */
+  CloseUnmatchSessions();
+}
+
+/**********************************
+CALLBACK FUNCTION
+called back from sqlite3_exec 
+in sessiondb.c/delUselessSessionsInDb & delAllSessionsInDb
+**********************************/
+int closeSession(void* pParam, int argc, char *argv[], char* colName[]){
+
+  int ruleNumber;
+  char* userId;
+  char* extraId;
+  char* ipAddress;
+  char* macAddress;
+  int openTime;
+
+  if(argc < 5) return 1; /* SQLITE_ERROR */
+  
+  ruleNumber=atoi(argv[0]);
+  userId=argv[1];
+  extraId=argv[2];
+  ipAddress=argv[3];
+  macAddress=argv[4];
+  openTime=atoi(argv[5]);
+
+  /* close firewall */
+  CloseClientGate(ruleNumber);
+  DelCacheItem(macAddress);
+
+  /* write close log to syslog */
+  WriteCloseToSyslog(userId, extraId, ipAddress, macAddress, openTime);
+  if(debug>0) WriteSessionInfoToSyslog(userId, extraId, ipAddress, 
+                                      macAddress, ruleNumber);
+
+  /* write close log to management db */
+  PutCloseToMngDb(macAddress);
+
+  return 0; /* SQLITE_OK */
+}
+
+/*******************************
+search db to find all ip
+del ipfw rule, del table entry, write db/log 
+*******************************/
+void delAllSessions(void){
+
+  /* scan db to remove all sessions. argument indicates delayed flag */
+  DelUselessSessionsInWorkDb(FALSE);
+
+  /* scan ipfw rule to close unmatched db row */
+  CloseUnmatchSessions();
+}
+
+/**********************************************
+is the mac session found 
+**********************************************/
+int isMatchedSessionFound(char* macAddress){
+  char userId[USERMAXLN];
+  char extraId[USERMAXLN];
+  int openTime;
+  int checkTime;
+  char ipAddress[ADDRMAXLN];
+  int ruleNumber;
+
+  /* get info for the macAddress */
+  return GetSessionFromWorkDb(macAddress, userId, extraId, 
+                        &openTime, &checkTime, ipAddress,
+                            &ruleNumber);
+}
+
+/************************************
+debug routine for hash table
+************************************/
+void dumpTable(DB* table){
+  DBT hashKey;
+  DBT hashVal;
+  int ruleNumber=0;
+  char macAddress[ADDRMAXLN]="?";
+  int ret;
+
+  memset(&hashKey, 0, sizeof(DBT));
+  memset(&hashVal, 0, sizeof(DBT));
+  ret=table->seq(table, &hashKey, &hashVal, R_FIRST);
+  while(ret==0){
+
+    ruleNumber=*(int*)(hashVal.data);
+    strncpy(macAddress, (char*)hashKey.data, ADDRMAXLN);
+    err_msg("%d:%s", ruleNumber, macAddress);
+
+    /* get next entry */
+    ret=table->seq(table, &hashKey, &hashVal, R_NEXT);
+  }
+}
+
+/************************************************
+ close sessions that lost ipfw rule or database entry
+ load rules from ipfw and database, then compare
+  sessionTable        ruleTable
+form opengatemd.db    from ipfw
+   key=macAddr         macAddr
+   val=0               ipfwRule
+      ^                 ^  
+      |-----------------|  
+entry in ruleTable adn sessionTable should be matched.
+if exists in ruleTable and not in sessionTable, remove rule
+if exists in sessionTable and not in ruleTable, remove session
+*************************************************/
+void closeUnmatchSessions(void){
+  DB* ruleTable;
+  DB* sessionTable;
+
+  /* prepare hash table for active sessions */
+  if((sessionTable = dbopen(NULL, O_CREAT | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
+    err_msg("ERR at %s#%d: fail to open hash table",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* prepare hash table for rule numbers */
+  if((ruleTable = dbopen(NULL, O_CREAT | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
+    err_msg("ERR at %s#%d: fail to open hash table",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+
+  /* get rule numbers from ipfw */
+  GetRuleTableFromIpfw(ruleTable);
+
+  /* get active sessions from work db */
+  GetSessionTableFromWorkDb(sessionTable);
+
+  /****debug print
+  err_msg("Rule");
+  dumpTable(ruleTable);
+  err_msg("Session");
+  dumpTable(sessionTable);
+  ****/
+
+  /* remove unmatched entry */
+  RemoveSessionUnmatchedToIpfwRule(ruleTable, sessionTable);
+  RemoveIpfwRuleUnmatchedToSession(ruleTable, sessionTable);
+
+  /* erase table area */
+  sessionTable->close(sessionTable);
+  ruleTable->close(ruleTable);
+}
+
+/*******************************
+remove session in db unmatched to ipfw active rule
+ (db entry exists but no ipfw rule is found)
+*******************************/
+void removeSessionUnmatchedToIpfwRule(DB* ruleTable, DB* sessionTable){
+  DBT hashKey;
+  DBT hashVal;
+  int retRuleTbl;
+  int retSesTbl;
+  int ruleNumber;
+  char ipAddress[ADDRMAXLN];
+  char userId[USERMAXLN];
+  char extraId[USERMAXLN];
+  char macAddress[ADDRMAXLN];
+  int openTime;
+  int checkTime;
+
+  /* scan session table to find entry unmatched to rule table */
+  /* get first entry of session table */
+  memset(&hashKey, 0, sizeof(DBT));
+  memset(&hashVal, 0, sizeof(DBT));
+  retSesTbl=sessionTable->seq(sessionTable, &hashKey, &hashVal, R_FIRST);
+  while(retSesTbl==0){
+
+    /* (get-function returns 0 on success) */
+    /* if found a session, save the data */
+    strncpy(macAddress, (char*)hashKey.data, ADDRMAXLN);
+
+    /* get entry having same key in rule table */
+    hashKey.data = macAddress;
+    hashKey.size = strlen(macAddress)+1;
+    memset(&hashVal, 0, sizeof(DBT));
+    retRuleTbl=ruleTable->get(ruleTable, &hashKey, &hashVal, 0);
+
+    /* (get-function returns 0 on success) */
+    /*** rule for the session exists */
+    if(retRuleTbl==0){
+      ; /* do nothing */
+    }
+
+    /*** rule for the session does not exist */
+    else{
+      /* write log and close session */
+      if(!GetSessionFromWorkDb(macAddress, userId, extraId, 
+                             &openTime, &checkTime,ipAddress, &ruleNumber)){
+       err_msg("ERR at %s#%d: fail to get session info",__FILE__,__LINE__);
+      }else{
+       WriteCloseToSyslog(userId, extraId, ipAddress, macAddress, openTime);
+       PutCloseToMngDb(macAddress);
+       DelSessionFromWorkDb(macAddress);
+      }
+
+      /* write session info to syslog */
+      if(debug>0) WriteSessionInfoToSyslog(userId, extraId, ipAddress, 
+                                          macAddress, ruleNumber);
+    }
+
+    /* get next rule entry */
+    retSesTbl=sessionTable->seq(sessionTable, &hashKey, &hashVal, R_NEXT);
+  }
+}
+
+/***********************************
+remove active ipfw rule unmatched to session in db
+ (ipfw rule exists but no db entry is found)
+***********************************/
+void  removeIpfwRuleUnmatchedToSession(DB* ruleTable, DB* sessionTable){
+  DBT hashKey;
+  DBT hashVal;
+  int retRuleTbl;
+  int retSesTbl;
+  int ruleNumber;
+  char macAddress[ADDRMAXLN];
+
+  /* scan ipfw rule table to find entry unmatched to session table */
+  /* get first entry of ipfw rule table */
+  memset(&hashKey, 0, sizeof(DBT));
+  memset(&hashVal, 0, sizeof(DBT));
+  retRuleTbl=ruleTable->seq(ruleTable, &hashKey, &hashVal, R_FIRST);
+  while(retRuleTbl==0){
+
+    /* if found in rule table, save data */
+    ruleNumber=*(int*)(hashVal.data);
+    strncpy(macAddress, (char*)hashKey.data, ADDRMAXLN);
+
+    /* get entry having same key in session table */
+    hashKey.data = macAddress;
+    hashKey.size = strlen(macAddress)+1;
+    memset(&hashVal, 0, sizeof(DBT));
+    retSesTbl=sessionTable->get(sessionTable, &hashKey, &hashVal, 0);
+
+    /* (get-function returns 0 on success) */
+    /*** session for the rule exists */
+    if(retSesTbl==0){
+      ; /* do nothing */
+    }
+
+    /*** session for the rule does not exist */
+    else{
+
+      /* remove entry in ipfw rule */
+      CloseClientGate(ruleNumber);
+      DelCacheItem(macAddress);
+
+      /* write log */
+      WriteCloseToSyslog("?", "", "?", macAddress, time(NULL));
+      PutCloseToMngDb(macAddress);
+      
+      /* write session info to syslog */
+      if(debug>0) WriteSessionInfoToSyslog("?","","?",macAddress, ruleNumber);
+    }
+
+    /* get next rule entry */
+    retRuleTbl=ruleTable->seq(ruleTable, &hashKey, &hashVal, R_NEXT);
+  }
+}
+
+
+/******************************************
+write open message to syslog
+******************************************/
+void writeOpenToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress){
+
+  if(extraId[0]=='\0'){
+    err_msg("OPEN: user %s from %s at %s", 
+           userId, ipAddress, macAddress);
+  }else{
+    err_msg("OPEN: user %s%s%s from %s at %s", 
+           userId, GetConfValue("UserIdSeparator"), extraId, 
+           ipAddress, macAddress);
+  }
+}
+
+/******************************************
+write close message to syslog
+******************************************/
+void writeCloseToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int openTime){
+
+  double time_l;
+  int hour, min, sec;
+
+  time_l=difftime((int)time(NULL), openTime);
+  hour=time_l/60/60;
+  min=(time_l-hour*60*60)/60;
+  sec=(time_l-hour*60*60-min*60);
+
+  if(extraId[0]=='\0'){
+    err_msg("CLOS: user %s from %s at %s ( %02d:%02d:%02d )", 
+           userId, ipAddress, macAddress, hour,min,sec);
+  }else{
+    err_msg("CLOS: user %s%s%s from %s at %s ( %02d:%02d:%02d )", 
+           userId, GetConfValue("UserIdSeparator"), extraId, 
+           ipAddress, macAddress, hour,min,sec);
+  }
+}
+
+/******************************************
+write session info message to syslog
+******************************************/
+void writeSessionInfoToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int ruleNumber){
+
+  char detectTimeStr[WORDMAXLN];
+  int ttl;
+
+  /* get client info from macinfo table in workdb */
+  GetMacInfoFromWorkDb(macAddress, detectTimeStr, &ttl);
+
+  if(extraId[0]=='\0'){
+    err_msg("INFO: user=%s ipaddr=%s macaddr=%s "
+           "ipfwrule=%d ttl=%d lastcheck=%s", 
+           userId, ipAddress, macAddress, ruleNumber, ttl, detectTimeStr);
+  }else{
+    err_msg("INFO: user=%s%s%s ipaddr=%s macaddr=%s "
+           "ipfwrule=%d ttl=%d lastcheck=%s", 
+           userId, GetConfValue("UserIdSeparator"), extraId, 
+           ipAddress, macAddress, ruleNumber, ttl, detectTimeStr);
+  }
+}
+
+
+/**************************************************
+ routines for debugging output
+ *************************************************/
+
+int AddSession(char* macAddress, char* ipAddress, char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>addSession(%s,%s,%s,%s)",
+                     macAddress, ipAddress, userId, extraId);
+  ret = addSession(macAddress, ipAddress, userId, extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=addSession( )",ret);
+  return ret;
+}
+void DelSession(char* macAddress){
+  if(debug>1) err_msg("DEBUG:=>delSession(%s)",macAddress);
+  delSession(macAddress);
+  if(debug>1) err_msg("DEBUG:<=delSession( )");
+}
+void RenewSession(char* macAddress){
+  if(debug>1) err_msg("DEBUG:=>renewSession(%s)",macAddress);
+  renewSession(macAddress);
+  if(debug>1) err_msg("DEBUG:<=renewSession( )");
+}
+void DelUselessSessions(void){
+  if(debug>1) err_msg("DEBUG:=>delUselessSessions()");
+  delUselessSessions();
+  if(debug>1) err_msg("DEBUG:<=delUselessSessions( )");
+}
+void DelAllSessions(void){
+  if(debug>1) err_msg("DEBUG:=>delAllSessions()");
+  delAllSessions();
+  if(debug>1) err_msg("DEBUG:<=delAllSessions( )");
+}
+int CloseSession(void* pParam, int argc, char *argv[], char* colName[]){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>closeSession()");
+  ret = closeSession(pParam, argc, argv, colName);
+  if(debug>1) err_msg("DEBUG:(%d)<=closeSession( )",ret);
+  return ret;
+}
+int IsMatchedSessionFound(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isMatchedSessionFound(%s)",
+                     macAddress);
+  ret = isMatchedSessionFound(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isMatchedSessionFound( )",ret);
+  return ret;
+}
+
+void CloseUnmatchSessions(void){
+  if(debug>1) err_msg("DEBUG:=>closeUnmatchSessions( )");
+  closeUnmatchSessions();
+  if(debug>1) err_msg("DEBUG:<=closeUnmatchSessions( )");
+}
+
+void WriteOpenToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress){
+  if(debug>1) err_msg("DEBUG:=>writeOpenToSyslog(%s,%s,%s,%s)", userId, extraId, ipAddress, macAddress);
+  writeOpenToSyslog(userId, extraId, ipAddress, macAddress);
+  if(debug>1) err_msg("DEBUG:<=writeOpenToSyslog( )");
+}
+
+void WriteCloseToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int openTime){
+  if(debug>1) err_msg("DEBUG:=>writeCloseToSyslog(%s,%s,%s,%s,%d)", userId, extraId, ipAddress, macAddress, openTime);
+  writeCloseToSyslog(userId, extraId, ipAddress, macAddress, openTime);
+  if(debug>1) err_msg("DEBUG:<=writeCloseToSyslog( )");
+}
+
+void WriteSessionInfoToSyslog(char* userId, char* extraId, char* ipAddress, char* macAddress, int ruleNumber){
+  if(debug>1) err_msg("DEBUG:=>writeSessionInfoToSyslog(%s,%s,%s,%s,%d)", userId, extraId, ipAddress, macAddress, ruleNumber);
+  writeSessionInfoToSyslog(userId, extraId, ipAddress, macAddress, ruleNumber);
+  if(debug>1) err_msg("DEBUG:<=writeSessionInfoToSyslog( )");
+}
+
+
+void RemoveSessionUnmatchedToIpfwRule(DB* ruleTable, DB* sessionTable){
+  if(debug>1) err_msg("DEBUG:=>removeSessionUnmatchedToIpfwRule()");
+  removeSessionUnmatchedToIpfwRule(ruleTable, sessionTable);
+  if(debug>1) err_msg("DEBUG:<=removeSessionUnmatchedToIpfwRule()");
+}
+
+void RemoveIpfwRuleUnmatchedToSession(DB* ruleTable, DB* sessionTable){
+  if(debug>1) err_msg("DEBUG:=>removeIpfwRuleUnmatchedToSession()");
+  removeIpfwRuleUnmatchedToSession(ruleTable, sessionTable);
+  if(debug>1) err_msg("DEBUG:<=removeIpfwRuleUnmatchedToSession()");
+
+}
+
+
+/********************testmain********************
+void testmain(){
+
+  char* ipAddress="192.168.0.120";
+  char* macAddress="00:01:02:03:04:05";
+  char* userId="watanaby";
+  char* extraId="";
+
+  addSession(ipAddress, macAddress, userId, extraId);
+  sleep(10);
+  renewSession(ipAddress);
+  sleep(10);
+  delUselessSessions();
+  sleep(10);
+  delUselessSessions();
+  delSession(ipAddress);
+}
+************************************************/
diff --git a/mdsrc/ttlcheck.c b/mdsrc/ttlcheck.c
new file mode 100644 (file)
index 0000000..c17637b
--- /dev/null
@@ -0,0 +1,239 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+ module for checking ttl (or hlim in v6) to detect router
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+struct SubnetSet{
+  unsigned long subnetBits;
+  int maskLength;
+  int hopCount;
+};
+
+static char validInitialTtl[256];
+static struct SubnetSet* pSubnet;
+static int nSubnet;
+
+/**********************************
+initialize ttl check routine
+**********************************/
+int initTtlCheck(void){
+
+  char* pStart;
+  int ttlValue;
+  int i;
+  char* subnetStr=NULL;
+  struct SubnetSet* pNext;
+  unsigned long subnetBits;
+  unsigned int byte[4];
+  int maskLength=0;
+  int hopCount=0;
+
+
+  /***** ttl table setting ******/
+  /* initial values of table is false */
+  for(i=0; i<256; i++) validInitialTtl[i] = FALSE;
+
+  /* get string for initial ttls from conf file, eg:[64 128 255] */
+  pStart = GetConfValue("ValidInitialTtl");
+  if(isNull(pStart)) return FALSE;
+  
+  /* loop for setting ttl table */
+  while(1){
+
+    /* get number and set table entry */
+    if(sscanf(pStart, "%d", &ttlValue)==1){
+      validInitialTtl[ttlValue]=TRUE;
+    }
+
+    /* set next scan point */
+    pStart = strchr(pStart+1, ' ');
+    if(isNull(pStart)) break;
+  }
+
+  /******** subnet setting ***********/
+  /* count subnet setting */
+  nSubnet=0;
+  subnetStr=GetFirstConfValue("SubnetHopCount");
+  while(!isNull(subnetStr)){
+    nSubnet++;
+    subnetStr=GetNextConfValue();
+  }
+
+  /* get memory for the setting */
+  pSubnet=malloc(sizeof(struct SubnetSet)*(nSubnet));
+  pNext=pSubnet;
+  
+  /*loop all subnet setting */
+  subnetStr=GetFirstConfValue("SubnetHopCount");
+  while(!isNull(subnetStr)){
+
+    /* get address and hop count defined as [192.168.1.0/24 1] */
+    if(sscanf(subnetStr, "%d.%d.%d.%d/%d %d", 
+             &byte[0], &byte[1], &byte[2], &byte[3], 
+             &maskLength, &hopCount)==6){
+
+      /* sum up address bytes to a long int */
+      subnetBits=0;
+      for(i=0; i<4; i++){
+       subnetBits = subnetBits<<8;
+       subnetBits += byte[i];
+      }
+      
+      /* save subnet setting to malloc area */
+      pNext->subnetBits=subnetBits;
+      if(maskLength<=32) pNext->maskLength=maskLength;
+      else               pNext->maskLength=0;
+      pNext->hopCount=hopCount;
+
+      /* goto next store area */
+      pNext++;
+    }
+
+    /* get next subnet setting */
+    subnetStr=GetNextConfValue();
+  }
+
+  return TRUE;
+}
+
+/*********************************
+check ttl for detecting access via nat/router
+*********************************/
+int isSentViaNatOrRouter(char* ipAddress, char* macAddress, int ttl){
+
+  unsigned int byte[4]; /* 4 bytes representing given ipv4 address */
+  unsigned long addressBits=0;
+  unsigned long subnetMask=0;
+  int maxMaskLength=0;
+  int hopSave=0;
+  struct SubnetSet* pNext;
+  int i;
+
+  /* if ttl is valid initial ttl then no router/nat */
+  if( validInitialTtl[ttl] ) return 0; /* no router/nat */
+
+  /* if ipv6, the nat/router is assumed as a router */
+  if( strchr(ipAddress, ':')!=NULL){
+    if( validInitialTtl[ttl] ) return 0; /* direct (no router/nat) */
+    else return 2; /* router */ 
+  }
+
+  /* if ipv4, calculate initial ttl as (present ttl)+(router hops) */
+  /* and compare to the router hop setting in conf file */
+  /* get 4 bytes of ipv4 address */
+  if(sscanf(ipAddress, "%d.%d.%d.%d", 
+           &byte[0], &byte[1], &byte[2], &byte[3])!=4) return -1;/*error */
+
+  /* sum up address bytes to a long int */
+  addressBits=0;
+  for(i=0; i<4; i++){
+    addressBits = addressBits<<8;
+    addressBits += byte[i];
+  }
+
+  /* check each subnet setting */
+  pNext=pSubnet;
+  maxMaskLength=0;
+  hopSave=0;
+  for(i=0; i<nSubnet; i++){
+
+    /* compare subnet and address */
+    /*  subnetBits  1011 0011 1100 0011 0000 */
+    /*  addressBits 1011 0011 0110 0011 1100 */
+    /*    Bit XOR   0000 0000 1010 0000 1100 */ 
+    /*  subnet mask 1111 1111 1111 1111 0000 */
+    /*    Bit AND   0000 0000 1010 0000 0000 */
+    /* If result is all-zero, the address is in the subnet */
+    subnetMask=0xFFFFFFFF<<(32 - (pNext->maskLength));
+    if(!( ((pNext->subnetBits)^addressBits) & subnetMask )){
+
+      /* if the address is included in subnet having longest mask */
+      /* save the hop count */
+      if((pNext->maskLength) > maxMaskLength){
+       maxMaskLength = pNext->maskLength;
+       hopSave = pNext->hopCount;
+      }
+    }
+
+    /* get next SubnetHopCount */
+    pNext++;
+  }
+  
+  /* add hop to ttl, then compare to valid initial ttl */
+  if( hopSave<0 || (ttl+hopSave)>=256 ) return ERROR; /* error */
+  if( validInitialTtl[ttl+hopSave] ){
+    if(hopSave==0) return NONAT; /* no nat/router */
+    else  return ROUTER; /* valid router */
+  }
+  return NAT; /* unknown nat or router inserted */
+}
+
+/***********************************************
+ putout log at nat/router detection 
+ isNatOrRouter:1=UnknownNatOrRouter, 2=FormalRouterOnly, 0=None, -1=err
+**********************************************/
+void putLogAtNatOrRouter(int isNatOrRouter, char* ipAddress, char* macAddress, int ttl){
+
+  if(isNatOrRouter==1 && atoi(GetConfValue("ShowNat"))){
+    err_msg("INFO : packet is sent via unknown nat/router[%s][%s][%d]", 
+           ipAddress, macAddress, ttl);
+  }
+  if(isNatOrRouter==2 && atoi(GetConfValue("ShowRouter"))){
+    err_msg("INFO : packet is sent via formal router[%s][%s][%d]", 
+           ipAddress, macAddress, ttl);
+  }
+}
+
+/***********************************************
+ routines for debugging output 
+**********************************************/
+int InitTtlCheck(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initTtlCheck( )");
+  ret = initTtlCheck();
+  if(debug>1) err_msg("DEBUG:(%d)<=initTtlCheck( )",ret);
+  return ret;
+}
+
+int IsSentViaNatOrRouter(char* ipAddress, char* macAddress, int ttl){
+  int ret;
+  if(debug>2) err_msg("DEBUG:=>isSentViaNatOrRouter(%s,%s,%d)", ipAddress, macAddress, ttl);
+  ret = isSentViaNatOrRouter(ipAddress, macAddress, ttl);
+  if(debug>2) err_msg("DEBUG:(%d)<=isSentViaNatOrRouter( )", ret);
+  return ret;
+}
+
+void PutLogAtNatOrRouter(int isNatOrRouter, char* ipAddress, char* macAddress, int ttl){
+  if(debug>2) err_msg("DEBUG:=>putLogAtNatOrRouter(%d,%s,%s,%d)", 
+                     isNatOrRouter,ipAddress,macAddress,ttl);
+  putLogAtNatOrRouter(isNatOrRouter,ipAddress,macAddress,ttl);
+  if(debug>2) err_msg("DEBUG:(%d)<=putLOgAtNatOrRouter( )");
+}
+
+
+
+/**************test main********************
+int testmain(){
+
+}
+******************************************/
diff --git a/mdsrc/udpserv.c b/mdsrc/udpserv.c
new file mode 100644 (file)
index 0000000..cf65ceb
--- /dev/null
@@ -0,0 +1,341 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+
+ module to control queue 
+
+  As ip address check by database is time consuming procedure,
+  the recently checked addresses are cached and skiped.
+  Implemented with HashTable and Queue.
+  HashTable has recentry checked dataStress and checked time.
+  If ip is included in table and time is new, ignore checking.
+  Queue has dataStresses odrered by checked time.
+  If an old item is found in table, elder items are removed from table.
+  The queue controls the remove sequence.
+
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemd.h"
+
+
+#define MAXFDCOUNT 10
+
+/* data for select fds */
+static fd_set fds; /* fd set */
+static int selMax=0; /* max number of fds */
+static int fdList[MAXFDCOUNT]; /* fd numbers */
+static int fdCount=0; /* count of fds */
+
+static int udpPrepared=FALSE;
+
+/**********************************
+ get sockaddr, IPv4 or IPv6:
+***********************************/
+void *get_in_addr(struct sockaddr *sa)
+{
+  if (sa->sa_family == AF_INET) {
+    return &(((struct sockaddr_in*)sa)->sin_addr);
+  }else{
+    return &(((struct sockaddr_in6*)sa)->sin6_addr);
+  }
+}
+
+
+/***************************************
+prepare udp server port
+****************************************/
+int prepareUdpPort(void (*handler)(int)){
+  int sockfd;
+  struct addrinfo hints, *servinfo, *p;
+  int val=1;
+  int ret;
+  char* udpServerPort;
+
+  /* prepare socket hint */
+  memset(&hints, 0, sizeof hints);
+  hints.ai_family = AF_UNSPEC;  /* IPv4/IPv6 dual */
+  hints.ai_socktype = SOCK_DGRAM; /* UDP */
+  hints.ai_flags = AI_PASSIVE;  /* allow any address of mine */
+
+  /* get server addresses info */
+  if(isNull(udpServerPort=GetConfValue("UdpServerPort"))){
+    err_msg("ERR at %s#%d: no udp server port in conf", __FILE__,__LINE__);
+    return FALSE;
+  }
+  if ( (ret=getaddrinfo(NULL, udpServerPort, &hints, &servinfo)) != 0 ) {
+    err_msg("ERR at %s#%d: getaddrinfo: %s", __FILE__,__LINE__, 
+           gai_strerror(ret));
+    return FALSE;
+  }
+  
+  /* loop through all addresses */
+  FD_ZERO(&fds);
+  for(p = servinfo; p != NULL; p = p->ai_next) {
+
+    /* create socket and bind */
+    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
+      continue;
+    }
+    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+      close(sockfd);
+      continue;
+    }
+    
+    /* if not overflow max, set to select set */
+    if(fdCount<MAXFDCOUNT){
+      EnableAsyncIo(sockfd, handler); /* set async mode */
+      ioctl(sockfd, FIONBIO,&val); /* set non-blocking mode */
+      FD_SET(sockfd, &fds);
+      fdList[fdCount]=sockfd;
+      fdCount++;
+      if(selMax<sockfd) selMax=sockfd;
+    }
+  }
+  
+/* if no fd is set, error */
+  if (fdCount==0) {
+    err_msg("ERR at %s#%d: failed to bind UDP server socket",
+           __FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* remove work area */
+  freeaddrinfo(servinfo);
+  
+  udpPrepared=TRUE;
+  return TRUE;
+}
+
+/***************************************
+get a data from udp port
+non-blocking read
+return=received bytes, 0=no data
+use in polling loop 
+in: buf=buffer, bufLen=buffer length
+out: clientIpAddress=client ip address
+***************************************/
+int getDataFromUdpPort(char* buf, int bufLen, char* clientIpAddress){
+
+  struct timeval timeout={0,0}; /* no wait */
+  int sockfd;
+  struct sockaddr_storage client_addr;
+  socklen_t addr_len;
+  int numbytes;
+  int i;
+
+  if(!udpPrepared) return 0;
+
+  /* select in non-blocking mode */
+  if(select(selMax+1, &fds, NULL, NULL, &timeout)<=0){
+
+    /* if no select, reset fds and exit */ 
+    FD_ZERO(&fds);
+    for(i=0;i<fdCount; i++){
+      FD_SET(fdList[i],&fds);
+    }
+    timeout.tv_sec=0;
+    timeout.tv_usec=0;
+    buf[0]='\0';
+    return 0;
+  }
+
+  /* search data received fd */
+  for(i=0; i<fdCount; i++){
+    if(FD_ISSET(fdList[i], &fds))break;
+  }
+  sockfd=fdList[i];
+    
+  /* receive data */
+  addr_len = sizeof client_addr;
+  if((numbytes = recvfrom(sockfd, buf, bufLen-1 , 0,
+                         (struct sockaddr *)&client_addr, &addr_len)) > 0) {
+    buf[numbytes] = '\0'; /* null char to terminate string */
+    inet_ntop(client_addr.ss_family,
+             get_in_addr((struct sockaddr *)&client_addr), 
+             clientIpAddress, ADDRMAXLN);
+  }
+
+  /* if zero bytes received, clear fd set */
+  else{
+    FD_CLR(sockfd, &fds);
+  }
+
+  /* return received bytes */
+  return numbytes;
+}
+
+/*************************
+ the udp client connected is trusted or not
+*************************/
+int isUdpClientTrusted(char* clientIpAddress){
+
+  char* ipAddressInConf=NULL;
+  int found=FALSE;
+  
+  /* if the address is my local address, return true */
+  if(IsMyIpAddress(clientIpAddress)){
+    found=TRUE;
+  }
+
+  /* if the udp client address is found in conf file, return true */
+  else{
+    ipAddressInConf=GetFirstConfValue("UdpClient");
+    while(!isNull(ipAddressInConf)){
+      if(strcmp(clientIpAddress, ipAddressInConf)==0){
+       found=TRUE;
+       break;
+      }
+      ipAddressInConf=GetNextConfValue();
+    }
+  }
+  if(!found){
+    err_msg("ERR at %s#%d: UDP client [%s] is not found on trusted list in conf file",
+           __FILE__,__LINE__, clientIpAddress);
+  }
+  return found;
+}
+
+/************************************
+is the ip address localhost  
+************************************/
+int isMyIpAddress(char* ipAddress){
+  struct ifaddrs * ifAddrStruct=NULL;
+  struct ifaddrs * ifa=NULL;
+  void * tmpAddrPtr=NULL;
+  char addressBuffer[INET6_ADDRSTRLEN];
+  int result=FALSE;
+  
+  /* get interface addresses */
+  getifaddrs(&ifAddrStruct);
+  
+  /* loop for interface addresses */
+  for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+    
+    /* if a valid IP4 Address */
+    if (ifa ->ifa_addr->sa_family==AF_INET) {
+      
+      /* convert address to display form */
+      tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+      inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
+    } 
+    
+    /* if a valid IP6 Address */
+    else if (ifa->ifa_addr->sa_family==AF_INET6) {
+      
+      /* if link local, remove scope-id in address */
+      struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ifa->ifa_addr;
+      if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
+       addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
+      }
+      
+      /* convert address to display form */
+      tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+      inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
+    }
+      
+    /* compare with arg */
+    if(strcmp(addressBuffer, ipAddress)==0){
+      result=TRUE;
+      break;
+    }
+  }
+  
+  /* clean */
+  if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
+  
+  return result;
+}
+
+/***************************************
+Set a socket as asynchronous IO mode
+***************************************/
+int enableAsyncIo(int sockfd, void (*handler)(int))
+{
+  int flags;
+  struct sigaction sa;
+
+  if(handler==NULL){
+    err_msg("ERR at %s#%d: handler is not set",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  flags = fcntl(sockfd, F_GETFL);
+  fcntl(sockfd, F_SETFL, flags | O_ASYNC); 
+
+  sa.sa_flags = 0;
+  sa.sa_handler = handler;
+  sigemptyset(&sa.sa_mask);
+
+  if (sigaction(SIGIO, &sa, NULL)){
+    err_msg("ERR at %s#%d: sigaction: %s",__FILE__,__LINE__, strerror(errno));
+    exit(0);
+  }
+  if (fcntl(sockfd, F_SETOWN, getpid()) < 0){
+    err_msg("ERR at %s#%d: fcntl: %s",__FILE__,__LINE__, strerror(errno));
+    exit(0);
+  }
+
+  return TRUE;
+}
+
+/**************************
+ *************************/
+
+int PrepareUdpPort(void (*handler)(int)){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>prepareUdpPort( )");
+  ret = prepareUdpPort(handler);
+  if(debug>1) err_msg("DEBUG:(%d)<=prepareUdpPort( )",ret);
+  return ret;
+}
+
+int GetDataFromUdpPort(char* buf, int bufLen, char* clientIpAddress){
+  int ret;
+  if(debug>2) err_msg("DEBUG:=>getDataFromUdpPort(%d)",bufLen);
+  ret = getDataFromUdpPort(buf, bufLen, clientIpAddress);
+  if(debug>2) err_msg("DEBUG:(%d)<=getDataFromUdpPort(%s,%s)",
+                     ret,buf,clientIpAddress);
+  return ret;
+}
+
+int IsUdpClientTrusted(char* clientIpAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isUdpClientTrusted(%s)",clientIpAddress);
+  ret = isUdpClientTrusted(clientIpAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isUdpClientTrusted()", ret);
+  return ret;
+}
+
+int IsMyIpAddress(char* ipAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isMyIpAddress(%s)",ipAddress);
+  ret = isMyIpAddress(ipAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isMyIpAddress()", ret);
+  return ret;
+}
+
+int EnableAsyncIo(int sockfd, void (*handler)(int)){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>enableAsyncIo(%d)",sockfd);
+  ret = enableAsyncIo(sockfd, handler);
+  if(debug>1) err_msg("DEBUG:(%d)<=enableAsyncIo()", ret);
+  return ret;
+}
diff --git a/mdsrc/util.c b/mdsrc/util.c
new file mode 100644 (file)
index 0000000..00597d6
--- /dev/null
@@ -0,0 +1,252 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+
+ module for misc routines
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+
+/******************************/
+/* lock functions using fcntl */
+/******************************/
+int lock(int fd){
+  struct flock lck;
+  
+  lck.l_type=F_WRLCK;
+  lck.l_whence=SEEK_SET;
+  lck.l_start=0;
+  lck.l_len=0;
+  return fcntl(fd, F_SETLKW, &lck);
+}
+  
+/********************************/
+/* unlock functions using fcntl */
+/********************************/
+int unlock(int fd)
+{
+  struct flock lck;
+
+  lck.l_type=F_UNLCK;
+  lck.l_whence=SEEK_SET;
+  lck.l_start=0;
+  lck.l_len=0;
+  return fcntl(fd, F_SETLK, &lck);
+}
+
+/**************************************/
+/* check NULL or point to null string */
+/**************************************/
+int isNull(const char *pStr)
+{
+  if(pStr==NULL) return TRUE;
+  if(*pStr=='\0') return TRUE;
+  return FALSE;
+}
+
+
+
+/**************************************************/
+/* popen with argument list                       */
+/* rootPriv: if 1, run command as root user       */
+/* type : open type "r" or "w"                    */
+/* path : command path to fork/exec               */
+/* ... : command arguments. last must be (char*)0 */
+/*  DO NOT SET [user entered string] in args      */
+/*  to prevent hacking                            */
+/**************************************************/
+FILE *Popenl(int rootPriv, const char *type, const char *path, ...)
+{
+  char commandLine[BUFFMAXLN];
+  va_list     ap;
+  char *pStr;
+  FILE *file;
+
+  /* insert command path */
+  strncpy(commandLine, path, BUFFMAXLN);
+
+  /* insert command arguments */
+  va_start(ap, path);
+  
+  while((pStr=va_arg(ap, char *))!=(char *)0){
+    strcat(commandLine, " ");
+    strncat(commandLine, pStr, BUFFMAXLN);
+  }
+  free(pStr);
+  va_end(ap);
+
+  /* if desired, add root privilege */
+  if(rootPriv==1){
+    if(seteuid(0)!=0){
+      err_msg("ERR at %s#%d: cannot add root privilege ",
+             __FILE__,__LINE__);
+    } 
+  }
+
+  /* open the pipe to the program  */
+  if(debug>1) err_msg("DEBUG:=>popen(%s, %s)", commandLine, type);
+  file=popen(commandLine, type);
+  if(debug>1) err_msg("DEBUG:(%x)<=popen( )",file);  
+
+  /* remove root privilege */
+  seteuid(getuid()); 
+
+  return file;
+}
+
+
+/**************************************************/
+/* system with argument list                      */
+/* rootPriv: if 1, run command as root user       */
+/* path : command path to fork/exec               */
+/* ... : command arguments. last must be (char*)0 */
+/*  DO NOT SET [user entered string] in args      */
+/*  to prevent hacking                            */
+/**************************************************/
+int Systeml(int rootPriv, const char *path, ...)
+{
+  char commandLine[BUFFMAXLN];
+  va_list     ap;
+  char *pStr;
+  int ret;
+
+  /* insert command path */
+  strncpy(commandLine, path, BUFFMAXLN);
+
+  /* insert command arguments */
+  va_start(ap, path);
+  
+  while((pStr=va_arg(ap, char *))!=(char *)0){
+    strcat(commandLine, " ");
+    strncat(commandLine, pStr, BUFFMAXLN);
+  }
+  free(pStr);
+  va_end(ap);
+
+  /* if desired, add root privilege */
+  if(rootPriv==1){
+    if(seteuid(0)!=0){
+      err_msg("ERR at %s#%d: cannot add root privilege ",
+             __FILE__,__LINE__);
+    } 
+  }
+
+  /* execute shell  */
+  if(debug>1) err_msg("DEBUG:=>system(%s)", commandLine);
+  ret=system(commandLine);
+  if(debug>1) err_msg("DEBUG:<=system()");
+
+  /* remove root privilege */
+  seteuid(getuid()); 
+  return ret;
+}
+
+/****************************************/
+/****************************************/
+int Pclose(FILE *stream)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>pclose( )");
+  ret = pclose(stream);
+  if(debug>1) err_msg("DEBUG:<=pclose( )");  
+
+  return ret;
+}
+
+
+int Lock(int fd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>lock( )");
+  ret=lock(fd);
+  if(debug>1) err_msg("DEBUG:(%d)<=lock( )",ret);
+
+  return ret;
+}
+
+
+int Unlock(int fd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>unlock( )");
+  ret=unlock(fd);
+  if(debug>1) err_msg("DEBUG:(%d)<=unlock( )",ret);
+
+  return ret;
+}
+
+
+int
+Open(const char *pathname, int oflag, mode_t mode)
+{
+       int             fd;
+
+       if ( (fd = open(pathname, oflag, mode)) == -1)
+               err_msg("open error for %s", pathname);
+       return(fd);
+}
+
+int
+Close(int fd)
+{
+  int ret;
+
+  /*if( (ret=close(fd)) == -1)
+   *  err_msg("close error");
+   */
+
+  ret=close(fd);
+
+  return ret;
+}
+
+pid_t
+Fork(void)
+{
+       pid_t   pid;
+
+       if ( (pid = fork()) == -1)
+               err_msg("fork error");
+       return(pid);
+}
+
+int
+Pipe(int *fds)
+{
+  int ret;
+       if ((ret=pipe(fds)) < 0)
+               err_msg("pipe error");
+
+       return ret;
+}
+
+void *
+Malloc(size_t size)
+{
+       void    *ptr;
+
+       if ( (ptr = malloc(size)) == NULL)
+               err_msg("malloc error");
+       return(ptr);
+}
+
diff --git a/mdsrc/workdb.c b/mdsrc/workdb.c
new file mode 100644 (file)
index 0000000..661daac
--- /dev/null
@@ -0,0 +1,561 @@
+/**************************************************
+OpengateM - a MAC address authentication system
+   module for local work database
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemd.h"
+#include <sqlite3.h>
+
+static int sqliteBusyTimeout=100;  /* value used in sqite3_busy_timeout() */
+static sqlite3 *dbMd; /* handle for opengatemd.db */
+
+/*******************************************************************
+ read sqlite busy timeout value from conf and set to static variable
+*******************************************************************/
+int setupSqliteBusyTimeoutValue(void){
+
+  char *str;
+  
+  /* if set in conf, use the value. if not, use the above default. */
+  str=GetConfValue("SqliteBusyTimeout");
+  if(str!=NULL) sqliteBusyTimeout=atoi(str);
+
+  return sqliteBusyTimeout;
+}
+
+/********************************************
+initialize work db implemented with sqlite
+********************************************/
+int initWorkDb(void){
+
+  char *pErrMsg=NULL;
+
+  /* SQL CREATE COMMAND */
+  char *createCmd1="CREATE TABLE IF NOT EXISTS sessionmd "
+    "(macAddress TEXT PRIMARY KEY, "
+    "userId TEXT, extraId TEXT, openTime INTEGER, checkTime INTEGER, "
+    "ipAddress TEXT, ruleNumber INTEGER)";
+  char *createCmd2="CREATE TABLE IF NOT EXISTS macinfo "
+    "(macAddress TEXT PRIMARY KEY ON CONFLICT REPLACE, "
+    "detectTime INTEGER, ttl INTEGER, isNat INTEGER)";
+
+  /* setup static variable value for SqLite3_busy_timeout from conf */
+  SetupSqliteBusyTimeoutValue();
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMd"),&dbMd)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(dbMd, sqliteBusyTimeout);
+
+  /* create table1 */
+  if(sqlite3_exec(dbMd, createCmd1, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  /* create table2 */
+  if(sqlite3_exec(dbMd, createCmd2, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  return TRUE;
+}
+
+/********************************************
+finalize work db implemented with sqlite
+********************************************/
+int finalizeWorkDb(void){
+
+  /* Close db for opengatemd */
+  sqlite3_close(dbMd);
+
+  return TRUE;
+}
+
+/************************************************************
+ insert session info to db at start     
+************************************************************/
+int insertSessionToWorkDb(char* macAddress, char* userId, char* extraId, 
+                       char* ipAddress, int ruleNumber){
+
+  int rc;
+  char *pErrMsg=NULL;
+
+  /* SQL INSERT COMMAND, where %x is replaced in snprintf */
+  char *insertFormat="INSERT INTO sessionmd "
+    "(macAddress, userId, extraId, openTime, checkTime, ipAddress, ruleNumber) "
+    "values ('%s','%s','%s', %d, %d,'%s', %d)";
+  char *insertCmd;
+  int resultFlag=TRUE;
+
+  /* Prepare insert command */
+  insertCmd=sqlite3_mprintf(insertFormat, macAddress, userId,extraId, 
+                           time(NULL), time(NULL), ipAddress, ruleNumber);
+
+  /* Execute insert to sqlite */
+  if((rc=sqlite3_exec(dbMd, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  /*Memory free for sqlite3 string */
+  sqlite3_free(insertCmd);
+
+  return resultFlag;
+}
+
+/*************************************************************
+ update checkTime to time now
+*************************************************************/
+int updateCheckTimeInWorkDb(char* macAddress){
+
+  char *pErrMsg=NULL;
+
+  /* SQL UPDATE COMMAND, where %x is replaced in mprintf */
+  char *updateFormat="UPDATE sessionmd "
+    "SET checkTime=%d WHERE macAddress='%s'";
+  char *updateCmd;
+  int resultFlag=TRUE;
+
+  /* prepare command */
+  updateCmd=sqlite3_mprintf(updateFormat, time(NULL), macAddress);
+
+  /* execute update to sqlite */
+  if(sqlite3_exec(dbMd, updateCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  /*memory free for sqlite3 string */
+  sqlite3_free(updateCmd);
+
+  return resultFlag;
+}
+
+/*************************************************************
+ delete session info to db at stop     
+*************************************************************/
+int delSessionFromWorkDb(char* macAddress){
+
+  char *pErrMsg=NULL;
+
+  /* SQL DELETE COMMAND, where %x is replaced in mprintf */
+  char *deleteFormat="DELETE FROM sessionmd WHERE macAddress='%s'";
+  char *deleteCmd;
+  int resultFlag=TRUE;
+
+  /* prepare command */
+  deleteCmd=sqlite3_mprintf(deleteFormat, macAddress);
+
+  /* execute delete */
+  if(sqlite3_exec(dbMd, deleteCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  /*memory free for sqlite3 string */
+  sqlite3_free(deleteCmd);
+
+  return TRUE;
+}
+
+/************************************************
+ get info for active session about ip addr from db  
+input = macAddress, output = others
+*************************************************/
+int getSessionFromWorkDb(char* macAddress, char* userId, char* extraId, 
+                        int* openTime, int* checkTime, char *ipAddress,
+                        int* ruleNumber){
+
+  sqlite3_stmt *stmt;
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char *selectFormat="SELECT userId, extraId, openTime, checkTime, "
+    "ipAddress, ruleNumber FROM sessionmd WHERE macAddress='%s'";
+  char *selectCmd;
+  int resultFlag=TRUE;
+
+  /* prepare command string */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+  
+  /* compile to internal statement */
+  if(sqlite3_prepare(dbMd, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+
+    return FALSE;
+  }
+
+  /* get first record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(userId, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
+    strncpy(extraId, (char*)sqlite3_column_text(stmt, 1), USERMAXLN);
+    *openTime=(int)sqlite3_column_int(stmt, 2);
+    *checkTime=(int)sqlite3_column_int(stmt, 3);
+    strncpy(ipAddress, (char*)sqlite3_column_text(stmt, 4), ADDRMAXLN);
+    *ruleNumber=(int)sqlite3_column_int(stmt, 5);
+    resultFlag=TRUE;
+  }else{
+    userId[0]='\0';
+    extraId[0]='\0';
+    *openTime=0;
+    *checkTime=0;
+    ipAddress[0]='\0';
+    *ruleNumber=0;
+    resultFlag=FALSE;
+  }
+
+  /* finalize */
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  
+  return resultFlag;
+}
+
+
+/************************************************
+ close session that exceed time limit  
+ 1. select the record to close firewall 
+ 2. delete the record
+if delayed=FALSE, close all sessions without delay 
+*************************************************/
+int delUselessSessionsInWorkDb(int delayed){
+
+  char *pErrMsg=NULL;
+  int uselessLimitTime;
+
+  /* the session is useless, if it doesn't update after this time */
+  uselessLimitTime = time(NULL)-atoi(GetConfValue("UselessTimeout"));
+  /* if delayed is false, all sessions(before now) are deleted */
+  if(!delayed) uselessLimitTime = time(NULL);
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char *selectFormat="SELECT ruleNumber, userId, extraId, ipAddress, "
+    "macAddress, openTime FROM sessionmd WHERE checkTime<%d";
+  char *deleteFormat="DELETE FROM sessionmd WHERE checkTime<%d";
+  char *selectCmd;
+  char *deleteCmd;
+  int resultFlag=TRUE;
+
+  /* prepare command string for select */
+  selectCmd=sqlite3_mprintf(selectFormat, uselessLimitTime);
+
+  /* exec command, callback function = CloseSession */
+  if(sqlite3_exec(dbMd, selectCmd, CloseSession, NULL, &pErrMsg)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite_exec:%s",__FILE__,__LINE__, pErrMsg);
+  }
+
+  /* prepare command string for update */
+  deleteCmd=sqlite3_mprintf(deleteFormat, uselessLimitTime);
+
+  /* exec command  */
+  if(sqlite3_exec(dbMd, deleteCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite_exec:%s",__FILE__,__LINE__, pErrMsg);
+  }
+    
+  /* finalize */
+  sqlite3_free(selectCmd);
+  sqlite3_free(deleteCmd);
+
+  return resultFlag;
+}
+
+/************************************************
+get list of sessions from DB and create hash table
+for opengatemd 
+ key=macAddress, value=0 
+*************************************************/
+int getSessionTableFromWorkDb(DB* sessionTable){
+  DBT hashKey;
+  DBT hashVal;
+  sqlite3_stmt *stmt=NULL;
+  int resultFlag=FALSE;
+  char macAddress[ADDRMAXLN];
+  int zero=0;
+  /* SQL SELECT COMMAND to get all mac address in session table */
+  char *selectCmd="SELECT macAddress FROM sessionmd";
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(dbMd, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+
+    /* finalize */
+    sqlite3_finalize(stmt);
+    return FALSE;
+  }
+
+  /* get result rows */
+  while(sqlite3_step(stmt)==SQLITE_ROW){
+    resultFlag=TRUE;
+    strncpy(macAddress,(char*)sqlite3_column_text(stmt, 0), ADDRMAXLN);
+
+    /* put to hash table */
+    hashVal.data = &zero;
+    hashVal.size = sizeof(int);    
+    hashKey.data = macAddress;
+    hashKey.size = strlen(macAddress)+1;
+    if(sessionTable->put(sessionTable, &hashKey, &hashVal, 0) == -1) {
+      err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+    }
+  }
+
+  /* finalize */
+  sqlite3_finalize(stmt);
+
+  return resultFlag;
+}
+
+
+/**********************************
+ put out detected mac info to macinfo table in work db
+for checking nat 
+**********************************/
+int putMacInfoToWorkDb(char* macAddress, int ttl, int isNat){
+
+  int rc;
+  char *pErrMsg=NULL;
+
+  /* SQL INSERT COMMAND, where %x is replaced in snprintf */
+  char *insertFormat="INSERT INTO macinfo "
+    "(macAddress, detectTime, ttl, isNat) "
+    "values ('%s', %d, %d, %d)";
+  char *insertCmd;
+  int resultFlag=TRUE;
+
+  /* Prepare insert command */
+  insertCmd=sqlite3_mprintf(insertFormat, macAddress, time(NULL), ttl, isNat);
+
+  /* Execute insert to sqlite */
+  if((rc=sqlite3_exec(dbMd, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  /*Memory free for sqlite3 string */
+  sqlite3_free(insertCmd);
+
+  return resultFlag;
+}
+
+
+/**********************************
+ get mac info from macinfo table in work db 
+**********************************/
+int getMacInfoFromWorkDb(char* macAddress, char* detectTimeStr, int* pTtl){
+
+  sqlite3_stmt *stmt;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char *selectFormat="SELECT datetime(detectTime,'unixepoch','localtime'), "
+    " ttl FROM macinfo WHERE macAddress='%s' ";
+  char *selectCmd;
+  int resultFlag=TRUE;
+
+  /* set default value */
+  *pTtl=0;
+  detectTimeStr[0]='?';
+  detectTimeStr[1]='\0';
+
+  /* Prepare select command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(dbMd, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    return FALSE;
+  }
+
+  /* get first record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(detectTimeStr, (char*)sqlite3_column_text(stmt, 0), WORDMAXLN);
+    *pTtl=(int)sqlite3_column_int(stmt, 1);
+    resultFlag=TRUE;
+  }else{
+    resultFlag=FALSE;
+  }
+
+  /* finalize */
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  return resultFlag;
+}
+
+/************************************
+is the rule number active in opengatemd session table
+************************************/
+int isActiveRuleInWorkDb(int ruleNumber){
+
+  sqlite3_stmt *stmt;
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char *selectFormat="SELECT * FROM sessionmd "
+    " WHERE ruleNumber=%d";
+  char *selectCmd;
+  int resultFlag=TRUE;
+
+  /* prepare command string */
+  selectCmd=sqlite3_mprintf(selectFormat, ruleNumber);
+  
+  /* compile to internal statement */
+  if(sqlite3_prepare(dbMd, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    return FALSE;
+  }
+
+  /* get first record */
+  if(sqlite3_step(stmt)==SQLITE_ROW) resultFlag=TRUE;
+  else resultFlag=FALSE;
+
+  /* finalize */
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  return resultFlag;
+}
+
+
+
+/*********************************************************
+ routines for debugging output
+*********************************************************/
+int SetupSqliteBusyTimeoutValue(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>setupSqliteBusyTimeoutValue()");
+  ret=setupSqliteBusyTimeoutValue();
+  if(debug>1) err_msg("DEBUG:(%d)<=setupSqliteBusyTimeoutValue()",ret);
+  return ret;
+}
+
+int InitWorkDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initWorkDb( )");
+  ret = initWorkDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=initWorkDb( )",ret);
+  return ret;
+}
+
+int FinalizeWorkDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>finalizeWorkDb( )");
+  ret = finalizeWorkDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=finalizeWorkDb( )",ret);
+  return ret;
+}
+
+int InsertSessionToWorkDb(char* macAddress, char* userId, char* extraId, 
+                       char* ipAddress, int ruleNumber){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>insertSessionToWorkDb(%s,%s,%s,%s,%d)",
+                     macAddress, userId, extraId, ipAddress, ruleNumber);
+  ret = insertSessionToWorkDb(macAddress, userId, extraId, ipAddress, ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=insertSessionToWorkDb( )",ret);
+  return ret;
+}
+
+int UpdateCheckTimeInWorkDb(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>updateCheckTimeInWorkDb(%s)", macAddress);
+  ret = updateCheckTimeInWorkDb(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=updateCheckTimeInWorkDb( )",ret);
+  return ret;
+}
+
+int DelSessionFromWorkDb(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delSessionFromWorkDb(%s)", macAddress);
+  ret = delSessionFromWorkDb(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=delSessionFromWorkDb( )",ret);
+  return ret;
+}
+
+int GetSessionFromWorkDb(char* macAddress, char* userId, char* extraId, 
+                        int* openTime, int* checkTime, char *ipAddress,
+                        int* ruleNumber){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getSessionFromWorkDb(%s)", macAddress);
+  ret = getSessionFromWorkDb(macAddress, userId, extraId, openTime, 
+                              checkTime, ipAddress, ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=getSessionFromWorkDb(,%s,%s,%d,%d,%s,%d)",
+                     ret,userId,extraId,*openTime,*checkTime,ipAddress,
+                     *ruleNumber);
+  return ret;
+}
+
+int DelUselessSessionsInWorkDb(int delayed){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delUselessSessionsInWorkDb(%d)", delayed);
+  ret=delUselessSessionsInWorkDb(delayed);
+  if(debug>1) err_msg("DEBUG:(%d)<=delUselessSessionsInWorkDb( )",ret);
+  return ret;
+}
+
+int GetSessionTableFromWorkDb(DB* sessionTable){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getSessionTableFromWorkDb( )");
+  ret=getSessionTableFromWorkDb(sessionTable);
+  if(debug>1) err_msg("DEBUG:(%d)<=getSessionTableFromWorkDb( )", ret);
+  return ret;
+}
+
+int PutMacInfoToWorkDb(char* macAddress, int ttl, int isNat){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putMacInfoToWorkDb(%s,%d,%d)",macAddress,ttl,isNat);
+  ret=putMacInfoToWorkDb(macAddress,ttl,isNat);
+  if(debug>1) err_msg("DEBUG:(%d)<=putMacInfoToWorkDb( )", ret);
+  return ret;
+}
+
+int IsActiveRuleInWorkDb(int ruleNumber){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isActiveRuleInWorkDb(%d)",ruleNumber);
+  ret=isActiveRuleInWorkDb(ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=isActiveRuleInWorkDb( )", ret);
+  return ret;
+}
+
+int GetMacInfoFromWorkDb(char* macAddress, char* detectTimeStr, int* pTtl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getMacInfoFromWorkDb(%s)", macAddress);
+  ret = getMacInfoFromWorkDb(macAddress, detectTimeStr, pTtl);
+  if(debug>1) err_msg("DEBUG:(%d)<=getMacInfoFromWorkDb(,%s,%d)",
+                     ret, detectTimeStr, *pTtl);
+  return ret;
+}
diff --git a/mngsrc/Makefile b/mngsrc/Makefile
new file mode 100644 (file)
index 0000000..a10a9dd
--- /dev/null
@@ -0,0 +1,228 @@
+################ Change following ########################
+##  some other parameters exist in opengatemmng.h  ########
+##########################################################
+CONFIGPATH = /etc/opengate        ## directory of config file
+WWWTOP = /usr/local/www/apache22  ## apache directory top
+DOCDIR = /data                   ## apache data directory(related to wwwtop)
+CGIDIR = /cgi-bin                ## apache cgi directory(related to wwtop)
+OPENGATEDIR = /opengate                  ## opengate web directory(related to docdir)
+
+DOCUMENTROOT = ${WWWTOP}${DOCDIR}
+INSTALLDOCPATH = ${WWWTOP}${DOCDIR}${OPENGATEDIR}
+INSTALLCGIPATH = ${WWWTOP}${CGIDIR}${OPENGATEDIR}
+INSTALLBINPATH = /usr/local/bin   ## install dir of executable file
+MAKEDIR != pwd                 ## save present directory
+
+.if exists(/usr/local/include/mysql)
+CFLAGSMYSQL = -I/usr/local/include/mysql -pipe -fno-strict-aliasing
+LIBMYSQL = -L/usr/local/lib/mysql -lmysqlclient  -pthread -lz -lm
+.endif
+
+.if exists(/usr/local/include/sqlite3.h)
+LIBSQLITE = -lsqlite3 -lpthread
+.endif
+
+.if exists(/usr/local/include/ldap.h)
+LIBLDAP = -lldap -llber
+.endif
+
+## This is memory leak check tool for debugging
+#LIBCCMALLOC = -lccmalloc -L/usr/local/lib
+
+CFLAGS= -g -O4 -Wall -I/usr/local/include ${CFLAGSMYSQL}
+
+LIBS = -lezxml -lssl -lcrypto -lradius -lpam -L../ezxml -L/usr/local/lib ${LIBLDAP} ${LIBSQLITE} ${LIBMYSQL} ${LIBCCMALLOC}
+
+OBJS = util.o error.o getparam.o managementdb.o workdb.c getmac.o cgi.o messages.o queue.o ipfw.o proc.o auth.o auth-pam.o auth-ftps.o auth-pop3s.o auth-rad.o auth-ldap.o alarms.o udpcli.o
+HDRS = opengatemmng.h
+
+CHKPROGO = opengatemchk.o
+CHKPROG = opengatemchk
+REGPROGO = opengatemreg.o
+REGPROG = opengatemreg
+UPPROGO = opengatemup.o
+UPPROG = opengatemup
+MAILPROGO = opengatemmail.o
+MAILPROG = opengatemmail
+OWNPROGO = opengatemown.o
+OWNPROG = opengatemown
+FWDPROGO = opengatemfwd.o
+FWDPROG = opengatemfwd
+
+LIBOPT = ezxml
+
+CLEANFILES = *.o *~ *.core a.out \\#*
+
+all:           ${CHKPROG} ${REGPROG} ${UPPROG} ${OWNPROG} ${MAILPROG} ${FWDPROG} ${LIBOPT}
+
+opengatemchk:  ${OBJS} ${CHKPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${CHKPROGO} ${LIBS}
+
+opengatemreg:  ${OBJS} ${REGPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${REGPROGO} ${LIBS}
+
+opengatemup:   ${OBJS} ${UPPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${UPPROGO} ${LIBS}
+
+opengatemmail: ${OBJS} ${MAILPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${MAILPROGO} ${LIBS}
+
+opengatemown:  ${OBJS} ${OWNPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${OWNPROGO} ${LIBS}
+
+opengatemfwd:  ${OBJS} ${FWDPROGO} ${LIBOPT}
+               ${CC} ${CFLAGS} -o $@ ${OBJS} ${FWDPROGO} ${LIBS}
+
+ezxml: 
+               ${MAKE} -C ../ezxml
+
+clean:
+               rm -f ${CHKPROG} ${REGPROG} ${UPPROG} ${OWNPROG} ${FWDPROG} ${MAILPROG} ${CLEANFILES}
+               ${MAKE} clean -C ../ezxml
+               rm -f ../*/*~  ../*~ ../*/*/*~
+
+# install mac registration and upating systems
+install:       install-chkcgi install-regcgi install-upcgi install-owncgi install-fwdcgi install-mailbin install-conf install-html
+
+#install only mac registration system
+installmreg:   install-chkcgi install-regcgi install-conf install-html
+
+#install only mac updating system
+installmup:    install-upcgi install-mailbin install-conf install-html
+
+#install only mac reg/update by owner oneself
+installmown:   install-owncgi install-fwdcgi install-mailbin install-conf install-html
+
+install-chkcgi:        ${CHKPROG}
+               ## Copy CGI program and Set S bit ##
+.if !exists(${INSTALLCGIPATH})
+               mkdir ${INSTALLCGIPATH}
+.endif
+               cp ${CHKPROG} ${INSTALLCGIPATH}/${CHKPROG}.cgi
+               chmod 4755 ${INSTALLCGIPATH}/${CHKPROG}.cgi
+
+install-regcgi:        ${REGPROG}
+               ## Copy CGI program and Set S bit ##
+.if !exists(${INSTALLCGIPATH})
+               mkdir ${INSTALLCGIPATH}
+.endif
+               cp ${REGPROG} ${INSTALLCGIPATH}/${REGPROG}.cgi
+               chmod 4755 ${INSTALLCGIPATH}/${REGPROG}.cgi
+
+install-upcgi: ${UPPROG}
+               ## Copy CGI program and Set S bit ##
+.if !exists(${INSTALLCGIPATH})
+               mkdir ${INSTALLCGIPATH}
+.endif
+               cp ${UPPROG} ${INSTALLCGIPATH}/${UPPROG}.cgi
+               chmod 4755 ${INSTALLCGIPATH}/${UPPROG}.cgi
+
+install-owncgi:        ${OWNPROG}
+               ## Copy CGI program and Set S bit ##
+.if !exists(${INSTALLCGIPATH})
+               mkdir ${INSTALLCGIPATH}
+.endif
+               cp ${OWNPROG} ${INSTALLCGIPATH}/${OWNPROG}.cgi
+               chmod 4755 ${INSTALLCGIPATH}/${OWNPROG}.cgi
+
+install-fwdcgi:        ${FWDPROG}
+               ## Copy CGI program and Set S bit ##
+.if !exists(${INSTALLCGIPATH})
+               mkdir ${INSTALLCGIPATH}
+.endif
+               cp ${FWDPROG} ${INSTALLCGIPATH}/${FWDPROG}.cgi
+               chmod 4755 ${INSTALLCGIPATH}/${FWDPROG}.cgi
+
+install-mailbin:       ${MAILPROG}
+.if !exists(${INSTALLBINPATH})
+               mkdir ${INSTALLBINPATH}
+.endif
+               cp ${MAILPROG} ${INSTALLBINPATH}/${MAILPROG}
+               chmod 4755 ${INSTALLBINPATH}/${MAILPROG}
+
+install-html:
+               ## Copy HTML documents and etc ##
+.if !exists(${INSTALLDOCPATH})
+               mkdir ${INSTALLDOCPATH}
+.endif
+               cp -R ../html/* ${INSTALLDOCPATH}
+               mv ${INSTALLDOCPATH}/index.html.var ${DOCUMENTROOT}/index.html.var.opengatem
+
+install-conf:
+               ## Copy Config files ##
+.if !exists(${CONFIGPATH})
+               mkdir ${CONFIGPATH}
+.endif
+               cp  ../conf/opengatemmng.conf.sample ${CONFIGPATH}
+               cp  ../conf/warningmail.sample ${CONFIGPATH}
+               #
+               #-------------------------------------------------------#
+               # COPY xx.conf.sample to xx and EDIT it.                #
+               #  Eg. 'cp opengatemmng.conf.sample  opengatemmng.conf' #
+               #      'vi opengatemmng.conf'                           #
+               #-------------------------------------------------------#
+
+opengatemchk.o:        ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+opengatemreg.o:        ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+opengatemup.o: ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+opengatemmail.o:       ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+opengatemown.o:        ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+opengatemfwd.o:        ${HDRS}
+               ${CC} ${CFLAGS} -DMAKEDIR='"${MAKEDIR}"' -c $<
+
+util.o:                ${HDRS}
+
+mamagementdb.o:        ${HDRS}
+.if !exists(/usr/local/include/mysql)
+               ${CC} ${CFLAGS} -DMYSQL_NOT_INSTALLED -c $<
+.endif
+
+workdb.o:      ${HDRS}
+.if !exists(/usr/local/include/sqlite3.h)
+               ${CC} ${CFLAGS} -DSQLITE3_NOT_INSTALLED -c $<
+.endif
+
+error.o:       ${HDRS}
+
+getparam.o:    ${HDRS}
+
+messages.o:    ${HDRS}
+
+cgi.o:         ${HDRS}
+
+getmac.o:      ${HDRS}
+
+queue.o:       ${HDRS}
+
+ipfw.o:                ${HDRS}
+
+proc.o:                ${HDRS}
+
+auth.o:                ${HDRS}
+
+auth-pam.o:    ${HDRS}
+
+auth-ftps.o:   ${HDRS}
+
+auth-pop3s.o:  ${HDRS}
+
+auth-rad.o:    ${HDRS}
+
+auth-ldap.o:   ${HDRS}
+.if !exists(/usr/local/include/ldap.h)
+               ${CC} ${CFLAGS} -DLDAP_NOT_INSTALLED -c $<
+.endif
+
+alarms.o:      ${HDRS}
+
+udpcli.o:      ${HDRS}
diff --git a/mngsrc/alarms.c b/mngsrc/alarms.c
new file mode 100644 (file)
index 0000000..4b3fb7d
--- /dev/null
@@ -0,0 +1,359 @@
+/*************************************************
+OpengateM - MAC address authentication system 
+  module for multi-alarms 
+
+Copyright (C) 2006 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+typedef struct alarm{ /* an item in the alarm list */
+  char name[WORDMAXLN]; /* the alarm name */
+  int timeout;          /* the duration(sec) to timeout */
+  int unixtime;         /* the unix time to timeout */
+  int preceding;         /* if true, precede to other alarms */
+  Sigfunc *func;       /* function to call at timeout */
+  struct alarm *next;  /* the next item in list */
+} Alarm;
+
+int addAlarm(char *name, int timeout, int preceding, Sigfunc *func);
+int removeAlarm(char *name);
+int delAlarmListItem(Alarm *pDel);
+int enableAlarm(void);
+int disableAlarm(void);
+void alarmSigFunc(int signo);
+
+static Sigfunc *defaultSigfunc;
+static Alarm *pRunningAlarm=NULL;
+static Alarm *pAlarmTop=NULL;
+
+/*** alarms example ****
+This case, the alarms are ringed after 5 and 8 seconds
+
+int main(void)
+{
+  AddAlarm("alarm1", 8, FALSE, func1);
+  AddAlarm("alarm2", 5, FALSE, func2);
+  EnableAlarm();
+ }
+void func1(int signo){
+  printf("func1 is called at %d\n",time(NULL));
+}
+void func2(int signo){
+  printf("func2 is called at %d\n",time(NULL));
+}
+**********/
+
+/***************************************************
+Add a new alarm named <name>, which calls 
+function <func> after <timeout> seconds
+If <preceding> is TRUE, the alarm precedes to other alarms
+(the alarm has first priority. other alarms are delayed after the alarm)
+Multiple alarms can be registered in the alarm list
+At timeout, the alarm is removed from the alarm list
+after the calling addAlarm, alarms are disabled
+***************************************************/
+int addAlarm(char *name, int timeout, int preceding, Sigfunc *func)
+{
+  Alarm *pNew;
+  Alarm *p;
+  Alarm *pPrev;
+
+  /* disable Alarm */
+  disableAlarm();
+
+  /* memory allocate for the alarm list item */
+  if((pNew = (Alarm *) malloc(sizeof(Alarm))) == NULL){
+    //   err_msg("ERR at %s#%d: malloc error",__FILE__,__LINE__);
+    return -1;
+  }
+
+  /* set the item info */
+  strncpy(pNew->name, name, WORDMAXLN);
+  pNew->timeout = timeout;
+  pNew->unixtime = time(NULL) + timeout;
+  pNew->preceding = preceding;
+  pNew->func = func;
+  
+  /* if list is null, add as first item */
+  if(pAlarmTop ==NULL){
+    pAlarmTop = pNew;
+    pNew->next =NULL;
+  }
+
+  /* if preceding alarm, insert it at the top */
+  else if(preceding==TRUE){
+    pNew->next =pAlarmTop;
+    pAlarmTop = pNew;
+  }
+
+  /* if list is not null, search the item later than the new alarm 
+     and not a preceding alarm */
+  else{
+    p = pPrev = pAlarmTop;
+    while(p!=NULL){
+      if(p->unixtime >= pNew->unixtime && (p->preceding)==FALSE) break;
+      pPrev = p;
+      p = p->next;
+    }
+    
+    /* insert new item before the item */
+    if(p==pAlarmTop) pAlarmTop = pNew;
+    else pPrev->next = pNew;
+    pNew->next = p;
+  }
+
+  return 0;
+}
+
+/***************************************************
+Remove alarm named <name> from the alarm list 
+after the calling removeAlarm, alarms are disabled
+***************************************************/
+int removeAlarm(char *name)
+{
+  Alarm *p, *pPrev, *pDel;
+
+
+  /* disable alarm */
+  disableAlarm();
+
+  p=pAlarmTop;
+
+  if(name==NULL){
+    /* if name is NULL, all items are removed */
+    while(p!=NULL){
+      pDel = p;
+      p = p->next;
+      free(pDel);
+    }
+    pAlarmTop=NULL;
+  }
+
+  else{
+    /* scan alarm list to search name and delete it */
+    while(p!=NULL){
+      
+      /* if name is matched */
+      if(strncmp(name, p->name, WORDMAXLN)==0){
+       
+       /* delete the item */
+       delAlarmListItem(p);
+
+       /* exit (only the first match item is deleted)  */
+       break;
+      }
+      
+      /* if not matched, move to next item */
+      else{
+       pPrev = p;
+       p = p->next;
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+/***************************************************
+Enable alarm interupt
+Delayed alarms by preceding alarm or by disable-mode 
+are executed in this timing
+***************************************************/
+int enableAlarm(void)
+{
+  Alarm *p, *pDel;
+  int alarmemain=0;
+  int alarmSet=FALSE;
+
+  p=pAlarmTop;
+
+  /* scan all list */
+  while(p!=NULL){
+    
+    /* time remain to the timeout */
+    alarmemain = p->unixtime - time(NULL);
+    
+    /* if the time is the past */
+    if(alarmemain<=0){
+      
+      /* execute the function and save item for deletion */
+      p->func(0);
+      pDel = p;
+      
+      /* move to next item */
+      p = p->next;
+      
+      /* delete the list item */
+      delAlarmListItem(pDel);
+    }
+    
+    /* if the time is the future */
+    else{
+      /* save the alarm info */
+      pRunningAlarm = p;
+      
+      /* set signal alarm */
+      if(defaultSigfunc==NULL)defaultSigfunc=signal(SIGALRM, alarmSigFunc);
+      else signal(SIGALRM, alarmSigFunc);
+      alarm(alarmemain);
+      alarmSet=TRUE;
+
+      /* exit */
+      break;
+    }
+  }
+  return 0;
+}
+
+
+/***************************************************
+Disable alarm interupt
+Time count is not stoped in disable mode
+***************************************************/
+int disableAlarm(void)
+{
+  /* reset alarm */
+  signal(SIGALRM, defaultSigfunc);
+  alarm(0);
+
+  return 0;
+}
+
+/***************************************************
+Signal function for alarm signal
+***************************************************/
+void alarmSigFunc(int signo)
+{
+  /* some alarm must run at this point, but check it */
+  if(pRunningAlarm != NULL){
+
+    /* execute the function */
+    (pRunningAlarm->func)(signo);
+
+    /* remove the alarm */
+    delAlarmListItem(pRunningAlarm);
+  }
+
+  /* restart alarm */
+  enableAlarm();
+}
+
+/***************************************************
+delete an item pointed by <p> in linked list
+***************************************************/
+int delAlarmListItem(Alarm *pDel){
+  Alarm *p;
+  Alarm *pPrev;
+
+  /* if the item is none, no proc */
+  if(pDel==NULL){
+    /* no proc */
+  }
+
+  /* if the item is top, change top to the next */
+  else if(pDel==pAlarmTop){
+    pAlarmTop = pDel->next;
+    free(pDel);
+  }
+
+  /* if the item is not top, search previous and link it to next */
+  else{
+    pPrev=pAlarmTop;
+    p=pAlarmTop->next;
+
+    while(p!=NULL){
+      if(p == pDel){
+       pPrev->next = p->next;
+       free(p);
+       break;
+      }
+      pPrev=p;
+      p=p->next;
+    }
+  }
+  return 0;
+}
+
+/***************************************************
+list up registered alarms
+upper alarm in the list has higher priority 
+this is prepared for debug use
+***************************************************/
+void listAlarm(void)
+{
+  Alarm *p;
+
+  printf("TimeNow=%d\n",(int)time(NULL));
+
+  p=pAlarmTop;
+
+  while(p!=NULL){
+    printf("name=%s timeout=%d unixtime=%d preceding=%d\n", 
+          p->name, p->timeout, p->unixtime, p->preceding);
+    p=p->next;
+  }
+}
+/*****************************************************/
+/*****************************************************/
+int AddAlarm(char *name, int timeout, int preceding, Sigfunc *func){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>addAlarm(%s,%d, %d, %x)", 
+                   name, timeout, preceding, func);
+  ret=addAlarm(name, timeout, preceding, func);
+  if(debug>1) err_msg("DEBUG:(%d)<=addAlarm( )",ret);
+
+  return ret;
+}
+
+int RemoveAlarm(char *name){
+  int ret;
+
+  if(debug>1){
+    if(name==NULL) err_msg("DEBUG:=>removeAlarm(NULL)");
+    else           err_msg("DEBUG:=>removeAlarm(%s)", name);
+  }
+  ret=removeAlarm(name);
+  if(debug>1) err_msg("DEBUG:(%d)<=removeAlarm( )",ret);
+
+  return ret;
+}
+
+int EnableAlarm(void){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>enableAlarm()");
+  ret=enableAlarm();
+  if(debug>1) err_msg("DEBUG:(%d)<=enableAlarm( )",ret);
+
+  return ret;
+}
+
+int DisableAlarm(void){
+  int ret;
+
+  //  if(debug>1) err_msg("DEBUG:=>disableAlarm()");
+  ret=disableAlarm();
+  //  if(debug>1) err_msg("DEBUG:(%d)<=disableAlarm( )",ret);
+
+  return ret;
+}
diff --git a/mngsrc/auth-ftps.c b/mngsrc/auth-ftps.c
new file mode 100644 (file)
index 0000000..5cdb286
--- /dev/null
@@ -0,0 +1,339 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication by FTPS
+       (Explicit and Implicit modes)
+
+Copyright (C) 2006 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+/*
+  Thanks to programs and documentations refered.
+   Sample client application cli.cpp found in the OpenSSL site 
+    (developed by Sampo Kellomaki and simplified by Wade Scholine) 
+   Apache module mod_auth_pam.c by Ingo Luetkebohle
+*/
+
+#include "opengatemmng.h"
+
+/*****************************************/
+/* Auth by FTP on SSL - Explicit Mode    */
+/*****************************************/
+int authFtpse(char *userid, char *passwd)
+{
+  int          sockfd, n;
+  char         recvline[BUFFMAXLN];
+  int           authResult;
+  char* serverAddr; /* auth server address */
+  char* port;      /* auth server port */
+  SSL_CTX    *ctx;
+  SSL        *ssl;
+  SSL_METHOD *meth;
+
+  /* get auth server address */
+  serverAddr=GetConfValue("AuthServer/Address");
+
+  if(isNull(serverAddr)){
+    err_msg("ERR at %s#%d: Missing address for FTP server in config",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get auth server port */
+  port=GetConfValue("AuthServer/Port");
+
+  /* FTP server connect */
+  if(isNull(port)){
+    sockfd = Tcp_connect(serverAddr, "ftp"); /* use ftp port in explicit */
+  }else{
+    sockfd = Tcp_connect(serverAddr, port);
+  }
+  if(sockfd<0){
+    err_msg("ERR at %s#%d: Ftpse server is not normal 0",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get [220 <host> FTP server ..]*/
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpse server is not normal 1",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"220")!=recvline){
+    err_msg("ERR at %s#%d: Ftpse server is not normal 2",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* put [AUTH TLS] */
+  Writefmt(sockfd, "AUTH TLS\r\n");
+
+  /* get [234 AUTH TLS successful] */
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpse server is not normal 3",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"234")!=recvline){
+    err_msg("ERR at %s#%d: Ftpse server is not normal 4",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* ----------------------------------------------- */
+  /* prepare SSL */
+  SSLeay_add_ssl_algorithms();
+  meth = SSLv23_client_method();
+  SSL_load_error_strings();
+  ctx = SSL_CTX_new (meth);
+  if( ctx == NULL ){
+    err_msg("ERR at %s#%d: SSL_CTX_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+  
+  /* ----------------------------------------------- */
+  /* start SSL negotiation. */
+  
+  ssl = SSL_new (ctx);
+  if( ssl == NULL ){
+    err_msg("ERR at %s#%d: SSL_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  SSL_set_fd (ssl, sockfd);
+  if( SSL_connect (ssl) == -1 ){
+    err_msg("ERR at %s#%d: SSL_connect returns error",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* --------------------------------------------------- */
+  /* DATA EXCHANGE - Send a message and receive a reply. */
+
+  /* put [USER <userid>] */
+  WritefmtSSL(ssl, "USER %s\r\n", userid);
+
+  /* get [331 Password required ..] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpse server is not normal 5",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* if multi-line greeting [220 ...] exist, skip them. */
+  while(strstr(recvline,"220")==recvline){
+    if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+      err_msg("ERR at %s#%d: Ftpse server is not normal 6",__FILE__,__LINE__);
+      authResult=DENY;
+      goto EXITPOINT;
+    }
+  }
+
+  /* check [331 Password required ..] */
+  if(strstr(recvline,"331")!=recvline){
+    err_msg("ERR at %s#%d: Ftpse server is not normal 7",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* put [PASS <password>] */
+  WritefmtSSL(ssl, "PASS %s\r\n", passwd);
+
+  /* get [230 User <userid> logged in] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpse server is not normal 8",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+  if(strstr(recvline,"230")==recvline){
+    authResult=ACCEPT;
+  }else{
+    authResult=DENY;
+  }
+  
+  /* put [quit] */
+  WritefmtSSL(ssl,"quit\r\n");
+
+EXITPOINT:
+  SSL_shutdown (ssl);  /* send SSL/TLS close_notify */
+
+  /* Clean up. */
+  Close(sockfd);
+  SSL_free (ssl);
+  SSL_CTX_free (ctx);
+
+  return authResult;
+}
+
+
+/*****************************************/
+/* Auth by FTP on SSL - Implicit Mode    */
+/*****************************************/
+int authFtpsi(char *userid, char *passwd)
+{
+  int          sockfd, n;
+  char         recvline[BUFFMAXLN];
+  int           authResult;
+  char* serverAddr; /* auth server address */
+  char* port;      /* auth server port */
+  SSL_CTX    *ctx;
+  SSL        *ssl;
+  SSL_METHOD *meth;
+
+  /* get auth server address */
+  serverAddr=GetConfValue("AuthServer/Address");
+
+  if(isNull(serverAddr)){
+    err_msg("ERR at %s#%d: Missing address for FTP server in config",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get auth server port */
+  port=GetConfValue("AuthServer/Port");
+
+  /* FTP server connect */
+  if(port==NULL){
+    sockfd = Tcp_connect(serverAddr, "ftps");
+  }else{
+    sockfd = Tcp_connect(serverAddr, port);
+  }
+  if(sockfd<0){
+    err_msg("ERR at %s#%d: Ftpsi server is not normal 0",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* ----------------------------------------------- */
+  /* prepare SSL */
+  SSLeay_add_ssl_algorithms();
+  meth = SSLv2_client_method();
+  SSL_load_error_strings();
+  ctx = SSL_CTX_new (meth);
+  if( ctx == NULL ){
+    err_msg("ERR at %s#%d: SSL_CTX_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+  
+  /* ----------------------------------------------- */
+  /* start SSL negotiation. */
+  
+  ssl = SSL_new (ctx);
+  if( ssl == NULL ){
+    err_msg("ERR at %s#%d: SSL_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  SSL_set_fd (ssl, sockfd);
+  if( SSL_connect (ssl) == -1 ){
+    err_msg("ERR at %s#%d: SSL_connect returns error",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* --------------------------------------------------- */
+  /* DATA EXCHANGE - Send a message and receive a reply. */
+
+  /* get [220 <host> FTP server ..]*/
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpsi server is not normal 1",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+  if(strstr(recvline,"220")!=recvline){
+    err_msg("ERR at %s#%d: Ftpsi server is not normal 2",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* put [USER <userid>] */
+  WritefmtSSL(ssl, "USER %s\r\n", userid);
+
+  /* get [331 Password required ..] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpi server is not normal 3",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* if multi-line greeting [220 ...] exist, skip them. */
+  while(strstr(recvline,"220")==recvline){
+    if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+      err_msg("ERR at %s#%d: Ftpsi server is not normal 4",__FILE__,__LINE__);
+      authResult=DENY;
+      goto EXITPOINT;
+    }
+  }
+
+  /* check [331 Password required ..] */
+  if(strstr(recvline,"331")!=recvline){
+    err_msg("ERR at %s#%d: Ftpsi server is not normal 5",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* put [PASS <password>] */
+  WritefmtSSL(ssl, "PASS %s\r\n", passwd);
+
+  /* get [230 User <userid> logged in] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftpsi server is not normal 6",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+  if(strstr(recvline,"230")==recvline){
+    authResult=ACCEPT;
+  }else{
+    authResult=DENY;
+  }
+  
+  /* put [quit] */
+  WritefmtSSL(ssl,"quit\r\n");
+
+EXITPOINT:
+  SSL_shutdown (ssl);  /* send SSL/TLS close_notify */
+
+  /* Clean up. */
+  Close(sockfd);
+  SSL_free (ssl);
+  SSL_CTX_free (ctx);
+
+  return authResult;
+}
+
+/***************************/
+
+int AuthFtpse(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authFtpse(%s,passwd)",userid);
+  ret=authFtpse(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authFtpse( )",ret);
+
+  return ret;
+}
+
+int AuthFtpsi(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authFtpsi(%s,passwd)",userid);
+  ret=authFtpsi(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authFtpsi( )",ret);
+
+  return ret;
+}
+
diff --git a/mngsrc/auth-ldap.c b/mngsrc/auth-ldap.c
new file mode 100644 (file)
index 0000000..02a39b6
--- /dev/null
@@ -0,0 +1,145 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication by LDAP
+
+Copyright (C) 2007 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemmng.h"
+
+
+#ifndef LDAP_NOT_INSTALLED
+  #include <ldap.h>
+  #include <lber.h>
+#endif
+
+/*****************************************/
+/* Authenticate by LDAP */
+/*****************************************/
+int authLdap(char *userid, char *passwd)
+{
+
+#ifdef LDAP_NOT_INSTALLED
+  err_msg("ERR at %s#%d: No LDAP. Install openldap-client and rebuild Opengate.",
+           __FILE__,__LINE__);
+  return DENY;
+#else
+
+  LDAP *ld;
+  int desiredVersion = LDAP_VERSION3; 
+  char *uri;                      /* ldap server URI */
+  char filter[BUFFMAXLN]="";
+  char *baseDn;
+  LDAPMessage *result;
+  LDAPMessage *entry;
+  char *dn;
+  int ret;
+  struct berval cred = { strlen(passwd), passwd };
+  struct berval *msgidp=NULL;
+
+  /* get LDAP server URI */
+  uri=GetConfValue("AuthServer/Uri");
+  if(isNull(uri)) uri=NULL; /* means ldap://localhost */
+  /* get LDAP search base DN */
+  baseDn=GetConfValue("AuthServer/BaseDN");
+  if(isNull(baseDn)) baseDn=NULL; /* set in uri */
+  
+  /* get handle */
+  if(ldap_initialize(&ld, uri)!=LDAP_SUCCESS) { 
+    err_msg("ERR at %s#%d: Can not initialize the LDAP server",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* set LDAP version */
+  if(ldap_set_option(ld,LDAP_OPT_PROTOCOL_VERSION,&desiredVersion) 
+     != LDAP_OPT_SUCCESS){
+    err_msg("ERR at %s#%d: error in LDAP set version",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* set URI such as [ldaps://ldap.saga-u.ac.jp:999] */
+  ret=ldap_set_option(ld, LDAP_OPT_URI, uri);
+  if(ret==LDAP_PARAM_ERROR){
+    err_msg("ERR at %s#%d: parameter error in LDAP set URI",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+  
+  /* set filter */
+  strncpy(filter, "(uid=", BUFFMAXLN);
+  strncat(filter, userid, BUFFMAXLN);
+  strncat(filter, ")", BUFFMAXLN);
+  
+  /* search LDAP entry */
+  ret = ldap_search_ext_s(ld,baseDn,LDAP_SCOPE_SUBTREE,
+                 filter,NULL,0,NULL,NULL,NULL,0,&result);
+  if (ret !=LDAP_SUCCESS) {
+    err_msg("ERR at %s#%d: error in LDAP search",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* count of matched entry must be one */
+  if(ldap_count_entries(ld,result)!=1){
+    return DENY;
+  }
+  /* get the entry */
+  entry=ldap_first_entry(ld,result); 
+  
+  /* get the DN */
+  dn=ldap_get_dn(ld, entry);
+  
+  /* authenticate by binding */
+  ret=ldap_sasl_bind_s(ld,dn,NULL,&cred,NULL,NULL,&msgidp);
+  
+  /* unbinding */
+  ldap_unbind_ext_s(ld,NULL,NULL);
+
+  /* return the auth result */
+  if(ret==LDAP_SUCCESS){
+    return ACCEPT;
+  }
+  else{
+    return DENY;
+  }
+#endif
+}
+
+  
+
+  
+int AuthLdap(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authLdap(%s,passwd)",userid);
+  ret=authLdap(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authLdap( )",ret);
+
+  return ret;
+}
+
+
+
+
+
diff --git a/mngsrc/auth-pam.c b/mngsrc/auth-pam.c
new file mode 100644 (file)
index 0000000..d604f13
--- /dev/null
@@ -0,0 +1,163 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication by PAM
+
+Copyright (C) 2002 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+/*
+  Thanks to programs and documentations refered.
+   The Linux-PAM Application Developer's Guide by A. G. Morgan.
+   The example appilication in above doc by Shane Watts
+   Manual files about PAM.
+*/
+
+#include <security/pam_appl.h>
+#include "opengatemmng.h"
+
+int pamCallback(int num_msg, const struct pam_message **msg,
+                   struct pam_response **resp, void *appdata_ptr);
+
+static struct pam_conv pamConv; /* PAM conversation info */
+
+typedef struct {
+  char *userid;
+  char *password;
+} userInfo_t;
+
+/******************************/
+/* authentication by PAM      */
+/* need to edit /etc/pam.conf */
+/******************************/
+int authPam(char *userid, char *passwd)
+{
+  char serviceName[ADDRMAXLN];
+  char *serviceNameInConf;
+  pam_handle_t *pamh=NULL;
+  int retval;
+  userInfo_t userInfo;
+  
+  /* get pam service name used in pam config file */
+  serviceNameInConf=GetConfValue("AuthServer/ServiceName");
+
+  if(isNull(serviceNameInConf)){
+    strncpy(serviceName, PAMSERVICENAME, ADDRMAXLN);
+  }else{
+    strncpy(serviceName, serviceNameInConf, ADDRMAXLN);
+  }
+  
+  if(!userid || !passwd) return DENY;
+  
+  /* set userInfo which is passed to call back function */
+  userInfo.userid=userid;
+  userInfo.password=passwd;
+  
+  /* setting of call back function (its name and data) */
+  pamConv.conv=pamCallback;
+  pamConv.appdata_ptr=&userInfo;
+  
+  /* root privilege is needed to control PAM */
+  if(seteuid(0)!=0){
+    err_msg("ERR at %s#%d: cannot add root privilege ",
+           __FILE__,__LINE__);
+  } 
+
+  /* PAM start */
+  retval = pam_start(serviceName, userid, &pamConv, &pamh);
+  
+  /* at success, check auth */
+  if (retval == PAM_SUCCESS){
+    retval = pam_authenticate(pamh, 0);    /* is user really user? */
+  }
+  
+  /* at success, check account */
+  if (retval == PAM_SUCCESS){
+    retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
+  }
+  
+  /* error message if not success */
+  if (retval != PAM_SUCCESS){
+    err_msg("ERR at %s#%d: %s\n",__FILE__,__LINE__,pam_strerror(pamh, retval));
+  }
+  
+  /* PAM end */
+  if (pam_end(pamh,retval) != PAM_SUCCESS) {
+    pamh = NULL;
+    err_msg("ERR at %s#%d: failed to release authenticator",__FILE__,__LINE__);
+  }
+  
+  /* remove root privilege */
+  seteuid(getuid()); 
+
+  /* clear password */
+  userInfo.password = NULL;
+
+  return ( retval == PAM_SUCCESS ? ACCEPT:DENY );       /* indicate success */
+}
+
+/**************************************************************/
+/* Send user information to PAM. Called back from PAM module. */
+/**************************************************************/
+int pamCallback(int num_msg, const struct pam_message **msg,
+                   struct pam_response **resp, void *appdata_ptr)
+{
+  userInfo_t *userInfo = (userInfo_t *)appdata_ptr;
+  struct pam_response *response=NULL;
+  int i;
+  
+  /* parameter check */
+  if(!resp || !msg || !userInfo) return PAM_CONV_ERR;
+
+  /* allocate memory to store response */
+  response = (struct pam_response *)
+    malloc(num_msg * sizeof(struct pam_response));
+  if(!response) return PAM_CONV_ERR;
+
+  /* set user informations */
+  for(i=0; i<num_msg; i++){
+    response[i].resp_retcode=0;
+    response[i].resp=NULL;
+
+    switch(msg[i]->msg_style){
+    case PAM_PROMPT_ECHO_ON:   /* must be requesting userid */
+      response[i].resp=(char *)strdup(userInfo->userid);
+      break;
+    case PAM_PROMPT_ECHO_OFF:   /* must be requesting password */
+      response[i].resp=(char *)strdup(userInfo->password);
+      break;                 
+    default:                 
+      break;                 
+    }
+  }
+
+  *resp = response;
+  return PAM_SUCCESS;
+}
+
+/************ For DEBUG ********************/
+int AuthPam(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authPam(%s,passwd)",userid);
+  ret=authPam(userid, passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authPam( )",ret);
+
+  return ret;
+}
diff --git a/mngsrc/auth-pop3s.c b/mngsrc/auth-pop3s.c
new file mode 100644 (file)
index 0000000..85367c1
--- /dev/null
@@ -0,0 +1,167 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication by POP3S
+
+Copyright (C) 2002 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+/*
+  Thanks to programs and documentations refered.
+   Sample client application cli.cpp found in the OpenSSL site 
+    (developed by Sampo Kellomaki and simplified by Wade Scholine) 
+   Apache module mod_auth_pam.c by Ingo Luetkebohle
+*/
+
+#include "opengatemmng.h"
+
+/*************************/
+/* Authenticate by POP3S */
+/*************************/
+int authPop3s(char *userid, char *passwd)
+{
+  char* serverAddr;
+  char* port;
+  int          sockfd, n;
+  char         recvline[BUFFMAXLN];
+  int           authResult;
+  SSL_CTX    *ctx;
+  SSL        *ssl;
+  SSL_METHOD *meth;
+
+  /* get auth server address */
+  serverAddr=GetConfValue("AuthServer/Address");
+
+  if(isNull(serverAddr)){
+    err_msg("ERR at %s#%d: Missing address for POP3s server in config",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get auth server port */
+  port=GetConfValue("AuthServer/Port");
+
+  /* POP3S server connect */
+  if(isNull(port)){
+    sockfd = Tcp_connect(serverAddr, "pop3s");
+  }else{
+    sockfd = Tcp_connect(serverAddr, port);
+  }
+  if(sockfd<0){
+    err_msg("ERR at %s#%d: Pop3s server is not normal 0",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* prepare SSL */
+  SSLeay_add_ssl_algorithms();
+  meth = SSLv23_client_method();
+  SSL_load_error_strings();
+  ctx = SSL_CTX_new (meth);
+  if( ctx == NULL ){
+    err_msg("ERR at %s#%d: SSL_CTX_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+  
+  /* ----------------------------------------------- */
+  /* start SSL negotiation. */
+  
+  ssl = SSL_new (ctx);
+  if( ssl == NULL ){
+    err_msg("ERR at %s#%d: SSL_new returns NULL",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  SSL_set_fd (ssl, sockfd);
+  if( SSL_connect (ssl) == -1 ){
+    err_msg("ERR at %s#%d: SSL_connect returns error",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* --------------------------------------------------- */
+  /* DATA EXCHANGE - Send a message and receive a reply. */
+  /*  pop3 message exchange */
+
+  /* get [+OK POP3 <host> <ver> server ready]*/
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3s server is not normal 1",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  if(strstr(recvline,"+OK")!=recvline){
+    err_msg("ERR at %s#%d: Pop3s server is not normal 2",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* put [user <userid>] */
+  WritefmtSSL(ssl, "user %s\r\n", userid);
+
+  /* get [+OK User name accepted, password please] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3s server is not normal 3",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  if(strstr(recvline,"+OK")!=recvline){
+    err_msg("ERR at %s#%d: Pop3s server is not normal 4",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  /* put [pass <password>] */
+  WritefmtSSL(ssl, "pass %s\r\n", passwd);
+
+  /* get [+OK Mailbox open, <count> messages] */
+  if((n = readlnSSL(ssl, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3s server is not normal 5",__FILE__,__LINE__);
+    authResult=DENY;
+    goto EXITPOINT;
+  }
+
+  if(strstr(recvline,"+OK")==recvline){
+    authResult=ACCEPT;
+  }else{
+    authResult=DENY;
+  }
+  
+  /* put [quit] */
+  WritefmtSSL(ssl,"quit\r\n");
+
+EXITPOINT:
+  SSL_shutdown (ssl);  /* send SSL/TLS close_notify */
+
+  /* Clean up. */
+  Close(sockfd);
+  SSL_free (ssl);
+  SSL_CTX_free (ctx);
+
+  return authResult;
+}
+
+int AuthPop3s(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authPop3s(%s,passwd)",userid);
+  ret=authPop3s(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authPop3s( )",ret);
+
+  return ret;
+}
diff --git a/mngsrc/auth-rad.c b/mngsrc/auth-rad.c
new file mode 100644 (file)
index 0000000..aeb3d2e
--- /dev/null
@@ -0,0 +1,130 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication by RADIUS
+
+Copyright (C) 2002 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+/*
+  Thanks to programs and documentations refered.
+   The experimental implementation by Fuyuta Sato.
+   Manual files about RADIUS.
+*/
+
+#include <radlib.h>
+#include "opengatemmng.h"
+
+/*****************************************/
+/* Authenticate by RADIUS */
+/*****************************************/
+int authRadius(char *userid, char *passwd)
+{
+  char* confFile;
+  int           authResult;
+  struct rad_handle *radh;
+  char hostname[ADDRMAXLN];
+
+  /* get radius config file path */
+  confFile=GetConfValue("AuthServer/ConfFile");
+
+  /* If not set, set default conf file path */
+  if(isNull(confFile)){
+    confFile=RADIUSCONF;
+  }
+
+  if( !(radh=rad_auth_open()) ){
+    err_msg("ERR at %s#%d: rad_auth_open",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  if(gethostname(hostname,ADDRMAXLN) < 0){
+    err_msg("ERR at %s#%d: gethostname",__FILE__,__LINE__);
+    rad_close(radh);
+    return DENY;
+  }
+    
+  if(rad_config(radh,confFile) < 0){
+    err_msg("ERR at %s#%d: rad_config: %s",__FILE__,__LINE__,  
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+
+  if(rad_create_request(radh, RAD_ACCESS_REQUEST) < 0){
+    err_msg("ERR at %s#%d: rad_ceate_request: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+
+  if(rad_put_string(radh,RAD_USER_NAME,userid)<0){
+    err_msg("ERR at %s#%d: rad_put_string: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+  if(rad_put_string(radh,RAD_USER_PASSWORD,passwd)<0){
+    err_msg("ERR at %s#%d: rad_put_string: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+  if(rad_put_string(radh,RAD_NAS_IDENTIFIER,hostname)<0){
+    err_msg("ERR at %s#%d: rad_put_string: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+  if(rad_put_int(radh,RAD_SERVICE_TYPE,RAD_LOGIN)<0){
+    err_msg("ERR at %s#%d: rad_put_int: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    rad_close(radh);
+    return DENY;
+  }
+
+  switch(rad_send_request(radh)){
+  case RAD_ACCESS_ACCEPT:
+    authResult=ACCEPT;
+    break;
+  case -1:
+    err_msg("ERR at %s#%d: rad_send_request: %s",__FILE__,__LINE__,
+           rad_strerror(radh));
+    authResult=DENY;
+    break; 
+  case RAD_ACCESS_REJECT:
+  case RAD_ACCESS_CHALLENGE:
+  case RAD_ACCOUNTING_RESPONSE:
+  default:
+    authResult=DENY;
+    break;
+  }
+  rad_close(radh);
+  return authResult;
+}
+  
+int AuthRadius(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authRadius(%s,passwd)",userid);
+  ret=authRadius(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authRadius( )",ret);
+
+  return ret;
+}
diff --git a/mngsrc/auth.c b/mngsrc/auth.c
new file mode 100644 (file)
index 0000000..f666382
--- /dev/null
@@ -0,0 +1,675 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Authentication of User
+
+Copyright (C) 1999 Opengate Project Team
+Written by Yoshiaki Watanabe
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemmng.h"
+
+void onAuthReplyAlarm(int signo);
+int authFtp(char *userid, char *passwd);
+int AuthFtp(char *userid, char *passwd);
+int authPop3(char *userid, char *passwd);
+int AuthPop3(char *userid, char *passwd);
+int authPam(char *userid, char *passwd);
+int AuthPam(char *userid, char *passwd);
+int authRadius(char *userid, char *passwd);
+int AuthRadius(char *userid, char *passwd);
+int authPop3s(char *userid, char *passwd);
+int AuthPop3s(char *userid, char *passwd);
+int authFtpse(char *userid, char *passwd);
+int AuthFtpse(char *userid, char *passwd);
+int authFtpsi(char *userid, char *passwd);
+int AuthFtpsi(char *userid, char *passwd);
+int authLdap(char *userid, char *passwd);
+int AuthLdap(char *userid, char *passwd);
+
+/****************************************
+get userid from anywhere (cookie/env/postdata)
+if not get, send back auth page.
+language indicates the one for web description
+****************************************/
+int getUserId(char* requestStr, char* userId, char* extraId, char* language, int userType, char* cgiName, char* mailDefault, char* redirectedUrl){
+  int authResult=DENY;
+  char useridfull[USERMAXLN]; /* userid@extraid */
+  char cookie[SIDMAXLN];
+  char password[USERMAXLN];
+  char* docName;
+
+  /* default mail address is null */
+  mailDefault[0]='\0';
+
+  /***** try to get userid from db corresponding to http cookie *****/
+  switch(userType){
+  case NORMALUSER:
+    if(GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
+      if(IsCookieFoundInWorkDb(cookie, userId, extraId, NORMALUSER)){ 
+       ConcatUserId(useridfull, userId, extraId);
+       GetMailDefaultFromWorkDb(cookie, mailDefault);
+       authResult=ACCEPT;
+      }
+    }
+    break;
+  case ADMINUSER:
+    if(GetHttpCookie(cookie, GetConfValue("AuthAdminCookie"))){
+      if(IsCookieFoundInWorkDb(cookie, userId, extraId, ADMINUSER)){ 
+       ConcatUserId(useridfull, userId, extraId);
+       authResult=ACCEPT;
+      }
+    }
+    break;
+  }
+
+  /***** try to get uid from environment variables(shibboleth/httpbasic) *****/
+  if(authResult==DENY){
+
+    /* search shibboleth / httpbasic auth setting in conf */
+    ResetAuthServerPointer();
+    while(SelectNextAuthServer()){
+
+      /* if server setting is not matched to the required usertype, skip it */
+      if( (strcmp(GetConfValue("AuthServer/UserType"), "admin")==0)
+       && (userType!=ADMINUSER) ) continue;
+      if( (strcmp(GetConfValue("AuthServer/UserType"), "admin")!=0)
+       && (userType==ADMINUSER) ) continue;
+       
+      /* if the server setting is not (shibboleth or httpbasic), skip it */
+      if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")!=0
+        && strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")!=0) continue;
+       
+      /* if reached to this(=shibboleth/httpbasic), get userid from env var */
+      if(GetUserIdFromEnv(useridfull)){
+
+       /* split user@extra to user and extra. then search conf extra set */
+       SplitId(useridfull, userId, extraId);
+       SetupConfExtra(userId, extraId);
+
+       /* if the user is found in accept user list, accept him, else deny */
+       if(IsUserIdFoundInAcceptUsersList(userId)){
+         authResult=ACCEPT;
+         MakeMailDefault(userId, extraId, mailDefault);
+       }
+       else{
+         SetMessage(NoInfoInDb); 
+         PutDenyToClient(language);
+         err_msg("DENY: user %s", useridfull);
+         authResult=DENY;
+         return FALSE;
+       }
+      }
+    }
+  }
+
+  /***** try to get userid from request string *****/
+  if(authResult==DENY){
+
+    /* if not get, in request string, send back auth page */
+    if(!GetUserIdFromPostData(requestStr, useridfull, password)){
+
+      /* split user@extra to user and extra, then search conf extra set */
+      SplitId(useridfull, userId, extraId);
+      SetupConfExtra(userId, extraId);
+      
+      /* select document content */
+      if(userType==ADMINUSER) docName=GetConfValue("AuthAdminDoc");
+      else docName=GetConfValue("AuthDoc");
+
+      /* put page and exit */
+      PutAuthRequestPageToClient(language, cgiName, docName, redirectedUrl);
+      return FALSE;
+    }
+
+    /* reaching this line means that userid is in request string */
+    /* split user@extra to user and extra. then search conf extra set */
+    SplitId(useridfull, userId, extraId);
+    SetupConfExtra(userId, extraId);
+
+    /* check user by authenticate servers */
+    ResetAuthServerPointer();
+    while(SelectNextAuthServer()){
+      
+      /* if check normal user and admin auth server, skip the server */
+      /* if check admin user and not admin auth server, skip the server */
+      if(userType==NORMALUSER 
+        && strcmp(GetConfValue("AuthServer/UserType"), "admin")==0) continue;
+      if(userType==ADMINUSER
+        && strcmp(GetConfValue("AuthServer/UserType"), "admin")!=0) continue;
+
+      /* authenticate the user with auth server. if deny, goto next server */
+      if((authResult=AuthenticateUser(userId, password))==DENY) continue;
+
+      /* if userid is not found in the user list in conf, goto next server */
+      if(!IsUserIdFoundInAcceptUsersList(userId)){
+       authResult=DENY;
+       continue;
+      }
+
+      /* if accepted, set mail default(used for warning mail) and exit loop */
+      if(authResult==ACCEPT){
+       MakeMailDefault(userId, extraId, mailDefault);
+       break;
+      }
+    }
+
+    /* if all check is failed, put error */
+    if(authResult==DENY){
+      SetMessage(NoInfoInDb); 
+      PutDenyToClient(language);
+      err_msg("DENY: user %s", useridfull);
+    }
+  }
+  if(authResult==ACCEPT) return TRUE;
+  else return FALSE;
+}
+
+/**************************************
+ if accept users are listed in conf file,
+find the userid in the list
+ if no list is indicated, return true
+**************************************/
+int isUserIdFoundInAcceptUsersList(char* userId){
+  char usersList[BUFFMAXLN];
+  char userIdPattern[WORDMAXLN];
+
+  /* get accept users list. if not exist, return true(accept all users) */
+  strncpy(usersList,GetConfValue("AuthServer/AcceptUsers"),BUFFMAXLN);
+  if(isNull(usersList)) return TRUE;
+
+  /* if userid is found in the usersList, return true */
+  /* example of usersList is [user1 user2 user3 user4] */
+
+  /* regular expression matched to "(^| )userid( |$)" */
+  /* meaning is [(head or space) userid-string (space or tail)] */
+ /* last-arg 0 of RegEx means ignore-case */
+  strncpy(userIdPattern, "(^| )", WORDMAXLN);
+  strncat(userIdPattern, userId, WORDMAXLN);
+  strncat(userIdPattern, "( |$)", WORDMAXLN);
+  return RegExMatch(usersList, userIdPattern, 0);
+}
+
+
+/*******************************************************/
+/* Authenticate user by accessing to ftp server        */
+/*  userid : user to auth                              */
+/*  password : password for the user                   */
+/*******************************************************/
+int authenticateUser(char *userid, char *passwd)
+{
+  char* proto;
+  int authResult=DENY;
+  int timeout;
+
+  /* authserver get timeout value */
+  timeout=atoi(GetConfValue("AuthServer/Timeout"));
+
+  /* set auth server reply timeout */
+  if(timeout>0){
+    AddAlarm("AuthReplyAlarm", timeout, TRUE, onAuthReplyAlarm); 
+    EnableAlarm();
+  }
+
+  /* get Protocol for authentication */
+  proto=GetConfValue("AuthServer/Protocol");
+
+  if(strcmp(proto, "ftp")==0){
+    /* authenticate by ftp access */
+    authResult=AuthFtp(userid, passwd);
+
+  }else if(strcmp(proto, "pop3")==0){
+    /* authenticate by pop3 access */
+    authResult=AuthPop3(userid, passwd);
+
+  }else if(strcmp(proto, "pam")==0){
+    /* authenticate by pam */
+    authResult=AuthPam(userid, passwd);
+
+  }else if(strcmp(proto, "radius")==0){
+    /* authenticate by radius */
+    authResult=AuthRadius(userid, passwd);
+
+  }else if(strcmp(proto, "pop3s")==0){
+    /* authenticate by pop3s */
+    authResult=AuthPop3s(userid, passwd);
+
+  }else if(strcmp(proto, "ldap")==0){
+    /* authenticate by ldap */
+    authResult=AuthLdap(userid, passwd);
+
+  }else if(strcmp(proto, "ftpse")==0){
+    /* authenticate by ftps-explicit */
+    authResult=AuthFtpse(userid, passwd);
+
+  }else if(strcmp(proto, "ftpsi")==0){
+    /* authenticate by ftps-implicit */
+    authResult=AuthFtpsi(userid, passwd);
+
+  }else if(strcmp(proto, "shibboleth")==0){
+    /* deny all request */
+    /* if shibboleth auth is accepted, cannot reach at this point */
+    authResult=DENY;
+
+  }else if(strcmp(proto, "httpbasic")==0){
+    /* deny all request */
+    /* if httpbasic auth is accepted, cannot reach at this point */
+    authResult=DENY;
+
+  }else if(strcmp(proto, "deny")==0){
+    /* deny all request */
+    authResult=DENY;
+
+  }else if(strcmp(proto, "accept")==0){
+    /* accept all request */
+    authResult=ACCEPT;
+  }else{
+    err_msg("ERR at %s#%d: Unknown protocol:%s",__FILE__,__LINE__,proto);
+    authResult=DENY;
+  }
+
+  /* stop the auth reply timeout */
+  if(timeout>0) RemoveAlarm("AuthReplyAlarm");
+  return authResult;
+}
+
+/*****************************/
+/* split userid and extraId */
+/*****************************/
+void splitId(char* useridfull, char* userId, char* extraId)
+{
+  char useridSave[USERMAXLN];
+
+  char* markPnt=NULL;
+
+  strncpy(useridSave, useridfull, USERMAXLN);
+
+  /* separate extraId from userid */
+  markPnt=strchr(useridSave, *GetConfValue("UserIdSeparator"));
+  if(markPnt==NULL){  
+    /* separator mark not found */
+    strncpy(extraId,"",USERMAXLN);
+    strncpy(userId,useridSave,USERMAXLN);
+  }else{
+    /* pick up extraId */
+    *markPnt='\0';
+    strncpy(extraId,markPnt+1,USERMAXLN);
+    strncpy(userId,useridSave,USERMAXLN);
+  }
+} 
+
+/*************************
+concatinate userid and extraid
+*************************/
+char* concatUserId(char* useridfull, char* userId, char* extraId){
+
+  /* set full userid */
+  strncpy(useridfull, userId,USERMAXLN);
+  if(!isNull(extraId)){
+    strncat(useridfull, GetConfValue("UserIdSeparator"), USERMAXLN);
+    strncat(useridfull, extraId, USERMAXLN);
+  }
+  return useridfull;
+}
+
+/***********************/
+/* Authenticate by FTP */
+/***********************/
+int authFtp(char *userid, char *passwd)
+{
+  int          sockfd, n;
+  char         recvline[BUFFMAXLN];
+  int           authResult;
+  char* serverAddr; /* auth server address */
+  char* port;      /* auth server port */
+
+  /* get auth server address */
+  serverAddr=GetConfValue("AuthServer/Address");
+
+  if(isNull(serverAddr)){
+    err_msg("ERR at %s#%d: Missing address for FTP server in config",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get auth server port */
+  port=GetConfValue("AuthServer/Port");
+
+  /* FTP server connect */
+  if(isNull(port)){
+    sockfd = Tcp_connect(serverAddr, "ftp");
+  }else{
+    sockfd = Tcp_connect(serverAddr, port);
+  }
+  if(sockfd<0){
+    err_msg("ERR at %s#%d: Ftp server is not normal 0",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get [220 <host> FTP server ..]*/
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftp server is not normal 1",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"220")!=recvline){
+    err_msg("ERR at %s#%d: Ftp server is not normal 2",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* put [user <userid>] */
+  Writefmt(sockfd, "user %s\r\n", userid);
+
+  /* get [331 Password required ..] */
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftp server is not normal 3",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* if multi-line greeting [220 ...] exist, skip them. */
+  while(strstr(recvline,"220")==recvline){
+    if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+      err_msg("ERR at %s#%d: Ftp server is not normal 3",__FILE__,__LINE__);
+      Close(sockfd);
+      return DENY;
+    }
+  }
+
+  /* check [331 Password required ..] */
+  if(strstr(recvline,"331")!=recvline){
+    err_msg("ERR at %s#%d: Ftp server is not normal 4",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* put [pass <password>] */
+  Writefmt(sockfd, "pass %s\r\n", passwd);
+
+  /* get [230 User <userid> logged in] */
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Ftp server is not normal 5",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"230")==recvline){
+    authResult=ACCEPT;
+  }else{
+    authResult=DENY;
+  }
+  
+  /* put [quit] */
+  Writefmt(sockfd,"quit\r\n");
+
+  Close(sockfd);
+  return authResult;
+}
+
+/************************/
+/* Authenticate by POP3 */
+/************************/
+int authPop3(char *userid, char *passwd)
+{
+  int          sockfd, n;
+  char         recvline[BUFFMAXLN];
+  int           authResult;
+  char*  serverAddr;
+  char* port;
+
+  /* get auth server address */
+  serverAddr=GetConfValue("AuthServer/Address");
+
+  if(isNull(serverAddr)){
+    err_msg("ERR at %s#%d: Missing address for POP3 server in config",
+           __FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get auth server port */
+  port=GetConfValue("AuthServer/Port");
+
+  /* POP3 server connect */
+  if(isNull(port)){
+    sockfd = Tcp_connect(serverAddr, "pop3");
+  }else{
+    sockfd = Tcp_connect(serverAddr, port);
+  }
+  if(sockfd<0){
+    err_msg("ERR at %s#%d: Pop3 server is not normal 0",__FILE__,__LINE__);
+    return DENY;
+  }
+
+  /* get [+OK POP3 <host> <ver> server ready]*/
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3 server is not normal 1",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"+OK")!=recvline){
+    err_msg("ERR at %s#%d: Pop3 server is not normal 2",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* put [user <userid>] */
+  Writefmt(sockfd, "user %s\r\n", userid);
+
+  /* get [+OK User name accepted, password please] */
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3 server is not normal 3",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"+OK")!=recvline){
+    err_msg("ERR at %s#%d: Pop3 server is not normal 4",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+
+  /* put [pass <password>] */
+  Writefmt(sockfd, "pass %s\r\n", passwd);
+
+  /* get [+OK Mailbox open, <count> messages] */
+  if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
+    err_msg("ERR at %s#%d: Pop3 server is not normal 5",__FILE__,__LINE__);
+    Close(sockfd);
+    return DENY;
+  }
+  if(strstr(recvline,"+OK")==recvline){
+    authResult=ACCEPT;
+  }else{
+    authResult=DENY;
+  }
+  
+  /* put [quit] */
+  Writefmt(sockfd,"quit\r\n");
+
+  Close(sockfd);
+  return authResult;
+}
+
+/***************************************/
+/* called at auth reply timeout        */
+/***************************************/
+void onAuthReplyAlarm(int signo)
+{
+}
+
+
+/***********************************
+check duplication of shibboleth / httpbasic auth server
+shibboleth/httpbasic cannot be used for both usertype
+***********************************/
+int isShibOrBasicAuthDuplicated(void){
+  int nShib=0;
+  int nBasic=0;
+
+  /* scan config file to count shibboleth/httpbasic auth server setting */
+  ResetAuthServerPointer();
+  while(SelectNextAuthServer()){
+    if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")==0) nShib++;
+    if(strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")==0) nBasic++;
+  }
+  ResetAuthServerPointer();
+
+  /* if duplicated, put error */
+  if(nShib>1 || nBasic>1){
+    err_msg("ERR at %s#%d: Shibboleth or HttpBasic auth cannot duplicate",__FILE__,__LINE__);
+    return TRUE;
+  }else{
+    return FALSE;
+  }
+}
+
+/**************************************
+setup default mail address
+made from conf value at MailAttribute or MailDomain
+**************************************/
+int makeMailDefault(char* userId, char* extraId, char* mailDefault){
+
+  char* pMailAttribute=NULL;
+  char* pMailDomain=NULL;
+  char* pMailAddr=NULL;
+
+  /* set default null */
+  mailDefault[0]='\0';
+
+  /* get conf values for mail domain */
+  pMailAttribute=GetConfValue("AuthServer/MailAttribute");
+  pMailDomain=GetConfValue("AuthServer/MailDomain");
+  if(isNull(pMailAttribute) && isNull(pMailDomain)){
+      err_msg("ERR at %s#%d: Can't get mail attibute/domain setting from conf file.",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* if set mail attribute, mail from the env variable in attr */
+  if(!isNull(pMailAttribute)){
+    pMailAddr=getenvEx(pMailAttribute,TRUE,FALSE); /* var list is permitted */
+    if(!isNull(pMailAddr)){
+      strncpy(mailDefault, pMailAddr, BUFFMAXLN);
+      return TRUE;
+    }else{
+      err_msg("ERR at %s#%d: Can't get mail attibute from environment variable.",__FILE__,__LINE__);
+      return FALSE;
+    }
+  }
+
+  /* if set mail domain, mail from userid+@+maildomain */
+  if(!isNull(pMailDomain)){
+    strncpy(mailDefault, userId, BUFFMAXLN);
+    strncat(mailDefault, "@", BUFFMAXLN);
+    strncat(mailDefault, pMailDomain, BUFFMAXLN);
+    return TRUE;
+  }else{
+      err_msg("ERR at %s#%d: Can't get mail domain string from conf file.",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  err_msg("ERR at %s#%d: Can't set mail. Check AuthServer/MailAttribute or AuthServer/MailDomain in conf.",__FILE__,__LINE__);
+  return FALSE;  
+}
+
+/**********************************/
+/**********************************/
+int GetUserId(char* requestStr, char* userId, char* extraId, char* language, int userType, char* cgiName, char* mailDefault, char* redirectedUrl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getUserId(..,%s,%d)",language,userType);
+  ret=getUserId(requestStr, userId, extraId, language, userType, cgiName, mailDefault, redirectedUrl);
+  if(debug>1) err_msg("DEBUG:(%d)<=getUserId(%s,%s,%s)",ret,userId,extraId,mailDefault);
+  return ret;
+}
+
+int AuthFtp(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authFtp(%s,passwd)",userid);
+  ret=authFtp(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authFtp( )",ret);
+
+  return ret;
+}
+
+
+int AuthPop3(char *userid, char *passwd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authPop3(%s,passwd)",userid);
+  ret=authPop3(userid,passwd);
+  if(debug>1) err_msg("DEBUG:(%d)<=authPop3( )",ret);
+
+  return ret;
+}
+
+int AuthenticateUser(char *userid, char *password)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>authenticateUser(%s,passwd)",userid);
+  ret=authenticateUser(userid,password);
+  if(debug>1) err_msg("DEBUG:(%d)<=authenticateUser( )",ret);
+
+  return ret;
+}
+
+void SplitId(char* userid, char* useridshort, char* extraId)
+{
+  if(debug>1) err_msg("DEBUG:=>splitId(%s,,)",userid);
+  splitId(userid,useridshort,extraId);
+  if(debug>1) err_msg("DEBUG:<=splitId(,%s,%s)",useridshort,extraId);
+}
+
+char* ConcatUserId(char*  useridfull, char* userId, char* extraId)
+{
+  char* ret;
+  if(debug>1) err_msg("DEBUG:=>concatUserId(,%s,%s)",userId,extraId);
+  ret=concatUserId(useridfull, userId, extraId);
+  if(debug>1) err_msg("DEBUG:<=concatUserId(%s,,)",useridfull);
+  return ret;
+}
+
+int IsUserIdFoundInAcceptUsersList(char* userId){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>isUserIdFoundInAcceptUsersList(%s)",userId);
+  ret=isUserIdFoundInAcceptUsersList(userId);
+  if(debug>1) err_msg("DEBUG:(%d)<=isUserIdFoundInAcceptUsersList( )",ret);
+
+  return ret;
+}
+
+int IsShibOrBasicAuthDuplicated(void){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>isShibOrBasicAuthDuplicated( )");
+  ret=isShibOrBasicAuthDuplicated();
+  if(debug>1) err_msg("DEBUG:(%d)<=isShibOrBasicAuthDuplicated( )",ret);
+
+  return ret;
+}
+
+int MakeMailDefault(char* userId, char* extraId, char* mailDefault){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>makeMailDefault(%s,%s,)",userId, extraId);
+  ret=makeMailDefault(userId, extraId,mailDefault);
+  if(debug>1) err_msg("DEBUG:(%d)<=makeMailDefault(,,%s)",ret,mailDefault);
+
+  return ret;
+}
diff --git a/mngsrc/cgi.c b/mngsrc/cgi.c
new file mode 100644 (file)
index 0000000..330f936
--- /dev/null
@@ -0,0 +1,1401 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Communication through CGI 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+
+Programmed by Yoshiaki WATANABE
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/* convert one-char-hex "a" to one-number 0Xa */ 
+#define hex2num(x)  ((x)>='A' ? ((x) & 0XDF) - 'A' +10 : ((x) - '0'))
+
+void split(char content[], char *name[], char *value[], char *next[]);
+void decode(char *string);
+
+char macAddress[ADDRMAXLN]="";
+
+/********************************************/
+/* get Post data from the client  */
+/********************************************/
+int getPostData(char *content, int contentMaxLength)
+{
+  int contentLen;
+
+  /* get content sent from web input */
+  if(isNull(getenv("CONTENT_LENGTH"))) return FALSE;
+  contentLen=atoi(getenv("CONTENT_LENGTH"));
+  contentLen++; /* for terminate ch */
+
+  /* if larger than buffer, cut off */
+  if(contentLen > contentMaxLength) contentLen=contentMaxLength;
+  if(fgets(content, contentLen, stdin) == NULL){
+    content[0]='\0';
+  }
+
+  return TRUE;
+}
+
+/********************************************/
+/* get language form query string (in url lang=ja)  */
+/********************************************/
+int getLangFromQueryString(char* language){
+
+  int found=FALSE;
+  char queryStr[BUFFMAXLN];
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+
+  /* get default language at the top of lang list */
+  sscanf(GetConfValue("HtmlLangs"), "%s", language);
+
+  /* if no string, return default */
+  if(isNull(getenv("QUERY_STRING"))) return FALSE;
+
+  /* get html access parameter string */
+  strncpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);
+
+  /* split language in string [....&lang=ja&.....] */
+  ptr=queryStr;
+  while(ptr!=NULL){
+    split(ptr, name, value, next);
+    if(strstr(name[0], "lang")!=NULL){
+      if(!isNull(value[0])) strncpy(language, value[0], WORDMAXLN);
+      found=TRUE;
+    }
+    ptr=next[0];
+  }
+  return found;
+}
+
+/********************************************/
+/* get redirected url form query string     */
+/********************************************/
+int getRedirectedUrlFromQueryString(char* redirectedUrl){
+
+  int found=FALSE;
+  char queryStr[BUFFMAXLN];
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+
+  /* default is null */
+  redirectedUrl[0]='\0';
+
+  /* if no string, return default */
+  if(isNull(getenv("QUERY_STRING"))) return FALSE;
+
+  /* get html access parameter string */
+  strncpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);
+
+  /* split language in string [....&redirectedurl=xxxx&.....] */
+  ptr=queryStr;
+  while(ptr!=NULL){
+    split(ptr, name, value, next);
+    if(strstr(name[0], "redirectedurl")!=NULL){
+      if(!isNull(value[0])) strncpy(redirectedUrl, value[0], BUFFMAXLN);
+      found=TRUE;
+    }
+    ptr=next[0];
+  }
+  return found;
+}
+
+/********************************************/
+/* get mac address form query string (in url lang=ja)  */
+/********************************************/
+int getMacAddrFromQueryString(char* macAddress){
+
+  int found=FALSE;
+  char queryStr[BUFFMAXLN];
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+
+  /* set default */
+  macAddress[0]='\0';
+
+  /* if no string returns, return default */
+  if(isNull(getenv("QUERY_STRING"))) return FALSE;
+
+  /* get html access parameter string */
+  strncpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);
+
+  /* split in string [....&macaddr=xxxxx&.....] */
+  ptr=queryStr;
+  while(ptr!=NULL){
+    split(ptr, name, value, next);
+    if(strstr(name[0], "macaddr")!=NULL){
+      strncpy(macAddress, value[0], WORDMAXLN);
+      found=TRUE;
+    }
+    ptr=next[0];
+  }
+  decode(macAddress);
+  return found;
+
+}
+
+/********************************************/
+/* get userid from environment variable     */
+/*  long userid: "userid@extraid" is set    */
+/********************************************/
+int getUserIdFromEnv(char *userid){
+
+  int ret=FALSE;
+  char* pEnv=NULL;
+
+  /* if shibboleth or httpbasic, get uid from environment var */
+  /* shibboleth */
+  if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")==0){
+
+    /* get data from env-variables for uid and org attribute */
+    pEnv=getenvEx(GetConfValue("AuthServer/UidAttribute"),TRUE,TRUE); 
+    if(!isNull(pEnv)){
+      strncpy(userid, pEnv, USERMAXLN);
+
+      /* if orp string can be get from env var, concatenate it as uid@org */
+      pEnv=getenvEx(GetConfValue("AuthServer/OrgAttribute"),TRUE,TRUE);
+      if(!isNull(pEnv)){
+       strncat(userid, GetConfValue("UserIdSeparator"), USERMAXLN);
+       strncat(userid, pEnv, USERMAXLN);
+      } 
+      ret=TRUE;
+    }
+
+    /* get from env-variable for EPPN(edu person principal name) attribute */
+    else{
+      pEnv=getenvEx(GetConfValue("AuthServer/EppnAttribute"),TRUE,FALSE);
+      if(!isNull(pEnv)){
+       strncat(userid, pEnv, USERMAXLN);
+       ret=TRUE;
+      }
+    }
+
+    if(ret==FALSE){
+      err_msg("ERR at %s#%d: Cannot get user info from shibboleth",__FILE__,__LINE__);
+      PutMessageToClient("Cannot get user info from shibboleth<br>Check shibboleth setting in .htaccess, conf and others");
+      exit(0);
+    }    
+  }
+
+  /* httpbasic */
+  else if(strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")==0){
+    if(!isNull(getenv("REMOTE_USER"))){
+      strncpy(userid,getenv("REMOTE_USER"),USERMAXLN);
+      ret=TRUE;
+    }else{
+      err_msg("ERR at %s#%d: Cannot get user info from httpbasic",__FILE__,__LINE__);
+      ret=FALSE;
+      PutMessageToClient("Cannot get user info from http basic<br>Check http basic setting in .htaccess and other");
+      exit(0);
+    }
+  }
+  return ret;
+}
+
+/*******************************
+get userid and password from post string
+*******************************/
+int getUserIdFromPostData(char* requestStr, char* userid, char* password){
+
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+  int ret=FALSE;
+  char content[BUFFMAXLN];
+
+  /* if null string, return */
+  if(isNull(requestStr)) return FALSE;
+
+  /* copy it to work area */
+  strncpy(content, requestStr, BUFFMAXLN);
+
+  /* split request item and execute the request */
+  ptr=content;
+  while(ptr!=NULL){
+
+    /* pick up next item */
+    split(ptr, name, value, next);
+    
+    /* copy to var */
+    if(strcmp(name[0], "userid")==0){
+      strncpy(userid, value[0], USERMAXLN);
+      decode(userid);
+      ret=TRUE;
+    }
+    else if(strcmp(name[0], "password")==0){
+      strncpy(password, value[0], USERMAXLN);
+      decode(password);
+    }
+    
+    /* shift pointer to next item */
+    ptr=next[0];
+  }
+
+  /* if password is found in request string, clear the string */
+  if(!isNull(password)) requestStr[0]='\0';
+
+  return ret;
+}
+
+/********************************************/
+/* analyze request for checking    */
+/********************************************/
+int analyzeCheckRequest(char *content, int* status, char* macAddress)
+{
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+
+  /* set default */
+  *status=NONE;
+  *macAddress='\0';
+
+  /* split request item and execute the request */
+  ptr=content;
+  while(!isNull(ptr)){
+
+    /* pick up next item */
+    split(ptr, name, value, next);
+
+    /* if item =status */
+    if(strcmp(name[0], "status")==0){
+      if(strcmp(value[0], "open")==0) *status=OPEN;
+      if(strcmp(value[0], "close")==0) *status=CLOSE;
+    }
+
+    /* if item = macaddr */
+    else if(strcmp(name[0], "macaddr")==0){
+      strncpy(macAddress, value[0], ADDRMAXLN);
+      decode(macAddress);
+    }
+    
+    /* shift pointer to next item */
+    ptr=next[0];
+  }
+
+  return TRUE;
+}
+
+/********************************************/
+/* analyze request and execute request for registering   */
+/********************************************/
+int analyzeRegisterRequest(char *content, char* macAddress, char* deviceName, char* mailAddress)
+{
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+
+  /* set default */
+  *macAddress='\0';
+  *deviceName='\0';
+  *mailAddress='\0';
+
+  /* split request item and execute the request */
+  ptr=content;
+  while(!isNull(ptr)){
+
+    /* pick up next item */
+    split(ptr, name, value, next);
+
+    /* if item = macaddr */
+    if(strcmp(name[0], "macaddr")==0){
+      strncpy(macAddress, value[0], ADDRMAXLN);
+      decode(macAddress);
+
+    }
+    else if(strcmp(name[0], "device")==0){
+      strncpy(deviceName, value[0], WORDMAXLN);
+      decode(deviceName);
+    }
+    else if(strcmp(name[0], "mailaddr")==0){
+      strncpy(mailAddress, value[0], BUFFMAXLN);
+      decode(mailAddress);
+    }
+
+    /* shift pointer to next item */
+    ptr=next[0];
+  }
+
+  /* if illegal device name, return */
+  if(*deviceName=='\0'){
+    SetMessage(EmptyDeviceName); 
+    return FALSE;
+  }
+  if(!IsSafeString(deviceName, WORDMAXLN)){
+    SetMessage(IllegalCharInDevice);
+    return FALSE;
+  }
+
+  /* if illegal mail address, return */
+  if(*mailAddress!='\0'){
+    if(!IsSafeString(mailAddress, BUFFMAXLN)){
+      SetMessage(IllegalCharInMailAddr);
+      return FALSE;
+    }
+  }
+
+  /* if illegal mac address, return */
+  if(!ConvertMacAddr(macAddress)) return FALSE;
+
+  /* if already registered in db, return */
+  if(IsMacAddrFoundInMngDb(macAddress)){
+    SetMessage(ExistentMacAddr);
+    return FALSE;
+  }
+  
+  return TRUE;
+}
+  
+/******************************
+ convert mac address to regular format
+  [01:23:45:67:89:0a]
+******************************/
+int convertMacAddr(char* macAddr){
+
+  int m[6]; /* mac address sequence */
+  int i;
+
+  /* normal form is hex:hex:hex:hex:hex:hex */
+  /*             or hex-hex-hex-hex-hex-hex */
+  /* and hex<256 */
+  if((sscanf(macAddr, "%x:%x:%x:%x:%x:%x", 
+            &m[0],&m[1],&m[2],&m[3],&m[4],&m[5])!=6)
+     && (sscanf(macAddr, "%x-%x-%x-%x-%x-%x", 
+               &m[0],&m[1],&m[2],&m[3],&m[4],&m[5])!=6)){
+    SetMessage(IllegalMacAddrForm);
+    return FALSE;
+  }
+  for(i=0;i<6;i++){
+    if(m[i]>255){
+      SetMessage(IllegalMacAddr);
+      return FALSE;
+    }
+  }
+
+  /* format to [01:23:45:67:89:0a] */
+  snprintf(macAddr, ADDRMAXLN, "%02x:%02x:%02x:%02x:%02x:%02x",
+          m[0],m[1],m[2],m[3],m[4],m[5]);
+
+  return TRUE;
+}
+
+/******************************
+check safe characters string 
+******************************/
+int isSafeString(char* str, int length){
+  char allowableChar[]=" !#$&*+,-./:=?[]^_{|}@";
+  int i;
+  char ch;
+
+  /* scan all char in str */
+  for(i=0; i<length; i++){
+    ch=str[i];
+    
+    /* if reached to the end of string, return true */
+    if(ch=='\0') break;
+
+    /* if alpha or numeric is found, goto next char */
+    if(isalnum(ch)) continue;
+
+    /* if control or non ascii is found, return false */
+    if( (unsigned)ch < 0x20|| 0x7f < (unsigned)ch) return FALSE;
+    
+    /* if one of above list is found, goto next char */
+    if(strchr(allowableChar, ch)==NULL) return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*********************************************/
+/* put auth request page to client            */
+/*********************************************/
+int putAuthRequestPageToClient(char *language, char* cgiName, char* docName, char* redirectedUrl)
+{
+  char authdoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+
+  /* make read in path to the retry document */
+  snprintf(authdoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,docName);
+
+  /* replace keyword and send out the file */
+  printf("Content-type: text/html\r\n\r\n");
+
+  if((fp=fopen(authdoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, authdoc);
+    return FALSE;
+  }
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%CGINAME%%", cgiName);
+    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
+    if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(language);
+    }else{
+      printf("%s",buff);    
+    }
+  }
+  fclose(fp);
+  return TRUE;
+}
+
+/*********************************************/
+/* deny message to the client            */
+/*********************************************/
+int putDenyToClient(char *language){
+  char denydoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+
+  /* make read in path to the retry document */
+  snprintf(denydoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,GetConfValue("DenyDoc"));
+
+  /* replace keyword and send out the file */
+  printf("Content-type: text/html\r\n\r\n");
+
+  if((fp=fopen(denydoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, denydoc);
+    return FALSE;
+  }
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(language);
+    }else{
+      printf("%s",buff);
+    }
+  }
+  fclose(fp);
+  return TRUE;
+}
+
+/*********************************************/
+/* put response to client for check request   */
+/*********************************************/
+int putCheckPageToClient(char *language, char* userId, char* extraId)
+{
+  char responsedoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+  char cookie[SIDMAXLN];
+  char* chkCgi=GetConfValue("CheckCgi");
+  char* regCgi=GetConfValue("RegisterCgi");
+  char* timeout=GetConfValue("OpenTimeout");
+
+  /* make read in path to the document */
+  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,GetConfValue("CheckDoc"));
+
+  /* send header */
+  printf("Content-type: text/html\r\n");
+
+  /* if no cookie, make, send, and save cookie */
+  if(!GetHttpCookie(cookie,GetConfValue("AuthAdminCookie"))){
+    CreateCookie(cookie);
+    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthAdminCookie"), cookie);
+    SaveCookieToWorkDb(cookie,userId, extraId, ADMINUSER);
+  }
+
+  /* end of http header */
+  printf("\r\n");
+
+  /* replace keyword and send out the file */
+  if((fp=fopen(responsedoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
+    return FALSE;
+  }
+
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%CHECKCGI%%", chkCgi);
+    HtmlReplace(buff, "%%REGISTERCGI%%", regCgi);
+    HtmlReplace(buff, "%%TIMEOUT%%", timeout);
+    HtmlReplace(buff, "%%USERID%%", userId);
+
+    if(strstr(buff, "%%MACCHECKLIST%%")!=NULL){
+      PutMacCheckListToClient();
+    }
+    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(language);
+    }
+
+    else{
+      printf("%s",buff);    
+    }
+  }
+  fclose(fp);
+  return TRUE;
+}
+/*********************************************/
+/* put response to client for register request */
+/* ownReg:1=the page is controlled by owner, 0=under admin */
+/*********************************************/
+int putRegisterPageToClient(char *language, char* macAddress, char* deviceName, char* mailAddress, char* userId, char* extraId, int ownReg, char* redirectedUrl)
+{
+  char responsedoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+  char cookie[SIDMAXLN];
+  char* regCgi="";
+  char* regDoc="";
+
+
+  /* setup cgi and doc */
+  if(ownReg){
+    regCgi=GetConfValue("OwnCgi");
+    regDoc=GetConfValue("OwnRegisterDoc");
+  }else{
+    regCgi=GetConfValue("RegisterCgi");
+    regDoc=GetConfValue("RegisterDoc");
+  }
+  if(isNull(regCgi) || isNull(regDoc)){
+    err_msg("ERR at %s#%d: cannot find cgi/doc for reg in conf",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* make read in path to the document */
+  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,regDoc);
+
+  /* send header */
+  printf("Content-type: text/html\r\n");
+
+  /* if no cookie, make, send, and save cookie */
+  if(!GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
+    CreateCookie(cookie);
+    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthUserCookie"), cookie);
+    SaveCookieToWorkDb(cookie, userId, extraId, NORMALUSER);
+    SaveMailDefalutForCookieToWorkDb(cookie, mailAddress);
+  }
+
+  /* end of http header */
+  printf("\r\n");
+
+  if((fp=fopen(responsedoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
+    return FALSE;
+  }
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%REGISTERCGI%%", regCgi);
+    HtmlReplace(buff, "%%MACADDR%%", macAddress);
+    HtmlReplace(buff, "%%DEVICE%%", deviceName);
+    HtmlReplace(buff, "%%MAILADDR%%", mailAddress);
+    HtmlReplace(buff, "%%USERID%%", userId);
+    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
+
+    if(strstr(buff, "%%MACREGLIST%%")!=NULL){
+      PutMacRegListToClient(userId, extraId);
+    }
+    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(language);
+    }
+    else{
+      printf("%s",buff);    
+    }
+  }
+  fclose(fp);
+  return TRUE;
+}
+
+/*********************************************/
+/* put mac list in mac check table to the client */
+/*********************************************/
+void putMacCheckListToClient(void){
+
+  char macAddress[ADDRMAXLN];
+  char vendor[WORDMAXLN];
+  char ipv4[ADDRMAXLN];
+  char ipv6[ADDRMAXLN];
+  int firstRow=TRUE;
+  int inUse=FALSE;
+  int foundOnDb=FALSE;
+
+  /* get mac list from db and insert into html table */
+  while(GetNextRowInMacCheckTable(macAddress, ipv4, ipv6)){
+
+    /* get nic vendor from management db */
+    GetNicVendorFromMngDb(macAddress, vendor, WORDMAXLN);
+
+    /* is the terminal in use */
+    if(IsSessionFoundInSessionTable(macAddress) ||
+       IsActiveSessionFoundInOpengateSessionTable(macAddress)) inUse=TRUE;
+    else inUse = FALSE;
+    
+    /* is the terminal's MAC is registered in DB */
+    foundOnDb = IsMacAddrFoundInMngDb(macAddress);
+
+    /* print out table row */
+    /* the row is colored, if it is a candidate for registering */
+    /* the terminals inUse/foundInDb may be not the candidate */
+    if(inUse || foundOnDb){
+      printf("<tr align=middle>\n");
+    }else{
+      printf("<tr style='background-color: rgb(255,255,204);' align=middle>\n");
+    }
+
+    /* check radio button in first row */ 
+    if(firstRow){
+      printf("<td><input type='radio' name='macaddr' value='%s' checked></td>\n", macAddress);
+      firstRow=FALSE;
+    }else{
+      printf("<td><input type='radio' name='macaddr' value='%s'></td>\n", macAddress);
+    }
+
+    /* show macAddress, vendor, ipv4,ipv6 */
+    printf("<td>%s</td>\n", macAddress);
+    printf("<td>%s</td>\n",vendor);
+    printf("<td>%s</td>\n",ipv4);
+    printf("<td>%s</td>\n",ipv6);
+
+    /* show flags for inUse/foundInDb */
+    if(inUse) printf("<td>*</td>\n");
+    else  printf("<td><br></td>\n");
+    if(foundOnDb) printf("<td>*</td>\n");
+    else  printf("<td><br></td>\n");
+    printf("</tr>\n");
+  }
+}
+
+/*********************************************/
+/* put mac regsitered list the client            */
+/*********************************************/
+void putMacRegListToClient(char* userId, char* extraId){
+
+  char deviceName[WORDMAXLN]="";
+  char entryDate[WORDMAXLN]="";
+  char limitDate[WORDMAXLN]="";
+  char status[WORDMAXLN]="";
+  char macAddress[ADDRMAXLN]="";
+  char mailAddress[BUFFMAXLN]="";
+
+  /* get registered mac list form db and insert */
+  while(GetNextMacAddrFromMngDb(userId,extraId,macAddress,deviceName,
+                               entryDate,limitDate,status,mailAddress)){
+
+
+    printf("<tr align=middle>\n");
+    printf("<td>%s</td>\n", macAddress);
+    printf("<td>%s</td>\n",deviceName);
+    printf("<td>%s</td>\n",entryDate);
+    printf("<td>%s</td>\n",limitDate);
+    printf("<td>%s</td>\n",status);
+    printf("<td>%s</td>\n",mailAddress);
+    printf("</tr>\n");
+  }
+}
+
+/*********************************************/
+/* put some message to the client            */
+/*********************************************/
+void putMessageToClient(char *message)
+{
+  printf("Content-type: text/html\r\n\r\n");
+  printf("<HTML><HEAD><TITLE>OpengateMsg</TITLE></HEAD> \r\n");
+  printf("<BODY>\r\n");
+  printf("%s\r\n",     message);
+  printf("</BODY></HTML> \r\n\r\n");
+}
+
+/************************************************/
+/* send page for returning to the previous page */
+/************************************************/
+void returnToRedirectedPage(char* redirectedUrl, char* language){
+  
+  char returndoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+  char* waitTime="10";
+  /* make read in path to the document */
+  snprintf(returndoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,GetConfValue("ReturnDoc"));
+
+  /* send header */
+  printf("Content-type: text/html\r\n\r\n");
+  
+  if((fp=fopen(returndoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, returndoc);
+    printf("Error! \r\n\r\n");
+    return;
+  }
+
+  if(!isNull(GetConfValue("ReturnWaitTime"))){
+    waitTime=GetConfValue("ReturnWaitTime");
+  }
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%WAITTIME%%", waitTime);
+    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
+    printf("%s",buff);    
+  }
+  fclose(fp);
+}
+
+/************************************/
+/* split value for indicated name   */
+/* in content  "name=value&..."     */
+/************************************/
+void split(char content[], char *name[], char *value[], char *next[])
+{
+  char *pstr;
+  
+  /* set default */
+  name[0]=content;
+  value[0]=content+strlen(content);
+  next[0]=value[0];
+
+  /* set name end */
+  if((pstr=strchr(name[0],(int)'='))==NULL){
+    next[0]=NULL;
+    return;
+  }
+  *pstr='\0';
+  
+  /* set value start */
+  pstr++;
+  value[0]=pstr;
+  
+  /* set value end */
+  if((pstr=strchr(value[0],'&'))==NULL){
+    next[0]=NULL;
+    return;
+  }
+  *pstr='\0';
+
+  /* set next start */
+  pstr++;
+  next[0]=pstr;
+
+  return;
+}
+
+/**********************************/
+/* decode text coding in web post */
+/**********************************/
+void decode(char *string)
+{
+  char *pcheck, *pinsert;
+
+  pcheck=pinsert=string;
+  while(*pcheck != '\0'){
+    if(*pcheck == '+'){
+      *pinsert = ' ';
+    }else if(*pcheck == '%'){
+      *pinsert=(char)(hex2num(*(pcheck+1))*16 + hex2num(*(pcheck+2)));
+      pcheck+=2;
+    }else{
+      *pinsert=*pcheck;
+    }
+    pcheck++;
+    pinsert++;
+  }
+  *pinsert=*pcheck;
+}
+
+
+/*****************************************************/
+/* replace beforeStr to afterStr in string in buff   */
+/*****************************************************/
+int htmlReplace(char* buff,char *beforeStr,char *afterStr)
+{
+  char *pBuff , *pNext;
+  char tempBuff[BUFFMAXLN];
+  
+  if(buff==NULL) return 1;
+
+  strncpy(tempBuff, buff, BUFFMAXLN);
+  strncpy(buff,"",BUFFMAXLN);
+  
+  for(pBuff = tempBuff;
+      (pNext=StrSplit(pBuff, beforeStr)) != NULL;
+      pBuff = pNext){
+    strncat(buff,pBuff,BUFFMAXLN);
+    strncat(buff,afterStr,BUFFMAXLN);
+  }
+  strncat(buff,pBuff,BUFFMAXLN);
+  
+  return 0;
+}
+
+/*****************************************************/
+/* split a str at delimStr and return the point      */
+/*****************************************************/
+char* strSplit(char* str,const char* delimStr)
+{
+    char* delimPoint = strstr(str,delimStr);
+    const size_t delimLen = strlen(delimStr);
+
+    if(delimPoint == NULL) return NULL;
+    else{
+        *delimPoint = '\0';
+        delimPoint += delimLen; 
+    }
+    return delimPoint;
+}
+
+
+/**********************/
+/* get HTTP-Cookie    */
+/**********************/
+  /* cookie string examples 
+  "OpengateMmng=de..ac1&Userid=user1"
+  "OpengateMmng=de..ac1&Userid=user1; xxx=..; yyy=.."
+  "xxx=..; yyy=..; OpengateMmng=de..ac1&Userid=user1"
+  */
+int getHttpCookie(char *cookie, char* cookieName){
+  char content[BUFFMAXLN];
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr=NULL;
+  char *ptrNext=NULL;
+
+  /* reset buffer */
+  cookie[0]='\0';
+
+ /* if exist cookie, copy it to work area */
+  if(isNull(getenv("HTTP_COOKIE"))) return FALSE;
+  strncpy(content, getenv("HTTP_COOKIE"), BUFFMAXLN);
+  ptr=content;
+
+  /* search 'OpengateMmng' cookie string (terminated by ; or \0) */
+  while(ptr!=NULL){
+    if((ptrNext=strstr(ptr, "; "))==NULL) break;          /* search "; " */
+    *ptrNext='\0';                               /* overwrite string end */
+    ptrNext++;                                 /* pointer to next string */
+    while(!isNull(ptrNext)&&*ptrNext==' ') ptrNext++;     /* skip spaces */
+    if(strstr(ptr, cookieName)==ptr) break;          /* exit at matching */
+    ptr=ptrNext;                                    /* check next string */
+  }
+
+  /* get valuses of cookie from "OpengateMmng=de..ac1" */
+  while(ptr!=NULL){
+    split(ptr, name, value, next);
+
+    if(strstr(name[0], cookieName)!=NULL){
+      strncpy(cookie, value[0], SIDMAXLN);
+    }
+    ptr=next[0];
+  }
+  
+  if(isNull(cookie)) return FALSE;
+  else return TRUE;
+}
+
+/*************************************
+compare received cookie to previously saved one
+*************************************/
+int isCorrectCookie(char* cookie, int userType){
+  char userId[USERMAXLN];
+  char extraId[USERMAXLN];
+
+  /* compare http received cookie and DB readin cookie */
+  switch(userType){
+  case NORMALUSER:
+    GetHttpCookie(cookie, GetConfValue("AuthUserCookie"));
+    if(IsCookieFoundInWorkDb(cookie,userId,extraId,NORMALUSER)) return TRUE;
+    else return FALSE;
+  case ADMINUSER:
+    GetHttpCookie(cookie, GetConfValue("AuthAdminCookie"));
+    if(IsCookieFoundInWorkDb(cookie,userId,extraId,ADMINUSER)) return TRUE;
+    else return FALSE;
+  }
+  return FALSE;
+}
+
+/********************************************/
+/* analyze update request and execute request    */
+/********************************************/
+int analyzeUpdateRequestAndExecute(char *requestStr, char* userId, char* extraId)
+{
+  char *name[1];
+  char *value[1];
+  char *next[1];
+  char *ptr;
+  char macAddr[ADDRMAXLN];
+  int modified=FALSE;    /* database modification is executed */
+  int ret;
+  char content[BUFFMAXLN];
+
+  /* if null string, return */
+  if(isNull(requestStr)) return FALSE;
+
+  /* copy request string to work area */
+  strncpy(content, requestStr, BUFFMAXLN);
+
+  /* split request item and execute the request */
+  ptr=content;
+  while(ptr!=NULL){
+
+    /* pick up next item */
+    split(ptr, name, value, next);
+    
+    /* if item=delete, execute delete */
+    if(strcmp(value[0], "delete")==0){
+      strncpy(macAddr, name[0], ADDRMAXLN);
+      decode(macAddr);
+      if(ConvertMacAddr(macAddr)){
+       ret=DelMacAddrFromMngDb(macAddr);
+       if(ret){
+         modified=TRUE;
+         PutMacModifyLogToMngDb(userId, extraId, macAddr, 'D');
+         PutMacAddressToServers(macAddr);
+       }
+      }
+    }
+
+    /* if item = extend, execute extend */
+    else if(strcmp(value[0], "extend")==0){
+      strncpy(macAddr, name[0], ADDRMAXLN);
+      decode(macAddr);
+      if(ConvertMacAddr(macAddr)){
+       ret=RenewMacAddrInMngDb(macAddr);
+       if(ret){
+         modified=TRUE;
+         PutMacModifyLogToMngDb(userId, extraId, macAddr, 'E');
+         PutMacAddressToServers(macAddr);
+       }
+      }
+    }
+
+    /* if item = pause, execute pause */
+    else if(strcmp(value[0], "pause")==0){
+      strncpy(macAddr, name[0], ADDRMAXLN);
+      decode(macAddr);
+      if(ConvertMacAddr(macAddr)){
+       ret=PauseMacAddrInMngDb(macAddr);
+       if(ret){
+         modified=TRUE;
+         PutMacModifyLogToMngDb(userId, extraId, macAddr, 'P');
+         PutMacAddressToServers(macAddr);
+       }
+      }
+    }
+    
+    /* shift pointer to next item */
+    ptr=next[0];
+  }
+
+  return modified;
+}
+
+
+/*********************************************/
+/* put response to client            */
+/* ownUpdate:1=page is controlled by owner, 0=under admin */
+/*********************************************/
+int putUpdatePageToClient(char *language, char* userId, char* extraId, int ownUpdate, char* redirectedUrl)
+{
+  char responsedoc[BUFFMAXLN];
+  FILE *fp;
+  char buff[BUFFMAXLN];
+  char cookie[SIDMAXLN];
+  char* updateCgi="";
+  char* updateDoc="";
+  char mailDefault[BUFFMAXLN];
+
+  /* select update page for owner or administrator */
+  if(ownUpdate){
+    updateCgi=GetConfValue("OwnCgi");
+    updateDoc=GetConfValue("OwnUpdateDoc");
+  }else{
+    updateCgi=GetConfValue("UpdateCgi");
+    updateDoc=GetConfValue("UpdateDoc");
+  }
+  if(isNull(updateCgi) || isNull(updateDoc)){
+    err_msg("ERR at %s#%d: cannot find cgi/doc for update in conf",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* make read in path to the retry document */
+  snprintf(responsedoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
+         GetConfValue("OpengateDir"),language,updateDoc);
+
+  /* send header */
+  printf("Content-type: text/html\r\n");
+
+  /* if no cookie, make, send, and save cookie */
+  if(!GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
+    CreateCookie(cookie);
+    printf("Set-Cookie: %s=%s;path=/;\r\n", GetConfValue("AuthUserCookie"), cookie);
+    SaveCookieToWorkDb(cookie,userId, extraId, NORMALUSER);
+    MakeMailDefault(userId, extraId, mailDefault);
+    SaveMailDefalutForCookieToWorkDb(cookie, mailDefault);
+  }
+
+  /* end of http header */
+  printf("\r\n");
+
+  if((fp=fopen(responsedoc, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, responsedoc);
+    return FALSE;
+  }
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%CGINAME%%", updateCgi);
+    HtmlReplace(buff, "%%USERID%%", userId);
+    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
+
+    if(strstr(buff, "%%MACLIST%%")!=NULL){
+      PutMacListToClient(userId,extraId);
+    }
+    else if(strstr(buff, "%%USAGELOG%%")!=NULL){
+      PutUsageLogToClient(userId, extraId, language);
+    }
+    else if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(language);
+    }
+    else{
+      printf("%s",buff);    
+    }
+  }
+  fclose(fp);
+  return TRUE;
+}
+
+/*********************************************/
+/* put mac list the client            */
+/*********************************************/
+void putMacListToClient(char* userId, char* extraId){
+
+  char deviceName[WORDMAXLN];
+  char entryDate[WORDMAXLN];
+  char limitDate[WORDMAXLN];
+  char status[WORDMAXLN];
+  char macAddr[ADDRMAXLN];
+  char mailAddress[BUFFMAXLN];
+
+  /* make rows for deletion and extending */
+  /* get registered mac list form db and insert */
+  while(GetNextMacAddrFromMngDb(userId,extraId,macAddr,deviceName,
+                               entryDate,limitDate,status,mailAddress)){
+    printf("<tr align=middle>\n");
+    if(status[0]=='A'){
+      printf("<td><input type=radio name=%s value=extend checked></td>\n",macAddr);
+      printf("<td><input type=radio name=%s value=pause></td>\n",macAddr);
+      printf("<td><input type=radio name=%s value=delete></td>\n",macAddr);
+    }else{
+      printf("<td>-</td>\n");
+      printf("<td>-</td>\n");
+      printf("<td>-</td>\n");
+    }
+    printf("<td>%s</td>\n", macAddr);
+    printf("<td>%s</td>\n",deviceName);
+    printf("<td>%s</td>\n",entryDate);
+    printf("<td>%s</td>\n",limitDate);
+    printf("<td>%s</td>\n",status);
+    printf("</tr>\n");
+  }
+}
+
+/*********************************************/
+/* put usage log to the client            */
+/*********************************************/
+void putUsageLogToClient(char *userId, char* extraId, char* language){
+
+  char macAddr[ADDRMAXLN];
+  char deviceName[WORDMAXLN];
+  char openTime[WORDMAXLN];
+  char gatewayName[WORDMAXLN];
+  int weekday;
+  char str[WORDMAXLN];
+  char* p;
+
+  /* get usage log form db and insert as html table row */
+  while(GetNextUsageLogFromMngDb(userId,extraId,macAddr,deviceName,
+                                openTime,gatewayName,&weekday)){
+
+    /* split hostname only */
+    if((p=strchr(gatewayName,'.'))!=NULL) *p='\0';
+
+    /* put out table row */
+    printf("<tr align=middle>\n");
+    printf("<td>%s</td>\n", macAddr);
+    printf("<td>%s</td>\n",deviceName);
+    printf("<td>%s</td>\n",openTime);
+    printf("<td>%s</td>\n",WeekdayStr(weekday, str, language));
+    printf("<td>%s</td>\n",gatewayName);
+    printf("</tr>\n");
+  }
+}
+
+/**********************************************/
+/* check allowable http-agent defined in conf */
+/**********************************************/
+int isAccessedFromAllowableAgent(void){
+
+  char* pAgent=NULL;
+  char* pRegExPattern=NULL;
+  int found=FALSE;
+
+  /* get agent string. if not, return false */
+  if( isNull(pAgent=getenv("HTTP_USER_AGENT")) ) return FALSE;
+
+  /* get first reg expression in conf. if not, return true(not define=allow all) */
+  if(isNull(pRegExPattern=GetFirstConfValue("AllowableAgentPattern"))){
+    return TRUE;
+  }
+
+  /* loop for patterns in conf */
+  while(!isNull(pRegExPattern)){
+
+    /* if agent is matched to reg ex, return true. */
+    /* last-arg 1 means case sensitive */
+    if(RegExMatch(pAgent, pRegExPattern, 1)){
+      found=TRUE;
+      break;
+    }
+
+    /* get next reg expression in conf */
+    pRegExPattern=GetNextConfValue();
+  }
+
+  /* if fail, print message */
+  if(!found){
+    err_msg("ERR at %s#%d: http-agent[%s] is not allowed in conf file",__FILE__,__LINE__, pAgent);
+  }
+
+  return found;
+}
+
+
+/*******************************/
+/*******************************/
+
+int GetPostData(char *content, int contentMaxLength){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getPostData(%d)", contentMaxLength);
+  ret=getPostData(content, contentMaxLength);
+  if(debug>1) err_msg("DEBUG:%d<=getPostData(..)",ret);
+  return ret;
+}
+
+int GetLangFromQueryString(char* language){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getLangFromQueryString( )");
+  ret=getLangFromQueryString(language);
+  if(debug>1) err_msg("DEBUG:%d<=getLangFromQueryString(%s)",ret,language);
+  return ret;
+}
+
+int GetRedirectedUrlFromQueryString(char* redirectedUrl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getRedirectedUrlFromQueryString( )");
+  ret=getRedirectedUrlFromQueryString(redirectedUrl);
+  if(debug>1) err_msg("DEBUG:%d<=getRedirectedUrlFromQueryString(%s)",ret,redirectedUrl);
+  return ret;
+}
+
+int GetMacAddrFromQueryString(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getMacAddrFromQueryString( )");
+  ret=getMacAddrFromQueryString(macAddress);
+  if(debug>1) err_msg("DEBUG:%d<=getMacAddrFromQueryString(%s)",ret,macAddress);
+  return ret;
+}
+
+int AnalyzeCheckRequest(char *content, int* status, char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>analyzeCheckRequest(%s)", content);
+  ret=analyzeCheckRequest(content, status, macAddress);
+  if(debug>1) err_msg("DEBUG:%d<=analyzeCheckRequest(%d,%s)",ret,*status, macAddress);
+  return ret;
+}
+
+int AnalyzeRegisterRequest(char *content, char* macAddress, char* deviceName, char* mailAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>analyzeRegisterRequest(%s)", content);
+  ret=analyzeRegisterRequest(content, macAddress, deviceName, mailAddress);
+  if(debug>1) err_msg("DEBUG:%d<=analyzeRegisterRequest(%s,%s,%s)",ret, macAddress, deviceName, mailAddress);
+  return ret;
+}
+
+int PutDenyToClient(char *language){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putDenyToClient(%s)",language);
+  ret=putDenyToClient(language);
+  if(debug>1) err_msg("DEBUG:(%d)<=putDenyToClient( )",ret);
+  return ret;
+}
+
+int PutCheckPageToClient(char *language, char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putCheckPageToClient(%s,%s,%s)", 
+                     language,userId,extraId);
+  ret=putCheckPageToClient(language,userId,extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=putCheckPageToClient( )",ret);
+  return ret;
+}
+
+int PutRegisterPageToClient(char *language, char* macAddress, char* deviceName, char* mailAddress, char* userId, char* extraId, int ownReg, char* redirectedUrl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putRegisterPageToClient(%s,%s,%s,%s,%s,%s,%d,%s)", language,macAddress,deviceName,mailAddress,userId,extraId,ownReg, redirectedUrl);
+  ret=putRegisterPageToClient(language, macAddress, deviceName, mailAddress, userId, extraId, ownReg, redirectedUrl);
+  if(debug>1) err_msg("DEBUG:(%d)<=putRegisterPageToClient( )",ret);
+  return ret;
+}
+
+void PutMacCheckListToClient(void){
+  if(debug>1) err_msg("DEBUG:=>putMacCheckListToClient( )");
+  putMacCheckListToClient();
+  if(debug>1) err_msg("DEBUG:<=putMacCheckListToClient( )");
+}
+
+void PutMacRegListToClient(char* userId, char* extraId){
+  if(debug>1) err_msg("DEBUG:=>putMacRegListToClient( )");
+  putMacRegListToClient(userId, extraId);
+  if(debug>1) err_msg("DEBUG:<=putMacRegListToClient( )");
+}
+
+void PutMessageToClient(char *message){
+  if(debug>1) err_msg("DEBUG:=>putMessageToClient(%s)",message);
+  putMessageToClient(message);
+  if(debug>1) err_msg("DEBUG:<=putMessageToClient( )");
+}
+
+void ReturnToRedirectedPage(char* redirectedUrl, char* language){
+  if(debug>1) err_msg("DEBUG:=>returnToRedirectedPage(%s,%s)",redirectedUrl,language);
+  returnToRedirectedPage(redirectedUrl, language);
+  if(debug>1) err_msg("DEBUG:<=returnToRedirectedPage( )");
+}
+
+int ConvertMacAddr(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>convertMacAddr(%s)", macAddr);
+  ret=convertMacAddr(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=convertMacAddr(%s)",ret,macAddr);
+  return ret;
+}
+
+int IsSafeString(char* str, int length){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isSafeString(%s,%d)",str,length);
+  ret=isSafeString(str,length);
+  if(debug>1) err_msg("DEBUG:(%d)<=isSafeString( )",ret);
+  return ret;
+}
+
+int HtmlReplace(char* buff,char *beforeStr,char *afterStr){
+  int ret;
+  if(debug>2) err_msg("DEBUG:=>htmlReplace(%s,%s,%s)",buff,beforeStr,afterStr);
+  ret = htmlReplace(buff, beforeStr, afterStr);
+  if(debug>2) err_msg("DEBUG:(%d)<=htmlReplace( )",ret);
+  return ret;
+}
+
+char* StrSplit(char* str,const char* delimStr){
+  char* ret;
+  if(debug>2) err_msg("DEBUG:=>strSplit(%s,%s)",str,delimStr);
+  ret = strSplit(str, delimStr);
+  if(debug>2) err_msg("DEBUG:(%s)<=strSplit( )",ret);
+  return ret;
+}
+
+int GetHttpCookie(char *cookie, char* cookieName){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getHttpCookie(%s)", cookieName);
+  ret = getHttpCookie(cookie, cookieName);
+  if(debug>1) err_msg("DEBUG:(%d)<=getHttpCookie(%s)",ret, cookie);
+  return ret;
+}
+
+int IsCorrectCookie(char* cookie, int userType){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=> isCorrectCookie(%d)", userType);
+  ret =  isCorrectCookie(cookie,userType);
+  if(debug>1) err_msg("DEBUG:(%d)<= isCorrectCookie(%s)",ret,cookie);
+  return ret;
+}
+
+int GetUserIdFromEnv(char *userid){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getUserIdFromEnv(%s)",userid);
+  ret = getUserIdFromEnv(userid);
+  if(debug>1) err_msg("DEBUG:(%d)<=getUserIdFromEnv( )",ret);
+  return ret;
+}
+
+int GetUserIdFromPostData(char* requestStr, char* userid, char* password){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getUserIdFromPostData(..)");
+  ret = getUserIdFromPostData(requestStr,userid,password);
+  if(debug>1) err_msg("DEBUG:(%d)<=getUserIdFromPostData(,%s,password)",ret,userid);
+  return ret;
+}
+
+int PutAuthRequestPageToClient(char *language, char* cgiName, char* docName, char* redirectedUrl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putAuthRequestPageToClient(%s,%s,%s)",language,cgiName, docName, redirectedUrl);
+  ret=putAuthRequestPageToClient(language,cgiName, docName, redirectedUrl);
+  if(debug>1) err_msg("DEBUG:(%d)<=putAuthRequestPageToClient( )",ret);
+  return ret;
+}
+
+int AnalyzeUpdateRequestAndExecute(char *content, char* userId, char* extraId){
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>analyzeUpdateRequestAndExecute(%s,%s,%s)", content,userId,extraId);
+  ret=analyzeUpdateRequestAndExecute(content,userId,extraId);
+  if(debug>1) err_msg("DEBUG:%d<=analyzeUpdateRequestAndExecute( )",ret);
+  return ret;
+}
+
+int PutUpdatePageToClient(char *language, char* userId, char* extraId, int ownUpdate, char* redirectedUrl){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putUpdatePageToClient(%s,%s,%s,%d,%s)", 
+                     language,userId,extraId,ownUpdate,redirectedUrl);
+  ret=putUpdatePageToClient(language,userId,extraId,ownUpdate,redirectedUrl);
+  if(debug>1) err_msg("DEBUG:(%d)<=putUpdatePageToClient( )",ret);
+  return ret;
+}
+
+void PutMacListToClient(char *userId, char* extraId){
+  if(debug>1) err_msg("DEBUG:=>putMacListToClient(%s,%s)",userId,extraId);
+  putMacListToClient(userId,extraId);
+  if(debug>1) err_msg("DEBUG:<=putMacListToClient( )");
+}
+
+void PutUsageLogToClient(char *userId, char* extraId, char* language){
+  if(debug>1) err_msg("DEBUG:=>putUsageLogToClient(%s,%s,%s)",userId,extraId,language);
+  putUsageLogToClient(userId,extraId,language);
+  if(debug>1) err_msg("DEBUG:<=putUsageLogToClient( )");
+}
+
+int IsAccessedFromAllowableAgent(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isAccessedFromAllowableAgent( )");
+  ret=isAccessedFromAllowableAgent();
+  if(debug>1) err_msg("DEBUG:(%d)<=isAccessedFromAllowableAgent( )",ret);
+  return ret;
+}
diff --git a/mngsrc/error.c b/mngsrc/error.c
new file mode 100644 (file)
index 0000000..80e7062
--- /dev/null
@@ -0,0 +1,136 @@
+/**********************************************************/
+/* output error message to syslog or stdout               */
+/*  from UNIX NETWORK PROGRAMMING,Vol.1,Second Edition,   */
+/*      By W. Richard Stevens, Published By Prentice Hall */
+/*       ftp://ftp.kohala.com/pub/rstevens/unpv12e.tar.gz */
+/**********************************************************/
+
+#include "opengatemmng.h"
+#include       <stdarg.h>              /* ANSI C header file */
+#include       <syslog.h>              /* for syslog() */
+
+int            daemon_proc;
+
+static void    err_doit(int, int, const char *, va_list);
+
+/*************************************************/
+/* Nonfatal error related to a system call.
+ * Print a message and return. */
+/*************************************************/
+void errToSyslog(int i)
+{
+  daemon_proc=i;
+}
+
+void
+err_ret(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_INFO, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/*************************************************/
+/* Fatal error related to a system call.
+ * Print a message and terminate. */
+/*************************************************/
+void
+err_sys(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_ERR, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+/*************************************************/
+/* Fatal error related to a system call.
+ * Print a message, dump core, and terminate. */
+/*************************************************/
+void
+err_dump(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(1, LOG_ERR, fmt, ap);
+       va_end(ap);
+       abort();                /* dump core and terminate */
+       exit(1);                /* shouldn't get here */
+}
+
+/*************************************************/
+/* Nonfatal error unrelated to a system call.
+ * Print a message and return. */
+/*************************************************/
+void
+err_msg(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(0, LOG_INFO, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/*************************************************/
+/* Fatal error unrelated to a system call.
+ * Print a message and terminate. */
+/*************************************************/
+void
+err_quit(const char *fmt, ...)
+{
+       va_list         ap;
+
+       va_start(ap, fmt);
+       err_doit(0, LOG_ERR, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+
+/*************************************************/
+/* Print a message and return to caller.
+ * Caller specifies "errnoflag" and "level". */
+/*************************************************/
+static void
+err_doit(int errnoflag, int level, const char *fmt, va_list ap)
+{
+       int             errno_save, n;
+       char    buf[BUFFMAXLN];
+
+       errno_save = errno;             /* value caller might want printed */
+#ifdef HAVE_VSNPRINTF
+       vsnprintf(buf, sizeof(buf), fmt, ap);   /* this is safe */
+#else
+       vsprintf(buf, fmt, ap);                                 /* this is not safe */
+#endif
+       n = strlen(buf);
+       if (errnoflag)
+               snprintf(buf+n, sizeof(buf)-n, ": %s", strerror(errno_save));
+       strcat(buf, "\n");
+
+       if (daemon_proc) {
+               syslog(level, buf);
+       } else {
+               fflush(stdout);         /* in case stdout and stderr are the same */
+               fputs(buf, stderr);
+               fflush(stderr);
+       }
+       return;
+}
+
+
+/*************************
+ terminate this program
+ used for debug purpose
+*************************/
+void terminateProg(int ret){
+  exit(ret);
+}
diff --git a/mngsrc/getmac.c b/mngsrc/getmac.c
new file mode 100644 (file)
index 0000000..06161a5
--- /dev/null
@@ -0,0 +1,213 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module to get mac address
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/************************************/
+/* arp form is reformed to ndp form */ 
+/* format macAddr for ndp or arp    */
+/* match the form of two program    */
+/* mac addr by arp 00:01:12:0b:..   */
+/* mac addr by ndp 0:1:12:b:..      */
+/************************************/
+int reFormatMacAddr(char* macAddr)
+{
+  int m1,m2,m3,m4,m5,m6;
+  if(sscanf(macAddr, "%x:%x:%x:%x:%x:%x", &m1,&m2,&m3,&m4,&m5,&m6)!=6) return FALSE;
+  snprintf(macAddr, ADDRMAXLN,"%02x:%02x:%02x:%02x:%02x:%02x", m1,m2,m3,m4,m5,m6);
+  return TRUE;
+}
+
+/**********************************************************************/
+/* get MAC address for clientAddr (nnnn:nnnn::nnnn:nnnn) by ndp entry */
+/*  result is stored in queue                                         */
+/**********************************************************************/
+int getMacAddrListFromNdp(char* interface)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  char* firstTokenP;
+  char* secondTokenP;
+  char* thirdTokenP;
+  char macAddr[ADDRMAXLN];
+  char* p;
+  char ifStr[WORDMAXLN];
+  char* ndpPath=NULL;
+
+  /* if null, error return */
+  if(isNull(interface)){
+    err_msg("ERR at %s#%d: NIC device name is not set",__FILE__,__LINE__);
+    return -1;
+  }
+
+  /* exec proc */
+  /* exec proc */
+  if(isNull(ndpPath=GetConfValue("NdpPath"))){
+    err_msg("ERR at %s#%d:ndp path is not set in conf",__FILE__,__LINE__);
+    return -1;
+  }
+  if((fpipe=Popenl(1, "r", ndpPath,"-a",(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ndp -na error",__FILE__,__LINE__);
+    return -1;
+  }
+
+  /* get ndp response */
+  /* skip first title line */
+  if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
+    err_msg("ERR at %s#%d: readin error",__FILE__,__LINE__);
+    Pclose(fpipe);
+    return -1;
+  }
+  
+  /* arp response takes following format           */
+  /* "[IPv6 Addr] [Mac] [InterfaseID] [Expire] [Status] [Flags] [Prbs]" */
+  /* get MAC address from above string             */
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+
+    firstTokenP = strtok(buf," "); /* first token */
+    secondTokenP = strtok(NULL," "); /* second token */
+    thirdTokenP = strtok(NULL," "); /* third token */
+
+    /* skip if invalid address */
+    if(strstr(secondTokenP, ":")==NULL)continue;
+
+    /* if other interface, skip */
+    if(strstr(thirdTokenP, interface)==NULL) continue;
+
+    /* remove interface description */
+    /* form fe80::202:b3ff:fe0a:c30e%fxp1 */
+    snprintf(ifStr, WORDMAXLN, "%%%s", interface);
+    if((p=strstr(firstTokenP, ifStr))!=NULL) *p='\0';
+
+    /* Insert to queue */
+    strncpy(macAddr, secondTokenP, ADDRMAXLN);
+    ReFormatMacAddr(macAddr);
+    Enqueue(macAddr, firstTokenP);
+  }
+
+  Pclose(fpipe);
+  
+  return 0;
+}
+
+/*******************************************************************/
+/* get MAC address for clientAddr (nnn.nnn.nnn.nnn) by arp request */
+/*  result is stored in queue                                      */
+/*******************************************************************/
+int getMacAddrListFromArp(char* interface)
+{
+  char buf[BUFFMAXLN];
+  char *startp;
+  char *endp;
+  FILE *fpipe;
+  char* macAddr;
+  char* ipAddr;
+  char options[WORDMAXLN];
+  char* arpPath=NULL;
+
+  /* if null, error return */
+  if(isNull(interface)){
+    err_msg("ERR at %s#%d: NIC device name is not set",__FILE__,__LINE__);
+    return -1;
+  }
+
+  /* set arp options */
+  snprintf(options, WORDMAXLN, "-a -i %s", interface);
+
+  /* exec arp */
+  if(isNull(arpPath=GetConfValue("ArpPath"))){
+    err_msg("ERR at %s#%d: arp path is not set in conf",__FILE__,__LINE__);
+    return -1;
+  }
+  if( (fpipe=Popenl(1, "r", arpPath, options, (char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec arp error",__FILE__,__LINE__);
+    return -1;
+  }
+  
+  /* get arp response */  
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+
+    /* arp response takes following format           */
+    /* "? (133.49.22.1) at 8:0:20:a5:4:62 [ethernet]"*/
+    /* get ip address from above string             */
+    if((startp=strstr(buf," ("))==NULL) continue;
+    startp=startp+2;
+    if((endp=strstr(startp, ") "))==NULL) continue;
+    
+    /* save as ip address and cut off string at endp */
+    *endp='\0';
+    ipAddr=startp;
+    
+    /* get MAC address from above string             */
+    if((startp=strstr(endp+1," at "))==NULL) continue;
+    startp=startp+4;
+    if((endp=strstr(startp, " "))==NULL) continue;
+    
+    /* save as mac address and cut off string at endp */
+    *endp='\0';
+    macAddr=startp;
+    
+    /* skip if invalid address */
+    if((strstr(macAddr, ":"))==NULL) continue;
+    
+    /* save to queue */
+    Enqueue(macAddr, ipAddr);
+  }
+    
+  /* close pipe */
+  Pclose(fpipe);
+    
+  return 0;
+}
+
+
+/****************************************/
+/****************************************/
+int GetMacAddrListFromArp(char* interface)
+{
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getMacAddrListFromArp(%s)", interface);
+  ret=getMacAddrListFromArp(interface);
+  if(debug>1) err_msg("DEBUG:(%d)<=getMacAddrListFromArp( )",ret);
+
+  return ret;
+}  
+
+int GetMacAddrListFromNdp(char* interface){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getMacAddrListFromNdp(%s)", interface);
+  ret=getMacAddrListFromNdp(interface);
+  if(debug>1) err_msg("DEBUG:(%d)<=getMacAddrListFromNdp( )",ret);
+
+  return ret;
+}
+
+int ReFormatMacAddr(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>reFormatMacAddr(%s)", macAddr);
+  ret=reFormatMacAddr(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=reFormatMacAddr(%s)", ret, macAddr);
+  return ret;
+}
+
diff --git a/mngsrc/getparam.c b/mngsrc/getparam.c
new file mode 100644 (file)
index 0000000..e0acdf8
--- /dev/null
@@ -0,0 +1,582 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for getting parameters from conf file
+
+Copyright (C) 2006 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+
+Programmed by Yoshiaki WATANABE
+
+**************************************************/
+#include "opengatemmng.h"
+#include "../ezxml/ezxml.h"
+
+#define CONFIG_VERSION "0.7.5"
+#define SEPARATOR "/"
+
+int debug=0;
+static ezxml_t xmlRoot=NULL;
+static ezxml_t xmlExtraSet=NULL;
+static ezxml_t xmlAuthServer=NULL;
+static ezxml_t xml=NULL;
+static ezxml_t xmlSave=NULL;
+
+char *getConfValueExtra(char *name);
+char *getConfValue(char *name);
+char *convertToFacilityRaw(char *pValue);
+int selectNextAuthServer(void);
+char *GetConfAuthServer(char *name);
+
+/**************************************************/
+/* Prepare Conf file to use                       */
+/* this is called before syslog setup             */
+/**************************************************/
+int openConfFile(void)
+{
+  char buff[BUFFMAXLN];
+  char *s;
+  char *errMsg;
+
+  /* parse file and make tree */
+  if((xmlRoot = ezxml_parse_file(CONFIGFILE))==NULL){
+
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, " is not found. Call the administrator.</H3><BR>",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* to check error, convert to xml */
+  s=ezxml_toxml(xmlRoot);  free(s);
+  
+  /* if failed, show error message */
+  errMsg=(char *)ezxml_error(xmlRoot);
+
+  if(*errMsg!='\0'){
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, " is illegal. Call the administrator.</H3><HR>",BUFFMAXLN);
+    strncat(buff, "XML parser message: ", BUFFMAXLN);
+    strncat(buff, errMsg, BUFFMAXLN);
+    strncat(buff, "<HR>", BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* check the config file version */ 
+  if(isNull(ezxml_attr(xmlRoot, "ConfigVersion"))||
+     (strcmp(CONFIG_VERSION, ezxml_attr(xmlRoot, "ConfigVersion"))!=0)){
+    strncpy(buff, "<H3>Error: Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE, BUFFMAXLN);
+    strncat(buff, " has mismatch version.<br> Please update it with ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE, BUFFMAXLN);
+    strncat(buff, ".sample.",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  /* check the syslog */
+  if(atoi(GetConfValue("Syslog/Enable")) &&
+     atoi(GetConfValue("Syslog/Facility"))==0){
+
+    /* as the syslog is not prepared, error is send to web*/
+    strncpy(buff, "<H3>Error: correct SYSLOG setting(local0-local7) is not found in Opengate configuration file ",BUFFMAXLN);
+    strncat(buff, CONFIGFILE,BUFFMAXLN);
+    strncat(buff, ". Call the administrator.</H3><BR>",BUFFMAXLN);
+    PutMessageToClient(buff);
+
+    return -1;
+  }
+
+  return 0;
+}
+
+/**************************************************/
+/*  initialize the Config                         */
+/**************************************************/
+void initConf(void)
+{
+  /* as debug flag is used many times, put it in gloval variable */
+  debug=atoi(getConfValue("Debug"));
+}
+
+/**************************************************/
+/* Finish Conf file usage                         */
+/**************************************************/
+void closeConfFile(void)
+{
+  if(xmlRoot!=NULL)ezxml_free(xmlRoot);
+}
+
+/**************************************************/
+/* Setup pointer to the matched ExtraSet          */ 
+/**************************************************/
+void setupConfExtra(char * userId,char *extraId)
+{
+  char* progName;
+  char useridfull[USERMAXLN]; /* userid@extraid */
+
+  /* setup long userid (userid@extraid) */
+  ConcatUserId(useridfull, userId, extraId);
+
+  /* init as no ExtraSet */
+  xmlExtraSet=NULL;
+
+  /* search the matching extra set (first match is employed) */
+  for(xml=ezxml_child(xmlRoot, "ExtraSet"); xml; xml=xml->next){
+    
+    /* if ExtraId is exist, check it */
+    if(!isNull(ezxml_attr(xml, "ExtraId"))){
+
+      /* if not match, go to next ExtraSet */
+      /* ('default' indicated in conf matchs to Null-extraId) */
+      if(isNull(extraId)){
+       if(strcmp("default", ezxml_attr(xml, "ExtraId"))!=0)continue;
+      }else{
+       if(strcmp(extraId, ezxml_attr(xml, "ExtraId"))!=0)continue;
+      }
+    }
+
+    /* if userID pattern is exist, check it */
+    if(!isNull(ezxml_attr(xml, "UserIdPattern"))){
+
+      /* if not matched, go to next ExtraSet. last-arg 0 means ingore-case */
+      if(RegExMatch(userId,ezxml_attr(xml,"UserIdPattern"),0)==FALSE){
+       continue;
+      }
+    }
+
+    /* if UserExtraPattern is exist, check it */
+    /*  UserExtraPattern = REGEX pattern matching to "userid@extraid" */
+    if(!isNull(ezxml_attr(xml, "UserExtraPattern"))){
+
+      /* if not matched, go to next ExtraSet. last-arg 0 means ingore-case */
+      if(RegExMatch(useridfull,ezxml_attr(xml,"UserExtraPattern"),0)==FALSE){
+       continue;
+      }
+    }
+
+    /* if UserExtraPtternNot is exist, check it */
+    /*  UserExtraPatternNot = REGEX pattern NOT matching to "userid@extraid" */
+    if(!isNull(ezxml_attr(xml, "UserExtraPatternNot"))){
+
+      /* if matched, go to next ExtraSet. last-arg 0 means ingore-case */
+      if(RegExMatch(useridfull,ezxml_attr(xml,"UserExtraPatternNot"),0)==TRUE){
+       continue;
+      }
+    }
+
+    /* found matched ExtraSet */
+    break;
+  }
+
+  /* if found a matched ExtraSet, save the pointer */
+  if(xml!=NULL) xmlExtraSet=xml;
+
+  /* change syslog setting */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  progName=getProgramName();
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* reset config setting */
+  InitConf();
+}
+
+/***********************************************/
+/* regular expression matching                 */
+/*  inStr : string to match                    */
+/*  regEx : regular expression                 */
+/*  caseSensitive : 0=ignore case, 1=sensitive */
+/***********************************************/
+int regExMatch(const char *inStr, const char *regEx, int caseSensitive)
+{
+  regex_t reg;
+  int errcode;
+  int match;
+  char errbuff[WORDMAXLN];
+
+  /* compile regex */
+  if(caseSensitive){
+    errcode=regcomp(&reg, regEx, REG_NOSUB|REG_EXTENDED);
+  }else{
+    errcode=regcomp(&reg, regEx, REG_NOSUB|REG_EXTENDED|REG_ICASE);
+  }
+
+  /* if error, return false */
+  if(errcode!=0){
+    regerror(errcode, &reg, errbuff, WORDMAXLN);
+    err_msg("ERR at %s#%d: regex message=%s",__FILE__,__LINE__,errbuff);
+    match=FALSE;
+  }
+  
+  /* if compile is success, check the input string */
+  else{
+    if(regexec(&reg, inStr, (size_t)0, NULL, 0)==0) match=TRUE;
+    else match=FALSE;
+  }
+
+  regfree(&reg);
+
+  return match;
+}
+
+/**************************************************/
+/*  get a value for name from Conf file           */
+/*  the name[aa/bb/cc] means the path             */
+/*  if ID is set, extraSet value is overlayed */
+/**************************************************/
+char *getConfValue(char *name)
+{
+  char *pValue;
+  char *pValueExtra;
+  char *pStr;
+  char buff[BUFFMAXLN];
+
+  /* AuthServer setting is done in other routine */
+  if(strstr(name,"AuthServer/")==name) return GetConfAuthServer(name);
+
+  /* copy name to work area */
+  strncpy(buff,name,BUFFMAXLN);
+
+  /* get first token */
+  pStr=strtok(buff, SEPARATOR);
+
+  /* set search start to root of tree */
+  xml=xmlRoot;
+
+  /* search the tree node for the name */
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get, write error message */
+  if(pValue==NULL){
+    err_msg("ERR at %s#%d: cannot get %s from conf file",__FILE__,__LINE__,name);
+  }
+
+  /* get value in extra set matched to ID */
+  /* if name is matched in first level, reset all child setting */
+  /* in this section, many parameters are not set */
+  if(!isNull(pValueExtra=getConfValueExtra(name))){
+    pValue=pValueExtra;
+  }
+
+  /* if syslog facility, the id is converted to raw value */
+  if(strcmp(name,"Syslog/Facility")==0){
+    pValue=convertToFacilityRaw(pValue);
+  }
+
+  /* return found value */
+  return pValue;
+}
+
+/************************************************/
+/* get the value in extra set matched to ID     */
+/************************************************/
+char *getConfValueExtra(char *name)
+{
+  char *pStr;
+  char buff[BUFFMAXLN];
+  ezxml_t xml;
+
+  if(xmlExtraSet==NULL) return "";
+
+  /* extract first token in name */
+  strncpy(buff,name,BUFFMAXLN);
+  pStr=strtok(buff, SEPARATOR);  
+
+  /* get a first level matched node in extra set */
+  /* the first level is not included in the following loop */
+  /* as to prevent partial overlay of sub level value */
+  xml=ezxml_child(xmlExtraSet, pStr);
+  if(xml==NULL) return "";
+
+  /* search the node matched to name */
+  pStr=strtok(NULL, SEPARATOR);
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* return the found value */
+  return ezxml_txt(xml);
+}
+
+
+/***************************************************/
+/*  get a value for AuthServer param from Conf file*/
+/*  the name[AuthServer/bb/cc] means the path      */
+/***************************************************/
+char *getConfAuthServer(char *name)
+{
+  char *pValue;
+  char *pStr;
+  char buff[BUFFMAXLN];
+  ezxml_t xml;
+
+  /* copy name to work area */
+  strncpy(buff,name,BUFFMAXLN);
+
+  /* get first token */
+  pStr=strtok(buff, SEPARATOR);
+
+  /* it must be AuthServer. if not return */
+  if(strcmp(pStr, "AuthServer")!=0)return NULL;
+
+  /* if authserver pointer is not set, set it */
+  if(xmlAuthServer==NULL){
+    if(!selectNextAuthServer()) return NULL;
+  }
+
+  /* set search start to the saved pointer */
+  xml=xmlAuthServer;
+
+  /* search the tree node for the name */
+  pStr=strtok(NULL, SEPARATOR);
+  while(pStr!=NULL){
+    xml=ezxml_child(xml, pStr);
+    pStr=strtok(NULL, SEPARATOR);
+  }
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get Protocol, write error message */
+  if(isNull(pValue)
+     && (strcmp(name,"AuthServer/Protocol")==0) ){
+    err_msg("ERR at %s#%d: cannot get %s from conf file",__FILE__,__LINE__,name);
+  }
+
+  /* return found value */
+  return pValue;
+}
+
+/**********************************/
+/* select next authserver setting */
+/**********************************/
+int selectNextAuthServer(void){
+
+  ezxml_t xmlTmp; /* temporary variable */
+
+  /* first call (initialize) */
+  /* xmlAuthPointer is the static variable to save authserver pointer */
+  if(xmlAuthServer==NULL){
+
+    /* if not set, search the first authserver pointer */
+     xmlAuthServer=ezxml_child(xmlRoot, "AuthServer");
+     
+     /* if authserver is found in extra set, pointer is moved to it */ 
+     if(xmlExtraSet!=NULL){
+       xmlTmp=ezxml_child(xmlExtraSet, "AuthServer");
+       if(xmlTmp!=NULL){
+        xmlAuthServer=xmlTmp;
+       }
+     }
+  }
+
+  /* successive calls */
+  /* pointer is moved to next */
+  else{
+    xmlAuthServer=ezxml_next(xmlAuthServer);
+  }
+
+  /* if not found return False */
+  if(xmlAuthServer==NULL){
+    return FALSE;
+  }else{
+    return TRUE;
+  }
+}
+
+/**********************************************
+reset pointer for auth server list
+**********************************************/
+void resetAuthServerPointer(void){
+  xmlAuthServer=NULL;
+}
+
+/***********************************************/
+/* Convart the syslog facility id to raw value */
+/***********************************************/
+char *convertToFacilityRaw(char *pValue)
+{
+  static char facility[WORDMAXLN];
+  int rawValue;
+
+  if     (strcmp(pValue, "local0")==0) rawValue=LOG_LOCAL0;
+  else if(strcmp(pValue, "local1")==0) rawValue=LOG_LOCAL1;
+  else if(strcmp(pValue, "local2")==0) rawValue=LOG_LOCAL2;
+  else if(strcmp(pValue, "local3")==0) rawValue=LOG_LOCAL3;
+  else if(strcmp(pValue, "local4")==0) rawValue=LOG_LOCAL4;
+  else if(strcmp(pValue, "local5")==0) rawValue=LOG_LOCAL5;
+  else if(strcmp(pValue, "local6")==0) rawValue=LOG_LOCAL6;
+  else if(strcmp(pValue, "local7")==0) rawValue=LOG_LOCAL7;
+  else rawValue=0;
+
+  snprintf(facility, WORDMAXLN, "%d", rawValue);
+
+  return facility;
+}
+
+/**************************************************/
+/*  get the first value as previous call           */
+/*  (next node of the lowest level of tree)       */  
+/**************************************************/
+char *getFirstConfValue(char* name)
+{
+   char *pValue;
+   pValue=GetConfValue(name);
+
+  /* save the pointer now */
+   xmlSave=xml;
+
+  /* return found value */
+  return pValue;
+}
+
+/**************************************************/
+/*  get the next value as previous call           */
+/*  (next node of the lowest level of tree)       */  
+/**************************************************/
+char *getNextConfValue(void)
+{
+  char *pValue;
+
+  /* recover previous pointer */
+  xml=xmlSave;
+
+  /* get next node */
+  if(xml==NULL) return "";
+  xml = ezxml_next(xml);
+
+  /* save for next call */
+  xmlSave=xml;
+
+  /* get the node value */
+  pValue= ezxml_txt(xml);
+
+  /* if not get, write error message */
+  if(pValue==NULL) return "";
+
+  /* return found value */
+  return pValue;
+}
+
+
+/***********************************************/
+/***********************************************/
+int OpenConfFile(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>openConfFile( )");
+  ret = openConfFile();
+  if(debug>1) err_msg("DEBUG:(%d)<=openConfFile( )",ret);
+  return ret;
+}
+
+void CloseConfFile(void){
+  if(debug>1) err_msg("DEBUG:=>closeConfFile( )");
+  closeConfFile();
+  if(debug>1) err_msg("DEBUG:<=closeConfFile( )");
+}
+
+void SetupConfExtra(char *userId, char *extraId){
+  if(debug>1) err_msg("DEBUG:=>setupConfExtra(%s,%s)",userId, extraId);
+  setupConfExtra(userId, extraId);
+  if(debug>1) err_msg("DEBUG:<=setupConfExtra( )");
+}
+
+char *GetConfValue(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfValue(%s)",name);
+  ret=getConfValue(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfValue( )",ret);
+  return ret;
+}
+
+char *GetConfValueExtra(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfValueExtra(%s)",name);
+  ret=getConfValueExtra(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfValueExtra( )",ret);
+  return ret;
+}
+
+char *GetConfAuthServer(char *name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getConfAuthServer(%s)",name);
+  ret=getConfAuthServer(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getConfAuthServer( )",ret);
+  return ret;
+}
+
+int SelectNextAuthServer(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>selectNextAuthServer( )");
+  ret=selectNextAuthServer();
+  if(debug>1) err_msg("DEBUG:(%d)<=selectNextAuthServer( )",ret);
+  return ret;
+}
+
+void InitConf(void){
+  if(debug>1) err_msg("DEBUG:=>initConf( )");
+  initConf();
+  if(debug>1) err_msg("DEBUG:<=initConf( )");
+}
+
+int RegExMatch(const char *inStr, const char *regEx, int caseSensitive){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>regExMatch(%s,%s)",inStr,regEx,caseSensitive);
+  ret=regExMatch(inStr, regEx,caseSensitive);
+  if(debug>1) err_msg("DEBUG:(%d)<=regExMatch( )",ret);
+  return ret;
+}
+  
+void ResetAuthServerPointer(void){
+  if(debug>1) err_msg("DEBUG:=>resetAuthServerPointer( )");
+  resetAuthServerPointer();
+  if(debug>1) err_msg("DEBUG:<=resetAuthServerPointer( )");
+}
+
+char *GetFirstConfValue(char* name){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getFirstConfValue( )");
+  ret=getFirstConfValue(name);
+  if(debug>1) err_msg("DEBUG:(%s)<=getFirstConfValue( )",ret);
+  return ret;
+}
+
+char *GetNextConfValue(){
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getNextConfValue( )");
+  ret=getNextConfValue();
+  if(debug>1) err_msg("DEBUG:(%s)<=getNextConfValue( )",ret);
+  return ret;
+}
+
diff --git a/mngsrc/ipfw.c b/mngsrc/ipfw.c
new file mode 100644 (file)
index 0000000..94f4290
--- /dev/null
@@ -0,0 +1,476 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+
+ module for Controling ipfw 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemmng.h"
+
+char ruleNumber[WORDMAXLN];  /* ipfw rule number in string form */
+
+static void sigFunc(int signo);
+
+/******************************************************************
+ open gate for clientAddr
+  if forced=TRUE, ignore checking for address overlapping
+      return=ruleNumber. if overlapped ip return=(-1)*ruleNumber
+******************************************************************/
+int openClientGate(char *clientAddr, int forced, char* userId, char* extraId, char* macAddress)
+{
+  int fd=0;
+  int retNum;
+  struct stat st;
+  char* lockFile;
+  int lockFileExist=TRUE;
+  char userIdLong[WORDMAXLN];
+
+  Sigfunc *defaultSigFunc;
+
+  /* prepare userid-long as [userid@extraid] */
+  strncpy(userIdLong, userId, WORDMAXLN);
+  if(!isNull(extraId)){
+    strncat(userIdLong, "@", WORDMAXLN);
+    strncat(userIdLong, extraId, WORDMAXLN);
+  }
+
+  /* exclusive exec of ipfw to avoid overlapped rule number */
+  /**** prepare ****/
+  /* if not found lock is ignored */
+  lockFile=GetConfValue("LockFile");
+  if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
+  else lockFileExist=TRUE;
+
+  /* if lock file exists, exec lock */
+  if(lockFileExist){
+    /* open lockfile */
+    fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+    if(fd==-1){
+      err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
+      return -1;
+    } 
+
+    /* set timeout */
+    if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
+      err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
+      Close(fd);
+      return 1;
+    }
+    alarm(atoi(GetConfValue("LockTimeout")));
+    
+    /* lock */
+    if(Lock(fd)<0){
+      err_msg("ERR at %s#%d: lock error",__FILE__,__LINE__);
+      Close(fd);
+      return -1;
+    }
+
+    /* reset timeout */
+    signal(SIGALRM, defaultSigFunc);
+    alarm(0);
+  }
+
+  /**** read rules ****/
+  if((retNum=GetRuleNumber(clientAddr, forced))<0){
+    /* fail then unlock */
+    if(lockFileExist){
+      Unlock(fd);
+      Close(fd);
+    }
+    return retNum; /* perhaps aleady registered addr is -retNum */
+  }
+
+  /**** write rules ****/
+  /* branch by perl script control flag */
+  if(atoi(GetConfValue("IpfwScript/Enable"))){
+    /********** use perl script to control firewall ************/
+
+    if(Systeml(1, GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
+              ruleNumber,clientAddr,userIdLong,macAddress,"-",
+              GetConfValue("IpfwTagNumber"),(char *)0) != 0){
+      err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
+      retNum=1;  /* abnormal */
+    }
+  }
+
+  else{
+    /********** direct control of firewall **********************/
+    /********** add outgoing ipfw rule for the client *************/
+    if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
+              "count","tag",GetConfValue("IpfwTagNumber"),
+              "ip","from",clientAddr,"to","any",
+              "//", userIdLong, (char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
+      retNum=1;  /* abnormal */
+    }
+    
+    if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
+              "count","tag",GetConfValue("IpfwTagNumber"),
+              "ip","from","any","to",clientAddr,
+              "//", userIdLong, (char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
+      retNum=1; /* abnormal */
+    }
+  }
+
+  /* unlock */
+  if(lockFileExist){
+    Unlock(fd);
+    Close(fd);
+  }
+  
+  return retNum;
+}
+
+
+/******************************************************************
+ close gate for clientAddr for the rule number                  
+******************************************************************/
+void closeClientGate(int ruleNumber)
+{
+  int count;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* count rule */
+  count=CountRuleNumber(ruleNumber);
+
+  if(count>0){
+    /* exec ipfw del */
+    /* [ipfw del rule] deletes all rule of the rule number at one call */
+    if(Systeml(1, GetConfValue("IpfwPath"),"delete",ruleNumberStr,(char *)0) != 0){
+      err_msg("ERR at %s#%d: exec ipfw del error",__FILE__,__LINE__);
+    }
+  }
+}
+
+/**************************************
+ get unused ipfw rule number       
+ error if addr is already in rules  
+ if forced=TRUE, ignore checking for address overlapping
+ return value ret>0: acquired rule number that can be used 
+              ret=-1: no rule number available 
+              ret=-2: some system error occured 
+              ret=-num: the ip address is already registered in rule 'num' 
+**************************************/
+int getRuleNumber(char *clientAddr, int forced)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int num,newNum,readinNum;
+  int ipfwmin;
+  int ipfwmax;
+  int ipfwinterval;
+  int portStatus;
+  int fileStatus;
+  char* p;
+
+  enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
+
+  /* exec ipfw list and open pipe */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
+      err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* search unused rule number in the list read from pipe */
+  /* check duplication of clientAddr to existing rules */
+
+  newNum=-1;
+  readinNum=0;
+  portStatus=NOTFOUND;
+  fileStatus=NORMAL;
+
+  /* get rule range from config */
+  ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
+  ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
+  ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
+
+  /* each port is checked whether it can be used for new rule or not */
+  for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
+
+    /* skip rules smaller than num */
+    while(readinNum<num){
+      if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
+       if(feof(fpipe)==1) fileStatus=EOF; 
+       else fileStatus=ABNORMAL;
+       break;
+      }
+      if( sscanf(buf, "%d", &readinNum) !=1 ){
+       err_msg("ERR at %s#%d: abnormal ipfw response[ %s ]",
+               __FILE__,__LINE__, buf);
+       fileStatus=ABNORMAL; /* abnormal responsem exit internal loop */
+       break;
+      }
+    }
+
+    if(fileStatus==ABNORMAL){
+      /* abnormal file proc, exit external loop */ 
+      break;
+    }
+
+    if(fileStatus==EOF){
+      /* EOF before reading a rule that is larger or equal to num */
+      /* it means that num can be used for new client */
+      portStatus=FOUND;
+      newNum=num;
+      break;
+    }
+
+    /* at this point, readinNum is larger or equal to num */
+    /* check number duplication */
+    if(readinNum==num){
+
+      /* if clientAddr found in the existing rule, then duplicate err exit */
+      /* if in forced mode, ignore the checking */
+      if(!forced){
+       if(((p=(char*)strstr(buf+1,clientAddr))!=NULL)
+          && isspace(*(p-1))
+          && !isalnum(*(p+strlen(clientAddr)))){
+         newNum=num;
+         portStatus=DUP;
+         break;
+       } else{
+         continue;
+       }
+      }
+      continue;
+    }
+    /* at this point, readNum is larger than num */
+    /* it means that num can be used for new client */
+    newNum=num;
+    portStatus=FOUND;
+
+    break;
+  }
+  
+  /* close pipe */
+  Pclose(fpipe);
+    
+  if(fileStatus==ABNORMAL){
+    err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
+    return -2;
+  }
+  if(portStatus==NOTFOUND){
+    err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
+    return -1;
+  }
+  if(portStatus==DUP){
+    snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
+    return -newNum;
+  }
+
+  snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
+  return newNum;
+}
+
+/*******************************
+ get packet count from ipfw  
+*******************************/
+int getPacketCount(int ruleNumber)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int rule;
+  int packets,packetsSum;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* exec proc */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"-a","list",ruleNumberStr,(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw -a list error",__FILE__,__LINE__);
+  }
+
+  /* search unused number in the list read from pipe */
+  packetsSum=0;
+    
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+    sscanf(buf, "%d %d", &rule, &packets);   /* get packet count */
+    packetsSum+=packets;
+  }
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return packetsSum;
+}
+
+/**********************************************
+ get rule count registed to a rule number   
+**********************************************/
+int countRuleNumber(int ruleNumber)
+{
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int ruleCount;
+  char ruleNumberStr[WORDMAXLN];
+
+  snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
+
+  /* exec proc */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",ruleNumberStr,(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* count line read from pipe */
+  ruleCount = 0;
+  while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return ruleCount;
+}
+
+/**********************************************
+ function called by signal int              
+**********************************************/
+static void sigFunc(int signo)
+{
+  return;
+}
+
+
+/**********************************************
+get rule numbers table from ipfw rule set
+**********************************************/
+int getRuleTableFromIpfw(DB* ruleTable){
+
+  DBT hashKey;
+  DBT hashVal;
+  FILE *fpipe;
+  char buf[BUFFMAXLN];
+  int ruleNumber;
+  char clientAddr[ADDRMAXLN];
+  char *p;
+  int ipfwmin;
+  int ipfwmax;
+  int ipfwinterval;
+  int resultFlag=FALSE;
+  
+  /* exec ipfw list and open pipe */
+  if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
+    err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
+  }
+  
+  /* get rule range from config */
+  ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
+  ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
+  ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
+  
+  /* get ipfw rule line from pipe */
+  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
+
+    /* get ruleNumber(=leftmost number) */
+    /* 10000 count tag 123 ip from 192.168.0.2 to any .... */
+    /* 10000 count tag 123 ip from any to 192.168.0.2 .... */
+    if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
+
+    /* check the rule number range */
+    if(ruleNumber < ipfwmin)continue;
+    if(ruleNumber > ipfwmax)break;
+
+    /* get clientAddr(=after [from]) in the line */
+    if((p=(char*)strstr(buf, "from"))==NULL) continue;
+    if( sscanf((p+4), "%s", clientAddr) != 1 ) continue;
+    if( (strchr(clientAddr,'.')==NULL) && (strchr(clientAddr,':')==NULL) )continue;
+      
+    /* put to the hash table */
+    resultFlag=TRUE;
+    hashVal.data = &ruleNumber;
+    hashVal.size = sizeof(int);    
+    hashKey.data = clientAddr;
+    hashKey.size = strlen(clientAddr)+1;
+    if(ruleTable->put(ruleTable, &hashKey, &hashVal, 0) == -1) {
+      err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
+    }
+  }
+
+  /* close pipe */
+  Pclose(fpipe);
+
+  return resultFlag;
+}
+
+
+/*********************************************
+ routines for debugging output
+**********************************************/
+int GetRuleNumber(char *clientAddr, int forced)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>getRuleNumber(%s,%d)",clientAddr,forced);
+  ret=getRuleNumber(clientAddr, forced);
+  if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber( )",ret);
+
+  return ret;
+}
+
+int OpenClientGate(char *clientAddr, int forced, char* userId, char* extraId,char* macAddress)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>openClientGate(%s,%d,%s,%s)",clientAddr,forced,userId,extraId,macAddress);
+  ret=openClientGate(clientAddr,forced,userId,extraId,macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=openClientGate( )",ret);
+
+  return ret;
+}
+
+void CloseClientGate(int ruleNumber)
+{
+  if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
+  closeClientGate(ruleNumber);
+  if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
+}
+
+
+int GetPacketCount(int ruleNumber)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
+  ret=getPacketCount(ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
+
+  return ret;
+}
+
+int CountRuleNumber(int ruleNumber)
+{
+  int ret;
+  
+  if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
+  ret=countRuleNumber(ruleNumber);
+  if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
+  
+  return ret;
+}
+
+int GetRuleTableFromIpfw(DB* ruleTable){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
+  ret=getRuleTableFromIpfw(ruleTable);
+  if(debug>1) err_msg("DEBUG:<=getRuleTableFromIpfw( )", ret);
+  return ret;
+}
diff --git a/mngsrc/managementdb.c b/mngsrc/managementdb.c
new file mode 100644 (file)
index 0000000..17750ec
--- /dev/null
@@ -0,0 +1,741 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+
+ module to control management database
+ list of mac addresses
+ list of usage log
+ implemented with MySql 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemmng.h"
+#include <mysql.h>
+
+
+MYSQL mysql;
+
+/******************************************
+initialize management db
+******************************************/
+int initMngDb(void){
+
+  /* set parameters */
+  char *server = GetConfValue("MySqlDb/Server");
+  char *user =  GetConfValue("MySqlDb/User");
+  char *password = GetConfValue("MySqlDb/Password");
+  char *database = GetConfValue("MySqlDb/Database");
+  my_bool reconnect;
+
+/* initialize mysql */
+  mysql_library_init(-1,NULL,NULL);
+  if(mysql_init(&mysql)==NULL){
+     err_msg("ERR at %s#%d: mysql init: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     terminateProg(0);
+  }
+
+  /* Connect to database */
+  if (!mysql_real_connect(&mysql, server,
+                          user, password, database, 0, NULL, 0)) {
+    err_msg("ERR at %s#%d: mysql connect: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+    terminateProg(0);
+  }
+
+  /* set auto-reconnect true */
+  reconnect = TRUE;
+  mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);  
+
+  return TRUE;
+}
+
+/******************************************
+close management db
+******************************************/
+void closeMngDb(void){
+  mysql_close(&mysql);
+  mysql_library_end();
+}
+
+
+/******************************************
+ get nic vendor from management db
+******************************************/
+int getNicVendorFromMngDb(char* macAddress, char* vendor, int bufferLength){
+
+  MYSQL_RES *res;
+  MYSQL_ROW row;
+  int found=FALSE;
+  char queryStr[BUFFMAXLN];
+  char macHeader[ADDRMAXLN];
+
+  /* set default values */
+  vendor[0]='?';
+  vendor[1]='\0';
+  /* prepare query string */
+  strncpy(macHeader, macAddress, ADDRMAXLN);
+  macHeader[8]='\0';
+  snprintf(queryStr, BUFFMAXLN, 
+          "select org from nicvendors where oui='%s'",
+          macHeader);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  res = mysql_use_result(&mysql);
+  
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if not found, return false */
+  if(row==NULL)  found=FALSE;
+
+  /* if found */
+  else {
+    strncpy(vendor, row[0], bufferLength);
+    found=TRUE;
+  }
+
+  mysql_free_result(res);
+  return found;
+}
+
+/******************************************
+ The macAddr is already registered
+******************************************/
+int isMacAddrFoundInMngDb(char* macAddr){
+
+  MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+  int ret;
+
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "select * from macaddrs "
+          " where macAddress='%s' and status!='D'",
+          macAddr);
+  
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return FALSE;
+  }
+  
+  /* store result */
+  res = mysql_store_result(&mysql);
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+  
+  /* if found, return true */
+  if(row!=NULL) ret=TRUE;
+
+  /* if not found, return false */
+  else ret=FALSE;
+
+  mysql_free_result(res);
+  return ret;
+}
+
+/******************************************
+ The count of registered mac address for the user
+******************************************/
+int countMacAddrsForUserInMngDb(char* userId, char* extraId){
+
+  MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+  char countStr[WORDMAXLN];
+  int count=10000;
+
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "select count(*) from macaddrs "
+          " where userId='%s' and extraId='%s' and status!='D'",
+          userId, extraId);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return count;
+  }
+
+  /* store result */
+  res = mysql_store_result(&mysql);
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if found, return values */
+  if(row!=NULL){
+    strncpy(countStr, row[0], WORDMAXLN);
+    count=atoi(countStr);
+  }
+
+  /* free memory area */
+  mysql_free_result(res);
+
+  return count;
+}
+
+/******************************************
+register mac address to the management db
+******************************************/
+int registMacAddrToMngDb(char* macAddr, char* deviceName, char* userId, char* extraId, char* mailAddr){
+
+  char queryStr[BUFFMAXLN];
+  int count;
+
+   /* if alreay registered (and not deleted yet), return false */
+  if(IsMacAddrFoundInMngDb(macAddr)){
+    SetMessage(ExistentMacAddr);
+    return FALSE;
+  }
+  /* if the user registered device more than limit, return false */
+  count=CountMacAddrsForUserInMngDb(userId,extraId);
+  if(count >= atoi(GetConfValue("MaxDevices"))){
+    SetMessage(DeviceCountOver);
+    return FALSE;
+  }
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "insert into macaddrs "
+          "(macAddress, status, device, userId, extraId, "
+          " entryDate, renewDate, limitDate, mailAddress) "
+          "values ('%s','A','%s', '%s', '%s', "
+          " now(), now(), %s, '%s')",
+          macAddr, deviceName, userId, extraId, 
+          GetConfValue("LimitDate"), mailAddr);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*******************************************
+ get next mac address from management db
+ if end of list, return false
+*******************************************/
+int getNextMacAddrFromMngDb(char* userId, char* extraId, char* macAddress, char* deviceName, char* entryDate, char* limitDate, char* status, char* mailAddress){
+
+  static MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+
+  /* set default values */
+  macAddress[0]=deviceName[0]=entryDate[0]=limitDate[0]='\0';
+
+  /* if do not get result yet */
+  if(res==NULL){
+
+    /* prepare query string */
+    snprintf(queryStr, BUFFMAXLN, 
+      "select macAddress, device, entryDate, limitDate, status, mailAddress "
+      "from macaddrs where userId='%s' and extraId='%s' and status!='D'",
+      userId, extraId);
+
+    /* send SQL query */
+    if (mysql_query(&mysql, queryStr)){
+      err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+             mysql_error(&mysql));
+      return FALSE;
+    }
+    
+    /* store result */
+    res = mysql_store_result(&mysql);
+  }
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if found, return values */
+  if(row!=NULL){
+    strncpy(macAddress, row[0],ADDRMAXLN);
+    strncpy(deviceName,row[1],WORDMAXLN);
+    strncpy(entryDate,row[2],WORDMAXLN);
+    strncpy(limitDate,row[3],WORDMAXLN);
+    strncpy(status,row[4],WORDMAXLN);
+    strncpy(mailAddress,row[5],BUFFMAXLN);
+    return TRUE;
+  }
+  /* if not found, free memory area */
+  else{
+    mysql_free_result(res);
+    return FALSE;
+  }
+}
+
+
+/******************************************
+ write mac modification log to the management db
+******************************************/
+int putMacModifyLogToMngDb(char* userId, char* extraId, char* macAddr, char modifyType){
+
+  char queryStr[BUFFMAXLN];
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "insert into macmodify "
+          "(userId, extraId, macAddress, modifyType, modifyDate) "
+          "values ('%s', '%s', '%s', '%c', now())",
+          userId, extraId, macAddr, modifyType);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+     err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+            mysql_error(&mysql));
+     return FALSE;
+  }
+
+  return TRUE;
+}
+
+/******************************************
+ The count of mac address modification in last 24 hours
+******************************************/
+int countMacModifyPerDayInMngDb(char* userId, char* extraId){
+
+  MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+  char countStr[WORDMAXLN];
+  int count=10000;
+
+  /* prepare query string */
+  snprintf(queryStr, BUFFMAXLN, 
+          "select count(*) from macmodify "
+          " where userId='%s' and extraId='%s' and "
+          " modifyDate > adddate(now(), interval -1 day) ",
+          userId, extraId);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return count;
+  }
+
+  /* store result */
+  res = mysql_store_result(&mysql);
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if found, return values */
+  if(row!=NULL){
+    strncpy(countStr, row[0], WORDMAXLN);
+    count=atoi(countStr);
+  }
+
+  /* free memory area */
+  mysql_free_result(res);
+
+  return count;
+}
+
+/******************************************
+delete a mac address registered in the management db
+ do not delete, but set the status flag to 'D'
+******************************************/
+int delMacAddrFromMngDb(char* macAddr){
+
+  char queryStr[BUFFMAXLN];
+
+  /* if the mac data was used, it is preserved for usage log */ 
+  if(IsSessionFoundInMngDb(macAddr)){
+
+    /* prepare query string */
+    /* if session for the mac exists, the row is preserved */
+    /* don't touch device set as status=Inactive */
+    snprintf(queryStr, BUFFMAXLN, 
+            "update macaddrs set status='D',limitDate=now() "
+            " where macAddress='%s' and status='A'", macAddr);
+  }else{
+  
+    /* prepare query string */
+    /* if session does not exist, the row is removed */
+    /* don't touch device set as status=Inactive */
+    snprintf(queryStr, BUFFMAXLN, 
+            "delete from macaddrs "
+            " where macAddress='%s' and status='A'", macAddr);
+  }
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/******************************************
+renew the limit date for a mac address
+ registered in the management db
+******************************************/
+int renewMacAddrInMngDb(char* macAddr){
+
+  char queryStr[BUFFMAXLN];
+
+  /* prepare query string */
+  /* don't touch device set as inactive by admin */
+  snprintf(queryStr, BUFFMAXLN, 
+          "update macaddrs set renewDate=now(), limitDate=%s "
+          " where status='A' and macAddress='%s'", 
+          GetConfValue("LimitDate"),macAddr);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/******************************************
+pause the usage of the device for a mac address
+ registered in the management db
+ (set the limitDate to now)
+******************************************/
+int pauseMacAddrInMngDb(char* macAddr){
+
+  char queryStr[BUFFMAXLN];
+
+  /* prepare query string */
+  /* don't touch device set as inactive by admin */
+  snprintf(queryStr, BUFFMAXLN, 
+          "update macaddrs set limitDate=now() "
+          " where status='A' and macAddress='%s' and limitDate>now()", 
+          macAddr);
+
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/******************************************
+ is the mac address used in session log
+******************************************/
+int isSessionFoundInMngDb(char* macAddr){
+
+  MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+  int ret;
+
+  /* prepare query string */
+  /* get row for addr.entry<session.open<addr.limit */
+  snprintf(queryStr, BUFFMAXLN, 
+          "select * from macaddrs, sessionmd "
+          " where macaddrs.macAddress=sessionmd.macAddress and "
+          " macaddrs.macAddress='%s' and "
+          " entryDate<openTime and openTime<limitDate",
+          macAddr);
+  
+  /* send SQL query */
+  if (mysql_query(&mysql, queryStr)){
+    err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+           mysql_error(&mysql));
+    return FALSE;
+  }
+  
+  /* store result */
+  res = mysql_store_result(&mysql);
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+  
+  /* if found, return true */
+  if(row!=NULL) ret=TRUE;
+
+  /* if not found, return false */
+  else ret=FALSE;
+
+  mysql_free_result(res);
+  return ret;
+}
+
+/*******************************************
+ get next next usage log from management db
+ if end of list, return false
+*******************************************/
+int getNextUsageLogFromMngDb(char* userId, char* extraId, char* macAddr, char* deviceName, char* openTime, char* gatewayName, int* weekday){
+  static MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+
+  /* set default values */
+  macAddr[0]=deviceName[0]=openTime[0]=gatewayName[0]='\0';
+
+  /* if do not get result yet */
+  if(res==NULL){
+
+    /* prepare query string */
+    /* get log where addr.entry < session.open < addr.limit */
+    snprintf(queryStr, BUFFMAXLN, 
+            "select macaddrs.macAddress as mac, device, openTime,  "
+            " gatewayName, weekday(openTime), date(openTime) as dt "
+            " from macaddrs, sessionmd "
+            " where macaddrs.macAddress=sessionmd.macAddress "
+            " and entryDate < openTime and openTime < limitDate "
+            " and %s < openTime "
+            " and userId='%s' and extraId='%s'"
+            " group by dt,mac order by openTime desc",
+            GetConfValue("ShowLogAfter"), userId, extraId);
+
+    /* send SQL query */
+    if (mysql_query(&mysql, queryStr)){
+      err_msg("ERR at %s#%d: mysql query: %s",__FILE__,__LINE__,
+             mysql_error(&mysql));
+      return FALSE;
+    }
+    
+    /* store result */
+    res = mysql_store_result(&mysql);
+  }
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if found, return values */
+  if(row!=NULL){
+    strncpy(macAddr, row[0],ADDRMAXLN);
+    strncpy(deviceName,row[1],WORDMAXLN);
+    strncpy(openTime,row[2],WORDMAXLN);
+    strncpy(gatewayName,row[3],WORDMAXLN);
+    *weekday=atoi(row[4]);
+    return TRUE;
+  }
+  /* if not found, free memory area */
+  else{
+    mysql_free_result(res);
+    return FALSE;
+  }
+}
+
+/*******************************************
+ get next mail address near limit date
+from management db 
+*******************************************/
+int getNextMailAddressFromMngDb(char* mailAddress, char* limitDate, char* device){
+
+  static MYSQL_RES *res=NULL;
+  MYSQL_ROW row;
+  char queryStr[BUFFMAXLN];
+  char* mailTiming=NULL;
+
+  /* set default values */
+  mailAddress[0]=limitDate[0]='\0';
+
+  /* if do not get result yet */
+  if(res==NULL){
+
+    /* get mail send timing from conf file */
+    mailTiming = GetConfValue("Mail/Timing");
+    if(isNull(mailTiming)) return FALSE;
+
+    /* prepare query string */
+    /* [select mailAddress,limitDate,device from macaddrs 
+        where (  date(now())=date(adddate(limitDate, interval -1 day)) 
+              OR date(now())=date(adddate(limitDate, interval -7 day))  ) 
+             AND status='A'] */
+    snprintf(queryStr, BUFFMAXLN, 
+            "select mailAddress,limitDate,device from macaddrs "
+            " where (%s) and status='A'", mailTiming);
+
+    /* send SQL query */
+    if (mysql_query(&mysql, queryStr)){
+      err_msg("ERR at %s#%d: mysql query[%s]: %s",__FILE__,__LINE__,queryStr,
+             mysql_error(&mysql));
+      return FALSE;
+    }
+    
+    /* store result */
+    res = mysql_store_result(&mysql);
+  }
+
+  /* output table name */
+  row = mysql_fetch_row(res);
+
+  /* if found, return values */
+  if(row!=NULL){
+    strncpy(mailAddress, row[0], BUFFMAXLN);
+    strncpy(limitDate, row[1], WORDMAXLN);
+    strncpy(device, row[2], WORDMAXLN);
+    return TRUE;
+  }
+  /* if not found, free memory area */
+  else{
+    mysql_free_result(res);
+    return FALSE;
+  }
+}
+
+/********************************************
+ routines for debugging output
+********************************************/
+
+int InitMngDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initMngDb()");
+  ret=initMngDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=initMngDb()",ret);
+  return ret;
+}
+void CloseMngDb(void){
+  if(debug>1) err_msg("DEBUG:=>closeMngDb()");
+  closeMngDb();
+  if(debug>1) err_msg("DEBUG:<=closeMngDb()");
+}
+
+int GetNextMacAddrFromMngDb(char* userId, char* extraId, char* macAddress, char* deviceName, char* entryDate, char* limitDate, char* status, char* mailAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getNextMacAddrFromMngDb(%s,%s)",userId,extraId);
+  ret=getNextMacAddrFromMngDb(userId,extraId,macAddress,deviceName,
+                             entryDate,limitDate, status,mailAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=getNextMacAddrFromMngDb(,,%s,%s,%s,%s,%s,%s)",
+                     ret,macAddress,deviceName,entryDate,limitDate,status,mailAddress);
+  return ret;
+}
+
+int RegistMacAddrToMngDb(char* macAddr, char* deviceName, char* userId, char* extraId, char* mailAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>registMacAddrToMngDb(%s,%s,%s,%s,%s)",
+                     macAddr,deviceName,userId,extraId,mailAddress);
+  ret=registMacAddrToMngDb(macAddr,deviceName,userId,extraId, mailAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=registMacAddrToMngDb( )",ret);
+  return ret;
+}
+
+int IsMacAddrFoundInMngDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isMacAddrFoundInMngDb(%s)", macAddr);
+  ret=isMacAddrFoundInMngDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=isMacAddrFoundInMngDb( )",ret);
+  return ret;
+}
+
+int CountMacAddrsForUserInMngDb(char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>countMacAddrsForUserInMngDb(%s,%s)",
+                     userId,extraId);
+  ret=countMacAddrsForUserInMngDb(userId,extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=countMacAddrsForUserInMngDb( )",ret);
+  return ret;
+}
+
+int PutMacModifyLogToMngDb(char* userId, char* extraId, char* macAddr, char modifyType){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putMacModifyLogToMngDb(%s,%s,%s,%c)",
+                     userId,extraId,macAddr,modifyType);
+  ret=putMacModifyLogToMngDb(userId,extraId,macAddr,modifyType);
+  if(debug>1) err_msg("DEBUG:(%d)<=putMacModifyLogToMngDb( )",ret);
+  return ret;
+}
+
+int GetNicVendorFromMngDb(char* macAddress, char* vendor, int bufferLength){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getNicVendorFromMngDb(%s,,%d)",
+                     macAddress, bufferLength);
+  ret=getNicVendorFromMngDb(macAddress, vendor, bufferLength);
+  if(debug>1) err_msg("DEBUG:(%d)<=getNicVendorFromMngDb(%s)",ret, vendor);
+  return ret;
+}
+
+
+int CountMacModifyPerDayInMngDb(char* userId, char* extraId){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>countMacModifyPerDayInMngDb(%s,%s)",
+                     userId,extraId);
+  ret=countMacModifyPerDayInMngDb(userId,extraId);
+  if(debug>1) err_msg("DEBUG:(%d)<=countMacModifyPerDayInMngDb( )",ret);
+  return ret;
+}
+
+int DelMacAddrFromMngDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>delMacAddrFromMngDb(%s)",macAddr);
+  ret=delMacAddrFromMngDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=delMacAddrFromMngDb( )",ret);
+  return ret;
+}
+
+int RenewMacAddrInMngDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>renewMacAddrInMngDb(%s)",macAddr);
+  ret=renewMacAddrInMngDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=renewMacAddrinMngDb( )",ret);
+  return ret;
+}
+
+int PauseMacAddrInMngDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>pauseMacAddrInMngDb(%s)",macAddr);
+  ret=pauseMacAddrInMngDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=pauseMacAddrinMngDb( )",ret);
+  return ret;
+}
+
+int IsSessionFoundInMngDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isSessionFoundInMngDb(%s)",macAddr);
+  ret=isSessionFoundInMngDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=isSessionFoundInMngDb( )",ret);
+  return ret;
+}
+
+int GetNextUsageLogFromMngDb(char* userId, char* extraId, char* macAddr, char* deviceName, char* openTime, char* gatewayName, int* weekday){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getNextUsageLogFromMngDb(%s,%s)",userId,extraId);
+  ret=getNextUsageLogFromMngDb(userId,extraId,macAddr,deviceName,
+                             openTime,gatewayName,weekday);
+  if(debug>1) err_msg("DEBUG:(%d)<=getNextUsageLogFromMngDb(,,%s,%s,%s,%s,%d)",
+                     ret,macAddr,deviceName,openTime,gatewayName,*weekday);
+  return ret;
+}
+
+int GetNextMailAddressFromMngDb(char* mailAddress, char* limitDate, char*device){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getnextMailAddressFromMngDb( )");
+  ret=getNextMailAddressFromMngDb(mailAddress, limitDate, device);
+  if(debug>1) err_msg("DEBUG:(%d)<=getNextMailAddressFromMngDb(%s,%s,%s)",
+                     ret,mailAddress,limitDate,device);
+  return ret;
+}
diff --git a/mngsrc/messages.c b/mngsrc/messages.c
new file mode 100644 (file)
index 0000000..83a2906
--- /dev/null
@@ -0,0 +1,171 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for Communication through CGI 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+
+Programmed by Yoshiaki WATANABE
+**************************************************/
+
+#include       "opengatemmng.h"
+
+int messageSet[ENDOFLIST]={0};
+
+/*******************************
+ set message
+*******************************/
+void setMessage(int msgNo){
+
+  if(msgNo < ENDOFLIST) messageSet[msgNo]=TRUE;
+}
+
+/*******************************
+ reset message
+*******************************/
+void resetMessage(void){
+  int i;
+  for(i=0;i<ENDOFLIST;i++) messageSet[i]=FALSE;
+}
+
+/*******************************
+ insert message in multi-lang to page
+*******************************/
+void insertMessageToPage(char* language){
+  
+  char* (*pMessageFunc)(int msgNo);
+  int i;
+
+  /* get message in language indicated in argument */
+  if(strcmp(language, "ja")==0)      pMessageFunc=messagesInJa;
+  else if(strcmp(language, "en")==0) pMessageFunc=messagesInEn;
+
+  /* if not indicated in argument, use conf value */
+  else if(strcmp(GetConfValue("HtmlLangs"),"ja")==0) pMessageFunc=messagesInJa;
+  else if(strcmp(GetConfValue("HtmlLangs"),"en")==0) pMessageFunc=messagesInEn;
+
+  /* if no conf value, use english message */
+  else                               pMessageFunc=messagesInEn;
+
+  /* print messages that flag on */
+  for(i=0; i<ENDOFLIST; i++){
+    if(messageSet[i]) printf("%s<br>\n",(*pMessageFunc)(i));
+  }
+}
+
+/******************************
+ error message in english
+******************************/
+char* messagesInEn(int msgNo){
+  char* messages[ENDOFLIST];
+  messages[ExistentMacAddr]="Error: Mac address is already registered. Update it in update page.";
+  messages[DeviceCountOver]="Error: Device count reachs to the limit per one user. To register new device, remove a registered device.";
+  messages[IllegalMacAddrForm]= "Error: Mac address format is illegal.";
+  messages[IllegalCharInDevice]="Error: Not permitted character is found in device name.";
+  messages[IllegalCharInMailAddr]="Error: Not permitted character is found in mail address.";
+  messages[EmptyDeviceName]="Error: Registration device name is empty.";
+  messages[SuspectNat]="Error: Mac Address cannot detect. Accessed via NAT or router.";
+  messages[NoInfoInDb]="Error: Cannot get user information.";
+  messages[IllegalUserId]="Error: Illegal userId.";
+  messages[IllegalMacAddr]="Error: Illegal MAC address.";
+  messages[NoService]="Error: Cannot serve now.";
+  messages[NoDaemon]="Error: Resident program mulfunctions. Contact to the administrator.";
+  messages[ModifyCountOver]="Error: Modification count overflows. Retry after one day.";  
+  messages[RegisterSuccess]="Registration is performed. Network is enabled.";
+  messages[UpdateSuccess]="Update is performed.";
+  messages[IllegalCookie]="Error: Cannot get correct cookie.";
+  messages[NotSetAdminCookie]="Error: Cannot found admin cookie. Enter from check page.";
+  messages[RequestAdminAuth]="Enter Administrator's userID and password.";
+  messages[UnallowableAgent]="Cannot recognize the terminal to be allowable.";
+
+  return messages[msgNo];
+}
+
+/******************************
+ error message in japanese (utf-8)
+******************************/
+char* messagesInJa(int msgNo){
+  char* messages[ENDOFLIST];
+  messages[ExistentMacAddr]= "エラー:既登録のMACアドレスです。更新ページで更新してください。";
+  messages[DeviceCountOver]= "エラー:一人当りの許容機器数に達しています。新たな機器を登録するには登録済の一つを削除してください。";
+  messages[IllegalMacAddrForm]=  "エラー:MACアドレスの形式が不正です。";
+  messages[IllegalCharInDevice]="エラー:許容されていない文字が機器名にあります。";
+  messages[IllegalCharInMailAddr]="エラー:許容されていない文字がメールアドレスにあります。";
+  messages[EmptyDeviceName]= "エラー:機器名が入力されていません。";
+  messages[SuspectNat]=  "エラー:NAT/Router経由なのでMACアドレスが取れません。";
+  messages[NoInfoInDb]="エラー:ユーザ情報を得られません。";
+  messages[IllegalUserId]="エラー:不正なユーザIDです。";
+  messages[IllegalMacAddr]="エラー:不正なMACアドレスです。";
+  messages[NoService]="エラー:サービスを提供できません。";
+  messages[NoDaemon]="エラー: 常駐プログラムが不調です。管理者に連絡下さい。";
+  messages[ModifyCountOver]="エラー: 変更回数が制限を越えました。1日経ってから実行下さい。";
+  messages[RegisterSuccess]="登録を完了しました。ネットワークを利用できます。";
+  messages[UpdateSuccess]="更新を完了しました。";
+  messages[IllegalCookie]="エラー: 正しいCookieを取得できません。";
+  messages[NotSetAdminCookie]="エラー : 管理者のCookieを取得できません。チェックページから入って下さい。";
+  messages[RequestAdminAuth]="管理者のIDとPasswordを入力してください。";
+  messages[UnallowableAgent]="登録許容端末と認識できません。";
+  return messages[msgNo];
+}
+
+/***********************************
+make weekday string for language
+***********************************/
+char* weekdayStr(int weekday, char* str, char* language){
+
+  char* weekdayStrEn[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
+  char* weekdayStrJa[7]={"月","火","水","木","金","土","日"};
+
+  if(strcmp(language, "ja")==0)      str=weekdayStrJa[weekday];
+  else if(strcmp(language, "en")==0) str=weekdayStrEn[weekday];
+  else if(strcmp(GetConfValue("HtmlLangs"),"ja")==0) str=weekdayStrJa[weekday];
+  else if(strcmp(GetConfValue("HtmlLangs"),"en")==0) str=weekdayStrEn[weekday];
+  else                               str=weekdayStrEn[weekday];
+  return str;
+}
+
+/**********************************
+ *********************************/
+void SetMessage(int msgNo){
+  if(debug>1) err_msg("DEBUG:=>setMessage(%d)", msgNo);
+  setMessage(msgNo);
+  if(debug>1) err_msg("DEBUG:<=setMessage( )");
+}
+
+void ResetMessage(void){
+  if(debug>1) err_msg("DEBUG:=>resetMessage()");
+  resetMessage();
+  if(debug>1) err_msg("DEBUG:<=resetMessage( )");
+}
+
+void InsertMessageToPage(char* language){
+  if(debug>1) err_msg("DEBUG:=>insertMessageToPage(%s)",language);
+  insertMessageToPage(language);
+  if(debug>1) err_msg("DEBUG:<=insertMessageToPage( )");
+}
+
+char* WeekdayStr(int weekday, char* str, char* language){
+  char* ret;
+  if(debug>1) err_msg("DEBUG:=>weekdayStr(%d,,%s)",weekday,language);
+  ret=weekdayStr(weekday,str,language);
+  if(debug>1) err_msg("DEBUG:<=weekdayStr(%s)",str);
+  return ret;
+}
+
+
diff --git a/mngsrc/opengatemchk.c b/mngsrc/opengatemchk.c
new file mode 100644 (file)
index 0000000..e48d336
--- /dev/null
@@ -0,0 +1,116 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for mac address checking cgi main
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/***************************************************/
+/*  main routine called as cgi from Web server     */
+/***************************************************/
+int  main(int argc, char **argv)
+{
+  char language[WORDMAXLN]="";  /* browser prefered language(e.g.:ja,en) */
+  char requestStr[BUFFMAXLN]=""; /* http request string */
+  int status=NONE;   /* request offlag for open/close: OPEN/CLOSE/NONE */
+  char macAddress[ADDRMAXLN]="";  /* client MAC address */
+  char userId[USERMAXLN]="";      /* user id */
+  char extraId[USERMAXLN]="";     /* extra id used as user@extra */
+  char* progName="";              /* the name of this program in argv[0] */
+  char mailDefault[BUFFMAXLN]=""; /* default mail address to get warning */
+
+  /* drop root privilege to prevent dangerous actions */
+  seteuid(getuid());
+  
+  /* if this is executed in shell with '-v' option, show makedir */
+  /* this is prepared to show information about version */
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is cgi program\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* save program load path */
+  saveLoadPath(argv[0]);
+  progName = getProgramName();
+
+  /* prepare configuration file */
+  if(OpenConfFile()==-1){
+    PutMessageToClient("Check config file by running this cgi on console");
+    return 0;
+  }
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize config */
+  InitConf();
+  if(!InitWorkDb()) return 0;
+  if(!InitMngDb()) return 0;
+
+  /* get request language indicated in query string */
+  GetLangFromQueryString(language);
+
+  /* get post data */
+  GetPostData(requestStr, BUFFMAXLN);
+  
+  /* get userid. if not get, exit */
+  if(!GetUserId(requestStr, userId, extraId, language, ADMINUSER, 
+               GetConfValue("CheckCgi"), mailDefault, "")){
+    CloseMngDb();
+    return 0;
+  }
+
+  /* analyze request from client */
+  if(!isNull(requestStr)){
+    AnalyzeCheckRequest(requestStr, &status, macAddress);
+  }
+
+  /* send response to client and control watch process */
+  /* if status = OPEN/CLOSE, it is ajax request coded in html/macchk.js */
+  /* in this case, send back short message */
+  if(status==OPEN){
+    PutMessageToClient("open");
+    StartChildProc(macAddress);
+  }    
+  else if(status==CLOSE){
+    PutMessageToClient("close");
+    StopChildProc(macAddress);
+  }
+
+  /* if not OPEN/CLOSE, send back new page */
+  else{
+
+    /* make work table for checking client mac address */
+    CreateMacCheckTableInWorkDb();
+  
+    /* put page to client */
+    PutCheckPageToClient(language,userId,extraId);
+  }
+
+  return 0;
+}
diff --git a/mngsrc/opengatemfwd.c b/mngsrc/opengatemfwd.c
new file mode 100644 (file)
index 0000000..23d63cf
--- /dev/null
@@ -0,0 +1,185 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ opengatem forwarding CGI main
+
+ Program responding to the first forwarding HTTP access.
+ DocumentRoot/index.html.var must be set to start this program
+ at forwarding HTTP access from IPFW.
+
+---sample index.himl.var---
+URI: /cgi-bin/opengate/opengatemfwd.cgi?en
+Content-language: en
+Content-type: text/html
+
+URI: /cgi-bin/opengate/opengatemfwd.cgi?ja
+Content-language: ja
+Content-type: text/html
+
+URI: /cgi-bin/opengate/opengatemfwd.cgi?en
+Content-type: text/html
+---------------------------
+
+Copyright (C) 2012 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemmng.h"
+
+int  main(int argc, char **argv)
+{
+  char htmlFile[BUFFMAXLN]="";   /* html file */
+  char lang[ADDRMAXLN]=""; /* client language */
+  char jumpCgiUrl[BUFFMAXLN];  /* url of forwarding destination */
+  char redirectedUrl[BUFFMAXLN]; /* url of redirected(requested) page */
+  char *protocol;
+  char *httpHost;
+  char *requestUri;
+  FILE *fp;
+  char buff[BUFFMAXLN];
+
+  /* drop root privilege */
+  seteuid(getuid());
+
+  /* if this is executed in shell with '-v' option, show makedir */  
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is cgi program\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* prepare config file */
+  if(OpenConfFile()==-1)return 0;
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(GetConfValue("FwdCgi"), LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize config */
+  InitConf();
+
+  if(debug>1) err_msg("DEBUG: started");
+
+  /* favicon.ico request is ignored */
+  if(!isNull(getenv("REQUEST_URI"))){
+    if(strcmp(getenv("REQUEST_URI"), "/favicon.ico")==0){
+      PutMessageToClient("");
+      return 0;
+    }
+  }
+
+
+  /* create jump cgi URL string */
+  snprintf(jumpCgiUrl, BUFFMAXLN, "%s%s%s/%s",
+          GetConfValue("OpengateServerName"),
+          GetConfValue("CgiDir"),
+          GetConfValue("OpengateDir"),
+          GetConfValue("JumpCgi"));
+
+  /* if null element is included, put error */
+  if(isNull(GetConfValue("OpengateServerName")) ||
+     isNull(GetConfValue("CgiDir")) ||
+     isNull(GetConfValue("OpengateDir")) ||
+     isNull(GetConfValue("JumpCgi")) ){
+    err_msg("ERR at %s#%d: jump url cannot setup properly from conf[%s]",__FILE__,__LINE__, jumpCgiUrl);
+      PutMessageToClient("error: refer conf file");
+      return 0;
+  }
+
+  /* get lang from httpd */
+  if(isNull(getenv("QUERY_STRING"))){
+    lang[0]='\0';
+  }else{
+    strncpy(lang, getenv("QUERY_STRING"), ADDRMAXLN);
+  }
+     
+  /* if not get, use default lang at the top of lang list */
+  if(isNull(lang)){
+    sscanf(GetConfValue("HtmlLangs"),"%s",lang);
+  }
+     
+  /* if the lang is not registered in lang list, set the default lang */
+  else if(strstr(GetConfValue("HtmlLangs"), lang)==NULL){
+    sscanf(GetConfValue("HtmlLangs"),"%s",lang);
+  }
+
+  /* construct redirected(requested) URL */
+  /* protocol */
+  if(!isNull(getenv("SERVER_PORT"))
+     && strcmp(getenv("SERVER_PORT"),GetServicePortStr("https"))==0) {
+    protocol="https";
+  }else{
+    protocol="http";
+  }
+
+  /* http-host */
+  if(!isNull(getenv("HTTP_HOST"))) httpHost=getenv("HTTP_HOST");
+  else httpHost="";
+
+  /* request-uri */
+  if(!isNull(getenv("REQUEST_URI"))) requestUri=getenv("REQUEST_URI");
+  else requestUri="";
+
+  /* concat above items to make redirect URL */
+  if(!isNull(httpHost)){
+    snprintf(redirectedUrl,BUFFMAXLN,"%s://%s%s", protocol,httpHost,requestUri);
+  }else redirectedUrl[0]='\0';
+
+  /* construct readin html file path */
+  snprintf(htmlFile, BUFFMAXLN, "%s%s/%s/%s", 
+         GetConfValue("DocumentRoot"), 
+         GetConfValue("OpengateDir"),
+         lang, 
+         GetConfValue("FwdDoc"));
+
+  /* if null element is included, put error */
+  if(isNull(GetConfValue("DocumentRoot")) ||
+     isNull(GetConfValue("OpengateDir")) ||
+     isNull(GetConfValue("FwdDoc")) ){
+    err_msg("ERR at %s#%d: fwd doc path cannot setup properly from conf[%s]",__FILE__,__LINE__, htmlFile);
+      PutMessageToClient("error: refer conf file");
+      return 0;
+  }
+
+  /* send out header */
+  printf("Content-Type: text/html\r\n\r\n\r\n");
+
+  /* relpace keywords and send out */
+  if((fp=fopen(htmlFile, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file [%s]",__FILE__,__LINE__, htmlFile);
+    return FALSE;
+  }
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%JUMPCGIURL%%", jumpCgiUrl);
+    HtmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
+    if(strstr(buff, "%%ERRORLIST%%")!=NULL){
+      InsertMessageToPage(lang);
+    }else{
+      printf("%s",buff);    
+    }
+  }
+  fclose(fp);
+
+  if(debug>1) err_msg("DEBUG: terminated");
+
+  return 0;
+}
diff --git a/mngsrc/opengatemmail.c b/mngsrc/opengatemmail.c
new file mode 100644 (file)
index 0000000..5ec1828
--- /dev/null
@@ -0,0 +1,149 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for sending mail to warn limit date 
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/***************************************************/
+/*  main routine called as cgi from Web server     */
+/***************************************************/
+int  main(int argc, char **argv)
+{
+  char mailAddress[BUFFMAXLN]; /* mail address */
+  char limitDate[WORDMAXLN]; /* limit date */
+  char device[WORDMAXLN]; /* device name */
+  int count=0;   /* count for sending mails */
+  char* progName; /* the name of this program in argv[0] */
+
+  /* drop root privilege */
+  seteuid(getuid());
+
+  /* if this is executed in shell with '-v' option, show makedir */  
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is the program used with cron\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* save program load path */
+  saveLoadPath(argv[0]);
+  progName = getProgramName();
+
+  /* prepare config file */
+  if(OpenConfFile()==-1){
+    PutMessageToClient("Check config file by running this cgi on console");
+    return 0;
+  }
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize config */
+  InitConf();
+  if(!InitMngDb()) return 0;
+
+  /* get mail address for users near expiration date and send mail */
+  while(GetNextMailAddressFromMngDb(mailAddress, limitDate, device)){
+    if(SendMail(mailAddress, limitDate, device)) count++;
+  }
+
+  /* finalize */
+  CloseMngDb();
+
+  /* report to syslog */
+  if(debug>0)  err_msg("INFO: Sended %d mails",count); 
+
+  return 0;
+}
+
+/**************************************************/
+/* send mail                                      */
+/**************************************************/
+int sendMail(char* mailAddress, char* limitDate, char* device)
+{
+  FILE* mailer;
+  FILE* fp;
+  char mailCmd[BUFFMAXLN];
+  char buff[BUFFMAXLN];
+  char* mailCmdPath;
+  struct stat st;
+
+  /* set mail command path (/bin/rmail) */
+  mailCmdPath=GetConfValue("Mail/CmdPath");
+  if(isNull(mailCmdPath)){
+    err_msg("ERR at %s#%d: cannot get Mail/CmdPath from conf",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* if mail command is not exists, return */
+  if(stat(mailCmdPath, &st)!=0){
+    err_msg("ERR at %s#%d: mail command[%s] is not found",__FILE__,__LINE__,mailCmdPath);
+    return FALSE;
+  }
+
+  /* prepare mail command [/bin/rmail user@domain] */
+  strncpy(mailCmd, mailCmdPath, BUFFMAXLN);
+  strncat(mailCmd, " ", BUFFMAXLN);
+  strncat(mailCmd, mailAddress, BUFFMAXLN);
+
+  /* prepare a pipe connected to the mail command */
+  mailer = popen(mailCmd, "w");
+  if(mailer==NULL){
+    err_msg("ERR at %s#%d: cannot open pipe",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* write the mail content to the pipe */
+  if((fp=fopen(GetConfValue("Mail/Content"), "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot find file %s",__FILE__,__LINE__, 
+           GetConfValue("Mail/Content"));
+    return FALSE;
+  }
+
+  while(fgets(buff,BUFFMAXLN,fp)!=NULL){
+    HtmlReplace(buff, "%%MAILADDRESS%%", mailAddress);
+    HtmlReplace(buff, "%%LIMITDATE%%", limitDate);
+    HtmlReplace(buff, "%%DEVICENAME%%", device);
+    fputs(buff, mailer);    
+  }
+  fclose(fp);
+  pclose(mailer);
+  return TRUE;
+}
+
+/***********************************************
+ routines for debugging output
+***********************************************/
+int SendMail(char* mailAddress, char* limitDate, char* device){
+    int ret;
+  if(debug>1) err_msg("DEBUG:=>sendMail(%s,%s,%s)", 
+                     mailAddress, limitDate, device);
+  ret=sendMail(mailAddress, limitDate, device);
+  if(debug>1) err_msg("DEBUG:(%d)<=sendMail( )",ret);
+  return ret;
+}
diff --git a/mngsrc/opengatemmng.h b/mngsrc/opengatemmng.h
new file mode 100644 (file)
index 0000000..42f629f
--- /dev/null
@@ -0,0 +1,289 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+header file
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <poll.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/signal.h>
+#include <regex.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <limits.h>
+#include <db.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <sys/utsname.h>
+#include <netdb.h>
+
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+
+typedef        void    Sigfunc(int);   /* for signal handlers */
+
+
+/***************** constants ***********************/
+
+/* Configuration file for opengate */ 
+#define CONFIGFILE "/etc/opengate/opengatemmng.conf"
+
+#define PAMSERVICENAME "opengate"    /* default service name used in PAM */
+#define RADIUSCONF  "/etc/radius.conf" /* default path to radius.conf */
+
+#define ADDRMAXLN 128      /* maximum address string length */
+#define USERMAXLN 128      /* maximum userid string length */
+#define BUFFMAXLN 1024      /* maximum buffer string length */
+#define WORDMAXLN 64       /* maximum word length */
+#define FILTERMAXLN 128   /* pcap filter max length */
+#define SIDMAXLN 64       /* maximum sessionID length */
+
+#define TRUE 1
+#define FALSE 0
+#define DENY   0
+#define ACCEPT 1
+#define OPEN 1
+#define CLOSE 0
+#define NONE -1
+#define NORMALUSER 0
+#define ADMINUSER 1
+#define ERROR -1
+#define NONAT 0
+#define NAT 1
+#define ROUTER 2
+#define OWNER 1
+#define ADMIN 0
+
+extern int debug;
+
+/* errors send to web client */
+enum errs{ExistentMacAddr,DeviceCountOver,IllegalMacAddrForm,
+         IllegalCharInDevice,EmptyDeviceName,IllegalCharInMailAddr,SuspectNat,
+         NoInfoInDb,IllegalUserId,IllegalMacAddr,NoService,
+         NoDaemon,ModifyCountOver,RegisterSuccess,UpdateSuccess,IllegalCookie,
+         NotSetAdminCookie,RequestAdminAuth,UnallowableAgent,
+         ENDOFLIST};
+
+/**********prototypes***************************************/
+
+/* opengatemreg.c */
+void CheckDaemonAndSendHupSignal(void);
+
+/* opengatemmail.c */
+int SendMail(char* mailAddress, char* limitDate, char* device);
+
+
+/* proc.c */
+int StartChildProc(char* macAddress);
+int StopChildProc(char* macAddress);
+void closeExit(int signo);
+void saveLoadPath(char* loadPath);
+char* getProgramName(void);
+
+/* util.c */
+void Writefmt(int fd, const char *fmt, ...);
+void WritefmtSSL(SSL *fd, const char *fmt, ...);
+ssize_t readln(int fd, void *vptr, size_t maxlen);
+ssize_t readlnSSL(SSL *fd, void *vptr, size_t maxlen);
+int Lock(int fd);
+int Unlock(int fd);
+FILE *Popenl(int rootPriv, const char *type, const char *path, ...);
+int Systeml(int roorPriv, const char *path, ...);
+int Pclose(FILE *stream);
+int isNull(const char *pStr);
+int Open(const char *pathname, int oflag, mode_t mode);
+int Close(int fd);
+pid_t Fork(void);
+int Pipe(int *fds);
+Sigfunc * Signal(int signo, Sigfunc *func);
+void * Malloc(size_t size);
+void CreateCookie(char *cookie);
+char* getenvEx(char* env, int pre, int post);
+int Tcp_connect(const char *host, const char *serv);
+
+/* error.c */
+void err_ret(const char *fmt, ...);
+void err_sys(const char *fmt, ...);
+void err_dump(const char *fmt, ...);
+void err_msg(const char *fmt, ...);
+void err_quit(const char *fmt, ...);
+void errToSyslog(int i);
+void terminateProg(int ret);
+
+/* getparam.c */
+int OpenConfFile(void);
+void CloseConfFile(void);
+void SetupConfExtra(char *userId, char *extraId);
+char *GetConfValue(char *name);
+char *GetConfValueExtra(char *name);
+char *GetConfAuthServer(char *name);
+int SelectNextAuthServer(void);
+void InitConf(void);
+int RegExMatch(const char *inStr, const char *regEx, int caseSensitive);
+void ResetAuthServerPointer(void);
+char *GetFirstConfValue(char* name);
+char *GetNextConfValue(void);
+
+/* managementdb.c */
+int InitMngDb(void);
+void CloseMngDb(void);
+int RegistMacAddrToMngDb(char* macAddr, char* deviceName, char* userId, char* extraId, char* mailAddress);
+int GetNextMacAddrFromMngDb(char* userId, char* extraId, char* macAddress, char* deviceName, char* entryDate, char* limitDate, char* status, char* mailAddress);
+int IsMacAddrFoundInMngDb(char* macAddr);
+int CountMacAddrsForUserInMngDb(char* userId, char* extraId);
+int PutMacModifyLogToMngDb(char* userId, char* extraId, char* macAddr, char modifyType);
+int GetNicVendorFromMngDb(char* macAddress, char* vendor, int bufferLength);
+int CountMacModifyPerDayInMngDb(char* userId, char* extraId);
+int DelMacAddrFromMngDb(char* macAddr);
+int RenewMacAddrInMngDb(char* macAddr);
+int PauseMacAddrInMngDb(char* macAddr);
+int IsSessionFoundInMngDb(char* macAddr);
+int GetNextUsageLogFromMngDb(char* userId, char* extraId, char* macAddr, char* deviceName, char* openTime, char* gatewayName, int* weekday);
+int GetNextMailAddressFromMngDb(char* mailAddress, char* limitDate, char*device);
+
+/* workdb.c */
+int SetupSqliteBusyTimeoutValue(void);
+int InitWorkDb(void);
+int CreateMacCheckTableInWorkDb(void);
+int AddIpv4ToMacCheckTable(void);
+int AddIpv6ToMacCheckTable(void);
+int GetNextRowInMacCheckTable(char* macAddress, char* ipv4, char* ipv6);
+int GetIpFromMacCheckTable(char* macAddress, char* ipv4, char* ipv6);
+int GetPidFromMacCheckTable(char* macAddress, int* pid, int* ruleIpv4, int* ruleIpv6);
+  int SavePidToMacCheckTable(char* macAddress, int pid, int ruleIpv4, int ruleIpv6);
+int GetDetectTimeFromMacinfoTable(char* macAddress);
+int IsSessionFoundInSessionTable(char* macAddress);
+int SaveCookieToWorkDb(char* cookie, char* userId, char* extraId, int userType);
+int IsCookieFoundInWorkDb(char* cookie, char* userId, char* extraId, int userType);
+int GetMailDefaultFromWorkDb(char* cookie, char* mailDefault);
+int IsNatSuspectedInWorkDb(char* macAddr);
+int SaveMacForCookieToWorkDb(char* cookie, char* macAddress);
+int SaveMailDefalutForCookieToWorkDb(char* cookie, char* mailDefault);
+int LoadMacForCookieFromWorkDb(char* cookie, char* macAddress);
+int IsActiveSessionFoundInOpengateSessionTable(char* macAddress);
+
+/* cgi.c */
+int GetPostData(char *content, int contentMaxLength);
+int GetLangFromQueryString(char* language);
+int GetRedirectedUrlFromQueryString(char* redirectedUrl);
+int GetMacAddrFromQueryString(char* macAddress);
+int AnalyzeCheckRequest(char *content, int* status, char* macAddress);
+int AnalyzeRegisterRequest(char *content, char* macAddress, char* deviceName, char* mailAddress);
+int PutDenyToClient(char *language);
+int PutCheckPageToClient(char *language, char* userId, char* extraId);
+int PutRegisterPageToClient(char *language, char* macAddress, char* deviceName, char* mailAddress, char* userId, char* extraId, int ownReg, char* redirectedUrl);
+void PutMacCheckListToClient(void);
+void PutMacRegListToClient(char* userId, char* extraId);
+void PutMessageToClient(char *message);
+void ReturnToRedirectedPage(char* redirectedUrl, char* language);
+int PutAuthRequestPageToClient(char *language, char* cgiName, char* docName, char* redirectedUrl);
+int ConvertMacAddr(char* macAddr);
+int IsSafeString(char* str, int length);
+int HtmlReplace(char* buff,char *beforeStr,char *afterStr);
+char* StrSplit(char* str,const char* delimStr);
+int GetUserIdFromEnv(char *userid);
+int GetUserIdFromPostData(char* requestStr, char* userid, char* password);
+int GetHttpCookie(char *cookie, char* cookieName);
+int IsCorrectCookie(char* cookie, int userType);
+int AnalyzeUpdateRequestAndExecute(char *content, char* userId, char* extraId);
+int PutUpdatePageToClient(char *language, char* userId, char* extraId, int ownUpdate, char* redirectedUrl);
+void PutMacListToClient(char *userId, char* extraId);
+void PutUsageLogToClient(char *userId, char* extraId, char* language);
+int IsAccessedFromAllowableAgent(void);
+
+/* messages.c */
+void SetMessage(int errNo);
+void ResetMessage(void);
+void InsertMessageToPage(char* language);
+char* messagesInJa(int errNo);
+char* messagesInEn(int errNo);
+char* WeekdayStr(int weekday, char* str, char* language);
+
+/* getmac.c */
+int GetMacAddrListFromArp(char* interface);
+int GetMacAddrListFromNdp(char* interface);
+int ReFormatMacAddr(char* macAddr);
+
+/* queue.c */
+int Initqueue(void);
+int Enqueue(char* keyStr, char* dataStr);
+int Dequeue(char* keyStr, char* dataStr);
+int Listqueue(void);
+void Freequeue(void);
+
+/* ipfw.c */
+int GetRuleNumber(char *clientAddr, int forced);
+int OpenClientGate(char *clientAddr, int forced, char* userId, char* extraId,char* macAddress);
+void CloseClientGate(int ruleNumber);
+int CountRuleNumber(int ruleNumber);
+
+/* auth.c */
+int GetUserId(char* requestStr, char* userId, char* extraId, char* language, int userType, char* cgiName, char* mailDefault, char* redirectedUrl);
+int AuthenticateUser(char *userid, char *password);
+void SplitId(char* userid, char* useridshort, char* extraId);
+char* ConcatUserId(char*  useridfull, char* userId, char* extraId);
+int IsUserIdFoundInAcceptUsersList(char* userId);
+int IsShibOrBasicAuthDuplicated(void);
+int MakeMailDefault(char* userId, char* extraId, char* mailDefault);
+
+/* alarms.c */
+int AddAlarm(char *name, int timeout, int preceding, Sigfunc *func);
+int RemoveAlarm(char *name);
+int EnableAlarm(void);
+int DisableAlarm(void);
+
+/* udpcli.c */
+int PutDataToUdpPort(char* udpServerAddr, char* udpServerPort, char* buff);
+int PutMacAddressToServers(char* macAddress);
+char *GetServicePortStr(char *servName);
diff --git a/mngsrc/opengatemown.c b/mngsrc/opengatemown.c
new file mode 100644 (file)
index 0000000..9317432
--- /dev/null
@@ -0,0 +1,218 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ cgi module for reg/update by owner oneself
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/***************************************************/
+/*  main routine called as cgi from Web server     */
+/***************************************************/
+int  main(int argc, char **argv)
+{
+  char language[WORDMAXLN]="";  /* browser prefered language(e.g.:ja,en) */
+  char userId[USERMAXLN]="";    /* user id */
+  char extraId[USERMAXLN]="";   /* extra id used as user@extra */
+  char requestStr[BUFFMAXLN]=""; /* http request string */
+  char* progName="";             /* the name of this program in argv[0] */
+  char mailDefault[BUFFMAXLN]=""; /* default mail address to get warning */
+  char macAddress[ADDRMAXLN]="";  /* client MAC address */
+  char macAddressReq[ADDRMAXLN]=""; /* MAC address in request text */
+  char ipAddress[ADDRMAXLN]="";     /* IP address */
+  char* dev;                        /* name of network interface */
+  char ipAddressInQueue[ADDRMAXLN]="";  /* IP address found in queue */
+  char macAddressInQueue[ADDRMAXLN]=""; /* MAC address found in queue */ 
+  char deviceName[WORDMAXLN]=""; /* client device name */
+  char mailAddress[BUFFMAXLN]="";  /* user's mail address to get warning */
+  int isNatOrRouter=0; /* flag for nat or router insertion (checked in md) */
+  char redirectedUrl[BUFFMAXLN]=""; /* url from which the page is forwarded */
+  int modified=FALSE; /* register or update is done */
+
+  /* drop root privilege (to prevent dangerous action */
+  seteuid(getuid());
+
+  /* if this is executed in shell with '-v' option, show makedir */
+  /* this is prepared to show information about version */
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is cgi program\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* save program load path */
+  saveLoadPath(argv[0]);
+  progName = getProgramName();
+
+  /* prepare configuration file */
+  if(OpenConfFile()==-1){
+    PutMessageToClient("Check config file by running this cgi on console");
+    return 0;
+  }
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize configuration and database */
+  InitConf();
+  if(!InitMngDb()) return 0;
+  if(!InitWorkDb()) return 0;
+
+  /* get language and other from query string */
+  GetLangFromQueryString(language);
+  GetRedirectedUrlFromQueryString(redirectedUrl);
+
+  /* check client's http-agent, if the agent is not allowed in conf, exit */
+  if(!IsAccessedFromAllowableAgent()){
+    SetMessage(UnallowableAgent);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+
+  /*** Get request from client ***/
+  /* get post data */
+  GetPostData(requestStr, BUFFMAXLN);
+
+  /* get cgi name defined in conf file */
+  if(isNull(GetConfValue("OwnCgi"))){
+    err_msg("ERR at %s#%d: OwnCgi cannot get from conf file",__FILE__,__LINE__);
+    return 0;
+  }
+
+  /* get userid and other info. */
+  /* if not get, send auth page and exit */
+  if(!GetUserId(requestStr, userId, extraId, language, NORMALUSER,
+               GetConfValue("OwnCgi"),mailDefault,redirectedUrl)){
+    CloseMngDb();
+    return 0;
+  }
+
+  /* if too many requests per one day, send error and exit */
+  if(CountMacModifyPerDayInMngDb(userId,extraId) 
+     > atoi(GetConfValue("MaxMacModifyPerDay"))){
+    SetMessage(ModifyCountOver);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+
+  /*** Get client MAC address ***/
+  /* get the client ip address from environment variable */
+  strncpy(ipAddress, getenv("REMOTE_ADDR"), ADDRMAXLN);
+
+  /* get nic interface name in conf */
+  if(isNull(dev=GetConfValue("Device"))){
+        err_msg("ERR at %s#%d: Device cannot get from conf file",__FILE__,__LINE__);
+       return 0;
+  }
+
+  /* get IP-MAC pair list from arp or ndp on the nic */
+  Initqueue();
+  if(strchr(ipAddress,':')==NULL) GetMacAddrListFromArp(dev);
+  else GetMacAddrListFromNdp(dev);
+
+  /* search mac address corresponding to the client ip address */
+  while(Dequeue(macAddressInQueue, ipAddressInQueue)){
+    if(strcmp(ipAddress, ipAddressInQueue)==0){
+      strncpy(macAddress, macAddressInQueue, ADDRMAXLN);
+      break;
+    }
+  }
+
+  /* clear the ip-mac pair list */
+  Freequeue();
+
+  /*** Check the acquired MAC ***/
+  /* if accessed via nat or router, exit  */
+  /* if nat, check function returns 1. if router, it returns 2. */
+  isNatOrRouter=IsNatSuspectedInWorkDb(macAddress);
+  if(isNatOrRouter==NAT || isNatOrRouter==ROUTER){
+    SetMessage(SuspectNat);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+
+  /*** execute the client request ***/
+  /* if null request, skip execution and go to sending page */
+  if(!isNull(requestStr)){
+    
+    /* execute update requests */
+    if(AnalyzeUpdateRequestAndExecute(requestStr, userId, extraId)){
+      SetMessage(UpdateSuccess);
+      modified=TRUE;
+    }
+
+    /* if no update, check registration request */
+    else if(AnalyzeRegisterRequest(requestStr, macAddressReq, 
+                             deviceName, mailAddress)){
+      
+      /* if registration info is found, register values to db */
+      RegistMacAddrToMngDb(macAddress,deviceName,userId,extraId,mailAddress);
+      PutMacModifyLogToMngDb(userId, extraId, macAddress, 'R');
+      PutMacAddressToServers(macAddress);
+      SetMessage(RegisterSuccess);
+      modified=TRUE;
+    }
+  }
+
+  /*** Send back web page ***/
+  /* if registration/Updating is done, return to redirected site */
+  if(modified && !isNull(redirectedUrl)){
+    ReturnToRedirectedPage(redirectedUrl, language);
+  }
+
+  /* else if the client is registered, send back update page */
+  else if(IsMacAddrFoundInMngDb(macAddress)){
+    PutUpdatePageToClient(language, userId, extraId, OWNER, redirectedUrl);
+  }
+
+  /* client is not-registered */
+  /* but allowable registration device count is over the limit */
+  /* send back update page with overflow error message */
+  else if(CountMacAddrsForUserInMngDb(userId,extraId) 
+         >= atoi(GetConfValue("MaxDevices"))){
+    SetMessage(DeviceCountOver);
+    PutUpdatePageToClient(language, userId, extraId, OWNER, redirectedUrl);
+  }
+
+  /* client is not-registered and device count is under the limit */
+  else{
+
+    /* restore mail address */
+    if(isNull(mailAddress)) strncpy(mailAddress, mailDefault, BUFFMAXLN);
+
+    /* send registration page to the client */
+    PutRegisterPageToClient(language, macAddress, deviceName, mailAddress, 
+                           userId, extraId, OWNER, redirectedUrl);
+  }
+
+  /* finalize */
+  CloseMngDb();
+  return 0;
+}
+
diff --git a/mngsrc/opengatemreg.c b/mngsrc/opengatemreg.c
new file mode 100644 (file)
index 0000000..dbbb587
--- /dev/null
@@ -0,0 +1,209 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for mac address registration cgi main
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/***************************************************/
+/*  main routine called as cgi from Web server     */
+/***************************************************/
+int  main(int argc, char **argv)
+{
+  char language[WORDMAXLN]="";   /* browser prefered language(e.g.:ja,en) */
+  char requestStr[BUFFMAXLN]=""; /* http request string */
+  char macAddress[ADDRMAXLN]="";  /* client MAC address */
+  char mailAddress[BUFFMAXLN]="";  /* user's mail address to get warning */
+  char mailDefault[BUFFMAXLN]="";  /* default address to get warning */
+  char deviceName[BUFFMAXLN]="";   /* client device name */
+  char userId[USERMAXLN]="";     /* user id */
+  char extraId[USERMAXLN]="";    /* extra id used as user@extra */
+  char* progName="";             /* the name of this program in argv[0] */
+  char adminCookie[SIDMAXLN]="";  /* cookie for admin user */
+  int isNatOrRouter=0; /* flag for nat or router insertion (checked in md) */
+
+  /* drop root privilege */
+  seteuid(getuid());
+
+  /* if this is executed in shell with '-v' option, show makedir */  
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is cgi program\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* save program load path */
+  saveLoadPath(argv[0]);
+  progName = getProgramName();
+
+  /* prepare config file */
+  if(OpenConfFile()==-1){
+    PutMessageToClient("Check config file by running this cgi on console");
+    return 0;
+  }
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize configuration */
+  InitConf();
+  if(!InitMngDb()) return 0;
+
+  /* this page requires both of ADMIN and NORMAL user authentications. */
+  /* any protocol can be set for the two authentications. */
+  /* but in shibboleth or httpbasic, same one cannot be used for both auth. */
+  /* (as twice authentication processing cannot be performed) */
+  if(IsShibOrBasicAuthDuplicated()){
+    PutMessageToClient("Error: Duplicated Shibboleth or HttpBasic setting");
+    return 0;
+  }
+
+  /* get items in query string (sent from opengatemchk) */
+  GetLangFromQueryString(language);
+  GetMacAddrFromQueryString(macAddress);
+
+  /* if accessed via nat or router, return  */
+  /* if nat, check function returns 1. if router, it returns 2. */
+  isNatOrRouter=IsNatSuspectedInWorkDb(macAddress);
+  if(isNatOrRouter==NAT || isNatOrRouter==ROUTER){
+    SetMessage(SuspectNat);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+
+  /* if not get admin cookie, return */
+  /* as the admin cookie is set in check page, */
+  /* this certify the jumping from check page. */
+  if(!IsCorrectCookie(adminCookie, ADMINUSER)){
+    SetMessage(NotSetAdminCookie);
+    PutDenyToClient(language);
+    return 0;
+  }
+
+  /* if get cookie, save mac for cookie */
+  if(!isNull(macAddress)) SaveMacForCookieToWorkDb(adminCookie,macAddress);
+
+  /* get post data */
+  GetPostData(requestStr, BUFFMAXLN);
+
+  /* get userid. if not get, exit */
+  if(!GetUserId(requestStr, userId, extraId, language, NORMALUSER,
+               GetConfValue("RegisterCgi"), mailDefault, "")){
+    CloseMngDb();
+    return 0;
+  }
+
+  /* if the registration device count is overflowed the limit, send error */
+  if(CountMacAddrsForUserInMngDb(userId,extraId) 
+     >= atoi(GetConfValue("MaxDevices"))){
+    SetMessage(DeviceCountOver);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+  
+  /* if any request from client, analyze the request */
+  if(!isNull(requestStr)){
+    if(AnalyzeRegisterRequest(requestStr, macAddress, deviceName, mailAddress)){
+      /* register the new mac info to db */
+      RegistMacAddrToMngDb(macAddress,deviceName,userId,extraId,mailAddress);
+      PutMacModifyLogToMngDb(userId, extraId, macAddress, 'R');
+      SetMessage(RegisterSuccess);
+
+      /* refresh daemon cache */
+      /* send udp message including the mac address to the service daemon */
+      PutMacAddressToServers(macAddress);
+    }
+  }    
+
+  /* prepare response and send to client */
+  /* restore mac address sent from opengatemchk */
+  if(isNull(mailAddress)) strcpy(mailAddress, mailDefault);
+  if(isNull(macAddress)) LoadMacForCookieFromWorkDb(adminCookie,macAddress);
+  
+  /* send register page to the client */
+  PutRegisterPageToClient(language, macAddress, deviceName, mailAddress, userId, extraId,ADMIN,"");
+
+  /* finalize */
+  CloseMngDb();
+
+  return 0;
+}
+
+/********************************
+ check running of opengatemd daemon
+ and send hup signal to the daemon
+ *******************************/
+void checkDaemonAndSendHupSignal(void){
+  FILE* file;
+  struct stat st;
+  char* lockFileMd;
+  int pid;
+
+  /* get lock file name */  
+  lockFileMd=GetConfValue("DaemonLockFile");
+
+  /* if lock file is not exists, set error */
+  if(stat(lockFileMd, &st)!=0){
+    SetMessage(NoDaemon);
+    return;
+  }
+
+  /* read pid from the file */
+  if((file=fopen(lockFileMd, "r"))==NULL){
+    err_msg("ERR at %s#%d: cannot open daemon lock file:%s",__FILE__,__LINE__,
+           lockFileMd);
+    return;
+  }
+
+  if(fscanf(file, "%d", &pid)==0){
+    err_msg("ERR at %s#%d: cannot read daemon lock file:%s",__FILE__,__LINE__,
+           lockFileMd);
+    return;
+  }
+  fclose(file);
+
+  /* check the daemon process running */
+  if(kill(pid, 0)!=0 && errno==ESRCH) SetMessage(NoDaemon);
+
+  /* send kill signal to the pid process if send is enabled */
+  if(atoi(GetConfValue("EnableSendingHup"))){
+    seteuid(0);
+    kill(pid, SIGHUP);
+    seteuid(getuid());
+  }   
+}
+
+
+/*************************************
+ ************************************/
+void CheckDaemonAndSendHupSignal(void){
+  if(debug>1) err_msg("DEBUG:=>checkDaemonAndSendHupSignal( )");
+  checkDaemonAndSendHupSignal();
+  if(debug>1) err_msg("DEBUG:<=checkDaemonAndSendHupSignal( )");
+}
diff --git a/mngsrc/opengatemup.c b/mngsrc/opengatemup.c
new file mode 100644 (file)
index 0000000..c29f76e
--- /dev/null
@@ -0,0 +1,110 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for cgi main
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+/***************************************************/
+/*  main routine called as cgi from Web server     */
+/***************************************************/
+int  main(int argc, char **argv)
+{
+  char language[WORDMAXLN]="";  /* browser prefered language(e.g.:ja,en) */
+  char userId[USERMAXLN]="";    /* user id */
+  char extraId[USERMAXLN]="";   /* extra id used as user@extra */
+  char requestStr[BUFFMAXLN]=""; /* http request string */
+  char* progName="";             /* the name of this program in argv[0] */
+  char mailDefault[BUFFMAXLN]=""; /* default mail address to get warning */
+
+  /* drop root privilege */
+  seteuid(getuid());
+
+  /* if this is executed in shell with '-v' option, show makedir */
+  /* this is prepared to show information about version */
+  if(argc>1){
+    if(strcmp(argv[1],"-v")==0){
+      printf("makedir: %s\n", MAKEDIR);
+    }else{
+      printf("This is cgi program\n");
+      printf("To show version, run this on console with '-v' option\n");
+    }
+    exit(0);
+  }
+
+  /* save program load path */
+  saveLoadPath(argv[0]);
+  progName = getProgramName();
+
+  /* prepare configuration file */
+  if(OpenConfFile()==-1){
+    PutMessageToClient("Check config file by running this cgi on console");
+    return 0;
+  }
+  /* start log */
+  errToSyslog(atoi(GetConfValue("Syslog/Enable")));
+  openlog(progName, LOG_PID, atoi(GetConfValue("Syslog/Facility")));
+
+  /* initialize config */
+  InitConf();
+  if(!InitMngDb()) return 0;
+  if(!InitWorkDb()) return 0;
+
+  /* get language from query string */
+  GetLangFromQueryString(language);
+
+  /* get post data */
+  GetPostData(requestStr, BUFFMAXLN);
+
+  /* get userid. if not get, exit */
+  if(!GetUserId(requestStr, userId, extraId, language, NORMALUSER,
+               GetConfValue("UpdateCgi"),mailDefault, "")){
+    CloseMngDb();
+    return 0;
+  }
+
+  /* if many modify requests per one day, ignore the request */
+  if(CountMacModifyPerDayInMngDb(userId,extraId) 
+     > atoi(GetConfValue("MaxMacModifyPerDay"))){
+    SetMessage(ModifyCountOver);
+    PutDenyToClient(language);
+    CloseMngDb();
+    return 0;
+  }
+
+  /* check null request from client */
+  if(!isNull(requestStr)){
+    
+    /* analize string and execute requests */
+    if(AnalyzeUpdateRequestAndExecute(requestStr, userId, extraId)){
+      SetMessage(UpdateSuccess);
+    }
+  }
+
+  /* prepare response and send to client */
+  PutUpdatePageToClient(language, userId, extraId, ADMIN, "");
+
+  /* finalize */
+  CloseMngDb();
+  return 0;
+}
diff --git a/mngsrc/proc.c b/mngsrc/proc.c
new file mode 100644 (file)
index 0000000..e84a0bb
--- /dev/null
@@ -0,0 +1,148 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for mac address checking child process control
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include       "opengatemmng.h"
+
+int rule4=0;
+int rule6=0;
+char loadPath[BUFFMAXLN];
+
+/**********************************************
+start child process to  open-net, sleep and close-net
+**********************************************/
+int startChildProc(char* macAddress){
+
+  int dummyfd[2];
+  char ipv4[ADDRMAXLN];
+  char ipv6[ADDRMAXLN];
+  int pid;
+
+  /* fork child process */
+  if((pid=fork())==-1){
+    err_msg("ERR at %s#%d: fork error",__FILE__,__LINE__);
+    return -1;
+  }
+
+  /* parent process */
+  else if(pid!=0){
+    return pid;
+  }
+
+  /* child process */
+  else{
+
+    /* detach from server */
+    Close(0);Close(1);Close(2);
+    Pipe(dummyfd);      /* connect dummy pipe for stdin and out */
+
+    /* get ipv4/ipv6 from db */
+    GetIpFromMacCheckTable(macAddress, ipv4, ipv6);
+
+    /* open firewall */
+    if(!isNull(ipv4)) rule4=OpenClientGate(ipv4,FALSE,"temp","","");
+    if(!isNull(ipv6)) rule6=OpenClientGate(ipv6,FALSE,"temp","","");
+    
+    /* save pid/ruleNumber to db */
+    SavePidToMacCheckTable(macAddress, getpid(), rule4, rule6);
+
+    signal(SIGTERM, closeExit);
+
+    /* sleep a while */
+    sleep(atoi(GetConfValue("OpenTimeout")));
+
+    /* close firewall */
+    if(rule4!=0) CloseClientGate(rule4);
+    if(rule6!=0) CloseClientGate(rule6);    
+
+    return 0;
+  }
+}
+
+/***************************
+ signal function
+***************************/
+void closeExit(int signo){
+
+    /* close firewall */
+    if(rule4!=0) CloseClientGate(rule4);
+    if(rule6!=0) CloseClientGate(rule6);    
+    exit(0);
+}
+
+/*********************************
+ stop child process 
+ ********************************/
+int stopChildProc(char* macAddress){
+  
+  int pid;
+
+  /* get pid/ruleNumber from db */
+  GetPidFromMacCheckTable(macAddress, &pid, &rule4, &rule6);
+
+  /* close firewall */
+  if(rule4!=0) CloseClientGate(rule4);
+  if(rule6!=0) CloseClientGate(rule6);    
+
+  /* kill child process */
+  kill(pid, SIGKILL);
+
+  return TRUE;
+}
+
+/**************************
+save the program load path
+**************************/
+void saveLoadPath(char* argv0){
+  strncpy(loadPath, argv0, BUFFMAXLN);
+}
+
+/******************************************
+get the program name extracted from argv[0]
+******************************************/
+char* getProgramName(void){
+  char* pCh;
+  pCh = strrchr(loadPath, '/');
+  if(isNull(pCh)) return loadPath;
+  else return pCh+1;
+}
+
+/*********************************************
+ routines for debugging output
+**********************************************/
+int StartChildProc(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>startChildProc(%s)",macAddress);
+  ret=startChildProc(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=startChildProc( )",ret);
+  return ret;
+}
+
+int StopChildProc(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>stopChildProc(%s)",macAddress);
+  ret=stopChildProc(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=stopChildProc( )",ret);
+  return ret;
+}
+
diff --git a/mngsrc/queue.c b/mngsrc/queue.c
new file mode 100644 (file)
index 0000000..eb5feab
--- /dev/null
@@ -0,0 +1,223 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module to control queue 
+
+  As ip address check by database is time consuming procedure,
+  the recently checked addresses are cached and skiped.
+  Implemented with HashTable and Queue.
+  HashTable has recentry checked dataStress and checked time.
+  If ip is included in table and time is new, ignore checking.
+  Queue has dataStresses odrered by checked time.
+  If an old item is found in table, elder items are removed from table.
+  The queue controls the remove sequence.
+
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemmng.h"
+
+/* Queue to store string-key stirng-data pair */
+struct queueNode{
+  char keyStr[WORDMAXLN];
+  char dataStr[WORDMAXLN];
+  struct queueNode *next;
+};
+static struct queueNode* queueTail=NULL;
+static struct queueNode* queueHead=NULL;
+
+
+/*********************************************
+initialize Address Queue
+Queue
+ HeadNode - DataNode - DataNode - TailNode
+ (dummy)                           (dummy)
+  ^queueHead                        ^queueTail
+*********************************************/
+int initqueue(void){
+
+  char keyStr[WORDMAXLN];
+  char dataStr[WORDMAXLN];
+
+  /* if not exist, prepare head and tail */
+  if(queueHead==NULL){
+    queueHead=(struct queueNode*)malloc(sizeof(struct queueNode));
+    if(queueHead==NULL){
+      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+    queueTail=(struct queueNode*)malloc(sizeof(struct queueNode));
+    if(queueTail==NULL){
+      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+      terminateProg(0);
+    }
+    queueHead->keyStr[0]='\0';
+    queueHead->dataStr[0]='\0';
+    queueTail->keyStr[0]='\0';
+    queueTail->dataStr[0]='\0';
+    queueHead->next=queueTail;
+    queueTail->next=NULL;
+  }
+  
+  /* if exist, reset all */
+  else{
+    while(Dequeue(keyStr, dataStr))
+      ;
+  }
+  return TRUE;
+}
+
+/****************************************
+Add data to the tail of Queue
+ input=addr
+****************************************/
+int enqueue(char* keyStr, char* dataStr){
+  struct queueNode *newNode;
+
+  /* if not prepared, error */
+  if(queueHead==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;
+  }
+
+  /* add item after the tail and set it as new tail*/
+  newNode=(struct queueNode*)malloc(sizeof(struct queueNode));
+  if(newNode==NULL){
+    err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
+    terminateProg(0);
+  }
+  strncpy(queueTail->keyStr, keyStr, WORDMAXLN);
+  strncpy(queueTail->dataStr, dataStr, WORDMAXLN);
+  queueTail->next=newNode;
+  queueTail=newNode;
+  queueTail->keyStr[0]='\0';
+  queueTail->dataStr[0]='\0';
+  queueTail->next=NULL;
+  return TRUE;
+}
+
+/****************************************
+Get and remove address data from the head of Queue
+ output=addr
+****************************************/
+int dequeue(char* keyStr, char* dataStr){
+
+  /* set null string as default */
+  keyStr[0]='\0';
+  dataStr[0]='\0';
+
+  /* if not prepared, error */
+  if(queueHead==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;
+  }
+  else if(queueHead->next==NULL){
+    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
+    return FALSE;  
+  }
+
+  /* if no data, return false */
+  else if(queueHead->next==queueTail){
+    return FALSE;
+  }
+
+  /* get item from the head */
+  else {
+    struct queueNode *temp;
+    temp=queueHead->next;
+    queueHead->next=temp->next;
+    strncpy(keyStr, temp->keyStr, sizeof(temp->keyStr));
+    strncpy(dataStr, temp->dataStr, sizeof(temp->dataStr));
+    free(temp);
+  }
+  return TRUE;
+}
+
+/****************************************
+Listing IpAddress Queue (for debugging)
+****************************************/
+int listqueue(void){
+
+  struct queueNode *temp;
+
+  if(queueHead==NULL) return FALSE;
+  temp=queueHead->next;
+  while(temp->next!=NULL){
+    printf("[%s][%s]\n", temp->keyStr, temp->dataStr);
+    temp=temp->next;
+  }
+  return TRUE;
+}
+
+
+/****************************************
+memory free for Address Queue
+****************************************/
+void freequeue(void){
+  char keyStr[WORDMAXLN];
+  char dataStr[WORDMAXLN];
+  while(Dequeue(keyStr, dataStr));
+  free(queueHead);
+  free(queueTail);
+  queueHead=queueTail=NULL;
+}
+
+/****************************************************
+ routines for debugging putput
+ ***************************************************/
+int Initqueue(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initqueue( )");
+  ret = initqueue();
+  if(debug>1) err_msg("DEBUG:(%d)<=initqueue( )",ret);
+  return ret;
+
+}
+int Enqueue(char* keyStr, char* dataStr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>enqueue(%s,%s)", keyStr, dataStr);
+  ret = enqueue(keyStr, dataStr);
+  if(debug>1) err_msg("DEBUG:(%d)<=enqueue( )",ret);
+  return ret;
+
+}
+int Dequeue(char* keyStr, char* dataStr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>dequeue( )");
+  ret = dequeue(keyStr, dataStr);
+  if(debug>1) err_msg("DEBUG:(%d)<=dequque(%s,%s)",ret, keyStr, dataStr);
+  return ret;
+
+}
+int Listqueue(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>listQueue( )");
+  ret = listqueue();
+  if(debug>1) err_msg("DEBUG:(%d)<=listQueue( )",ret);
+  return ret;
+}
+
+void Freequeue(void){
+  if(debug>1) err_msg("DEBUG:=>freeQueue()");
+  freequeue();
+  if(debug>1) err_msg("DEBUG:<=freequeue()");
+}
+
+
diff --git a/mngsrc/udpcli.c b/mngsrc/udpcli.c
new file mode 100644 (file)
index 0000000..187fea6
--- /dev/null
@@ -0,0 +1,138 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module to control udp client 
+
+  As ip address check by database is time consuming procedure,
+  the recently checked addresses are cached and skiped.
+  Implemented with HashTable and Queue.
+  HashTable has recentry checked dataStress and checked time.
+  If ip is included in table and time is new, ignore checking.
+  Queue has dataStresses odrered by checked time.
+  If an old item is found in table, elder items are removed from table.
+  The queue controls the remove sequence.
+
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemmng.h"
+
+/************************************
+send mac address to daemon at db update 
+************************************/
+int putMacAddressToServers(char* macAddress){
+  char udpServerAddr[ADDRMAXLN];
+  char udpServerPort[WORDMAXLN];
+  char* udpServer;
+
+  udpServer=GetFirstConfValue("UdpServer");
+  if(isNull(udpServer)){
+    err_msg("ERR at %s#%d: no udp server in conf",__FILE__,__LINE__);
+    return FALSE;
+  }
+  while(!isNull(udpServer)){
+    if(sscanf(udpServer, "%s %s", udpServerAddr, udpServerPort)!=2){
+      err_msg("ERR at %s#%d: abnormal udp servers in conf",__FILE__,__LINE__);
+      continue;
+    }
+    PutDataToUdpPort(udpServerAddr, udpServerPort, macAddress);
+    udpServer=GetNextConfValue();
+  }
+  return TRUE;
+}
+
+/*****************************************
+put data to server udp port
+*****************************************/
+int putDataToUdpPort(char* udpServerAddr, char* udpServerPort, char* buff){
+
+  int sockfd;
+  struct addrinfo hints, *servinfo, *p;
+  int ret;
+  int numbytes;
+  
+  /* if no buffer return error */
+  if (buff==NULL||*buff=='\0') return FALSE;
+
+  /* prepare address hints */ 
+  memset(&hints, 0, sizeof hints);
+  hints.ai_family = AF_UNSPEC; /* IPv4/IPv6 dual */
+  hints.ai_socktype = SOCK_DGRAM; /* UDP */
+
+  if ((ret = getaddrinfo(udpServerAddr, udpServerPort, &hints, &servinfo))!= 0) {
+    err_msg("ERR at %s#%d: getaddrinfo: %s",__FILE__,__LINE__, 
+           gai_strerror(ret));
+    return FALSE;
+  }
+  
+  /* loop through addresses */
+  for(p = servinfo; p != NULL; p = p->ai_next) {
+    if ((sockfd = socket(p->ai_family, p->ai_socktype,
+                        p->ai_protocol)) == -1) {
+      err_msg("ERR at %s#%d: socket error: %s",__FILE__,__LINE__,
+             strerror(errno));
+      continue;
+    }
+    break;
+  }
+  if (p == NULL) {
+    err_msg("ERR at %s#%d: failed to bind socket",__FILE__,__LINE__);
+    return FALSE;
+  }
+  
+  /* send data to server */
+  if ((numbytes = sendto(sockfd, buff, strlen(buff), 0,
+                        p->ai_addr, p->ai_addrlen)) == -1) {
+    err_msg("ERR at %s#%d: sendto error: %s",__FILE__,__LINE__,
+           strerror(errno));
+    err_msg("ERR at %s#%d: Check firewall/daemon on [%s] to get udp[%d] packet"
+           "from here", 
+           __FILE__,__LINE__,udpServerAddr,udpServerPort);
+    return FALSE;
+  }
+  
+  /* finalize */
+  freeaddrinfo(servinfo);
+  close(sockfd);
+  
+  return TRUE;
+}
+
+/**********************************
+put out buff to udp addr:port
+**********************************/
+int PutDataToUdpPort(char* udpServerAddr, char* udpServerPort,char* buff){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putDataToUdpPort(%s)",udpServerAddr, udpServerPort,buff);
+  ret = putDataToUdpPort(udpServerAddr, udpServerPort,buff);
+  if(debug>1) err_msg("DEBUG:(%d)<=putDateToUdpPort( )",ret);
+  return ret;
+}
+
+
+int PutMacAddressToServers(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>putMacAddressToServers(%s)",macAddress);
+  ret = putMacAddressToServers(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=putMacAddressToServers( )",ret);
+  return ret;
+}
+
+
diff --git a/mngsrc/util.c b/mngsrc/util.c
new file mode 100644 (file)
index 0000000..8cc6b29
--- /dev/null
@@ -0,0 +1,593 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+ module for misc routines
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+
+#include "opengatemmng.h"
+
+
+/*************************************************/
+/* formated write                                */
+/* fd : file descriptor                          */
+/* fmt : format to write                         */
+/* ... : terms to write                          */
+/*************************************************/
+void Writefmt(int fd, const char *fmt, ...)
+{
+  char buff[BUFFMAXLN];
+  va_list     ap;
+  int nchar, nwrt;
+
+  va_start(ap, fmt);
+  vsnprintf(buff, BUFFMAXLN, fmt, ap); 
+  va_end(ap);
+
+  nchar=strlen(buff);
+  nwrt=write(fd, buff, nchar);
+
+  return;
+}
+
+
+void WritefmtSSL(SSL *fd, const char *fmt, ...)
+{
+  char buff[BUFFMAXLN];
+  va_list     ap;
+  int nchar, nwrt;
+
+  va_start(ap, fmt);
+  vsnprintf(buff, BUFFMAXLN, fmt, ap); 
+  va_end(ap);
+
+  nchar=strlen(buff);
+  nwrt=SSL_write(fd, buff, nchar);
+
+  return;
+}
+
+
+/******************************************************/
+/* Read one line                                      */
+/*   fd: file descriptor                              */
+/*   vptr: input buffer pointer                       */
+/*   maxlen: buffer length                            */
+/*                                                    */
+/* the chars terminated with EOL or EOF is read in    */
+/* ## this function assumes two EOL chars [CR LF]     */ 
+/*  CRLF is not read in and skipped                   */
+/* [abcdCRLFefghCRLF] => read[abcd],left[efghCRLF]    */
+/*                                                    */
+/* return value                                       */
+/*    plus value means the count of chars to read     */
+/*    value 0 means NULL line (no-chars & CRLF)       */
+/*    value -1 means error (errno is set)             */
+/*    value -2 means EOF (no-chars & EOF)             */ 
+/******************************************************/
+ssize_t
+readln(int fd, void *vptr, size_t maxlen)
+{
+  ssize_t      n, rc;
+  char *ptr,c;
+
+  ptr=vptr;
+
+  /* pre read */
+  rc = read(fd, &c, 1);
+  if(rc==0) return(-2); /* EOF */
+  if(rc<0) return(-1);  /* ERR */
+
+  /* get char loop */
+  n=0;
+  while(n < maxlen-1) {
+    if ( rc == 1) {      /* get some char */
+      if (iscntrl(c)){         /* get control char (means EOL) */
+       rc = read(fd, &c, 1);  /* skip second EOL char */
+       break;
+      }
+      *ptr++ = c;
+      n++;
+    }else if (rc == 0) { /* EOF (but some chars are read already) */
+      break;
+    } else {             /* ERR */
+      return(-1);
+    }
+    rc = read(fd, &c, 1);
+  }
+  /* null terminate string */  
+  *ptr++ = 0;
+  return(n);
+}
+
+
+ssize_t
+readlnSSL(SSL *fd, void *vptr, size_t maxlen)
+{
+  ssize_t      n, rc;
+  char *ptr,c;
+
+  ptr=vptr;
+
+  /* pre read */
+  rc = SSL_read(fd, &c, 1);
+  if(rc==0) return(-2); /* EOF */
+  if(rc<0) return(-1);  /* ERR */
+
+  /* get char loop */
+  n=0;
+  while(n < maxlen-1) {
+    if ( rc == 1) {      /* get some char */
+      if (iscntrl(c)){      /* get control char (means EOL) */
+         rc = SSL_read(fd, &c, 1); /* skip second EOL char */
+         break;
+      }
+      *ptr++ = c;
+      n++;
+    }else if (rc == 0) { /* EOF (but some char are read already */
+      break;
+    } else {             /* ERR */
+      return(-1);
+    }
+    rc = SSL_read(fd, &c, 1);
+  }
+  /* null terminate string */  
+  *ptr++ = 0;
+  return(n);
+}
+
+/******************************/
+/* lock functions using fcntl */
+/******************************/
+int lock(int fd){
+  struct flock lck;
+  
+  lck.l_type=F_WRLCK;
+  lck.l_whence=SEEK_SET;
+  lck.l_start=0;
+  lck.l_len=0;
+  return fcntl(fd, F_SETLKW, &lck);
+}
+  
+/********************************/
+/* unlock functions using fcntl */
+/********************************/
+int unlock(int fd)
+{
+  struct flock lck;
+
+  lck.l_type=F_UNLCK;
+  lck.l_whence=SEEK_SET;
+  lck.l_start=0;
+  lck.l_len=0;
+  return fcntl(fd, F_SETLK, &lck);
+}
+
+/**************************************/
+/* check NULL or point to null string */
+/**************************************/
+int isNull(const char *pStr)
+{
+  if(pStr==NULL) return TRUE;
+  if(*pStr=='\0') return TRUE;
+  return FALSE;
+}
+
+
+
+/**************************************************/
+/* popen with argument list                       */
+/* rootPriv: if 1, run command as root user       */
+/* type : open type "r" or "w"                    */
+/* path : command path to fork/exec               */
+/* ... : command arguments. last must be (char*)0 */
+/*  DO NOT SET [user entered string] in args      */
+/*  to prevent hacking                            */
+/**************************************************/
+FILE *Popenl(int rootPriv, const char *type, const char *path, ...)
+{
+  char commandLine[BUFFMAXLN];
+  va_list     ap;
+  char *pStr;
+  FILE *file;
+
+  /* insert command path */
+  strncpy(commandLine, path, BUFFMAXLN);
+
+  /* insert command arguments */
+  va_start(ap, path);
+  
+  while((pStr=va_arg(ap, char *))!=(char *)0){
+    strcat(commandLine, " ");
+    strncat(commandLine, pStr, BUFFMAXLN);
+  }
+  free(pStr);
+  va_end(ap);
+
+  /* if desired, add root privilege */
+  if(rootPriv==1){
+    if(seteuid(0)!=0){
+      err_msg("ERR at %s#%d: cannot add root privilege ",
+             __FILE__,__LINE__);
+    } 
+  }
+
+  /* open the pipe to the program  */
+  if(debug>1) err_msg("DEBUG:=>popen(%s, %s)", commandLine, type);
+  file=popen(commandLine, type);
+  if(debug>1) err_msg("DEBUG:(%x)<=popen( )",file);  
+
+  /* remove root privilege */
+  seteuid(getuid()); 
+
+  return file;
+}
+
+
+/**************************************************/
+/* system with argument list                      */
+/* rootPriv: if 1, run command as root user       */
+/* path : command path to fork/exec               */
+/* ... : command arguments. last must be (char*)0 */
+/*  DO NOT SET [user entered string] in args      */
+/*  to prevent hacking                            */
+/**************************************************/
+int Systeml(int rootPriv, const char *path, ...)
+{
+  char commandLine[BUFFMAXLN];
+  va_list     ap;
+  char *pStr;
+  int ret;
+
+  /* insert command path */
+  strncpy(commandLine, path, BUFFMAXLN);
+
+  /* insert command arguments */
+  va_start(ap, path);
+  
+  while((pStr=va_arg(ap, char *))!=(char *)0){
+    strcat(commandLine, " ");
+    strncat(commandLine, pStr, BUFFMAXLN);
+  }
+  free(pStr);
+  va_end(ap);
+
+  /* if desired, add root privilege */
+  if(rootPriv==1){
+    if(seteuid(0)!=0){
+      err_msg("ERR at %s#%d: cannot add root privilege ",
+             __FILE__,__LINE__);
+    } 
+  }
+
+  /* execute shell  */
+  if(debug>1) err_msg("DEBUG:=>system(%s)", commandLine);
+  ret=system(commandLine);
+  if(debug>1) err_msg("DEBUG:<=system()");
+
+  /* remove root privilege */
+  seteuid(getuid()); 
+  return ret;
+}
+
+/*************************************************/
+/* calc MD5 in hex form                          */
+/*  str: plain text to convert                   */
+/*  hexdigest: converted hex string              */
+/*      prepare buff more or equal to 33chars    */
+/*  len: length of hexdigest buffer              */
+/*************************************************/
+char *md5hex(char *hexdigest, int len, char *str)
+{
+  char unsigned digest[16];
+  char hexcode[16]="0123456789abcdef";
+  int i;
+  
+  /* if not enough buffer, exit */
+  if(len<33){
+    *hexdigest='\0';
+    return hexdigest;
+  }
+
+  /* calc MD5 digest */
+  MD5((unsigned char*)str, strlen(str), digest);
+
+  /* convert to HEX string */
+  for(i=0;i<16;i++){
+    hexdigest[2*i]=hexcode[digest[i]/16];
+    hexdigest[2*i+1]=hexcode[digest[i]%16];
+  }
+  hexdigest[2*16]='\0';
+
+  return hexdigest;
+}
+
+/*******************************************/
+/* create random session cookie            */
+/*******************************************/
+void createCookie(char *cookie)
+{
+  char str[BUFFMAXLN];
+
+  /* make Http-cookie from pid&time */
+  snprintf(str, BUFFMAXLN, "%d%d", getpid(),time(NULL));
+  md5hex(cookie, SIDMAXLN, str);
+}
+
+/*******************************************/
+/* get port number string in /etc/services */
+/*******************************************/
+char *getServicePortStr(char *servName)
+{
+  struct servent *pServEnt;
+  static char portStr[WORDMAXLN];
+
+  /* get service info from service name */
+  pServEnt = getservbyname(servName, NULL);
+
+  if(pServEnt==NULL){
+    err_msg("ERR at %s#%d: cannot find /etc/services entry for %s",
+           __FILE__,__LINE__,servName);
+    return "";
+  }
+
+  /* convert service port number to string form */
+  snprintf(portStr, sizeof(portStr),"%d",ntohs(pServEnt->s_port));
+
+  return portStr;
+}
+
+/****************************************************/
+/* getenv for multiple variables                    */
+/*             after replacing '-' with '_'         */
+/*                                                  */
+/* if env = "ab cd-ef-gh ijk"                       */
+/*  repeat getenv until getting non-null value      */
+/*  getnev("ab"),getenv("cd_ef_gh"),getenv("ijk")   */
+/* if pre=TRUE convert '-' to '_' in env-var name   */
+/* if post=TRUE convert ' '|'@' to '_' in get-str   */
+/****************************************************/
+char* getenvEx(char* env, int pre, int post){
+  char work[BUFFMAXLN];
+  char* envValue="";
+  char* p=NULL;
+  char* thisVar=NULL;
+  char* nextVar=NULL;
+  int found=FALSE;
+
+  /* copy string not to destroy it */
+  strncpy(work, env, BUFFMAXLN);
+
+  /* repeat for variables */
+  thisVar=nextVar=work;
+
+  while(!isNull(thisVar)){
+
+    /* skip preceeding space in string */
+    for(p=thisVar; *p==' '; p++);
+    thisVar=p;
+
+    /* search space (end of this variable) */
+    for(p=thisVar; (*p!=' ' && *p!='\0'); p++);
+
+    /* prepare next variable */
+    if(*p=='\0') nextVar=p; /* end of env string */
+    else{                   /* some variales follows */
+      *p='\0';                /* set end of this variable */
+      nextVar=p+1;            /* and start of next variable */
+    }
+
+    /* replace '-' in string with '_' */
+    if(pre){
+      for(p=thisVar; *p!='\0'; p++){
+       if(*p=='-') *p='_';
+      }
+    }
+
+    /* exeute getenv. if success, exit loop */
+    envValue = getenv(thisVar);
+    if(!isNull(envValue)){
+      found=TRUE;
+      break;
+    }
+
+    /* try next variable */
+    thisVar=nextVar;
+  }
+
+  /* getting no data */
+  if(!found) return NULL;
+
+  /* convert ' ' and '@' to '_' */
+  if(post){
+    for(p=envValue; *p!='\0'; p++){
+      if(*p==' ') *p='_';
+      if(*p=='@') *p='_';
+    }
+  }
+
+  return envValue;
+}
+
+/*********************************************************/
+/* TCP Connection routine                                 */
+/*  from UNIX NETWORK PROGRAMMING,Vol.1,Second Edition,   */
+/*      By W. Richard Stevens, Published By Prentice Hall */
+/*       ftp://ftp.kohala.com/pub/rstevens/unpv12e.tar.gz */
+/**********************************************************/
+int
+tcp_connect(const char *host, const char *serv)
+{
+       int                             sockfd, n;
+       struct addrinfo hints, *res, *ressave;
+
+       bzero(&hints, sizeof(struct addrinfo));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0){
+               err_msg("tcp_connect error for %s, %s: %s",
+                                host, serv, gai_strerror(n));
+               return -1;
+       }
+       ressave = res;
+
+       do {
+               sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+               if (sockfd < 0)
+                       continue;       /* ignore this one */
+
+               if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
+                       break;          /* success */
+
+               Close(sockfd);  /* ignore this one */
+       } while ( (res = res->ai_next) != NULL);
+
+       if (res == NULL){       /* errno set from final connect() */
+               err_msg("tcp_connect error for %s, %s", host, serv);
+               return -1;
+       }
+
+       freeaddrinfo(ressave);
+
+       return(sockfd);
+}
+/* end tcp_connect */
+
+/*
+ * We place the wrapper function here, not in wraplib.c, because some
+ * XTI programs need to include wraplib.c, and it also defines
+ * a Tcp_connect() function.
+ */
+
+
+/****************************************/
+/****************************************/
+void CreateCookie(char *cookie){
+  if(debug>1) err_msg("DEBUG:=>createCookie( )");
+  createCookie(cookie);
+  if(debug>1) err_msg("DEBUG:<=createCookie(%s)", cookie);  
+}
+
+char *GetServicePortStr(char *servName)
+{
+  char *ret;
+  if(debug>1) err_msg("DEBUG:=>getServicePortStr(%s)", servName);
+  ret = getServicePortStr(servName);
+  if(debug>1) err_msg("DEBUG:(%s)<=getServicePortStr( )", ret);  
+  return ret;
+}
+
+int Pclose(FILE *stream)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>pclose( )");
+  ret = pclose(stream);
+  if(debug>1) err_msg("DEBUG:<=pclose( )");  
+
+  return ret;
+}
+
+
+int Lock(int fd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>lock( )");
+  ret=lock(fd);
+  if(debug>1) err_msg("DEBUG:(%d)<=lock( )",ret);
+
+  return ret;
+}
+
+
+int Unlock(int fd)
+{
+  int ret;
+
+  if(debug>1) err_msg("DEBUG:=>unlock( )");
+  ret=unlock(fd);
+  if(debug>1) err_msg("DEBUG:(%d)<=unlock( )",ret);
+
+  return ret;
+}
+
+
+int
+Open(const char *pathname, int oflag, mode_t mode)
+{
+       int             fd;
+
+       if ( (fd = open(pathname, oflag, mode)) == -1)
+               err_msg("open error for %s", pathname);
+       return(fd);
+}
+
+int
+Close(int fd)
+{
+  int ret;
+
+  /*if( (ret=close(fd)) == -1)
+   *  err_msg("close error");
+   */
+
+  ret=close(fd);
+
+  return ret;
+}
+
+pid_t
+Fork(void)
+{
+       pid_t   pid;
+
+       if ( (pid = fork()) == -1)
+               err_msg("fork error");
+       return(pid);
+}
+
+int
+Pipe(int *fds)
+{
+  int ret;
+       if ((ret=pipe(fds)) < 0)
+               err_msg("pipe error");
+
+       return ret;
+}
+
+void *
+Malloc(size_t size)
+{
+       void    *ptr;
+
+       if ( (ptr = malloc(size)) == NULL)
+               err_msg("malloc error");
+       return(ptr);
+}
+
+int
+Tcp_connect(const char *host, const char *serv)
+{
+       return(tcp_connect(host, serv));
+}
+
diff --git a/mngsrc/workdb.c b/mngsrc/workdb.c
new file mode 100644 (file)
index 0000000..ac26c1a
--- /dev/null
@@ -0,0 +1,1118 @@
+/**************************************************
+OpengateM - MAC address authentication system 
+   module for local work database
+
+Copyright (C) 2011 Opengate Project Team
+Written by Yoshiaki Watanabe
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Email: watanaby@is.saga-u.ac.jp
+**************************************************/
+#include "opengatemmng.h"
+#include <sqlite3.h>
+
+static int sqliteBusyTimeout=100;  /* value used in sqite3_busy_timeout() */
+
+/*******************************************************************
+ read sqlite busy timeout value from conf and set to static variable
+*******************************************************************/
+int setupSqliteBusyTimeoutValue(void){
+
+  char *str;
+  
+  /* if set in conf, use the value. if not, use the above default. */
+  str=GetConfValue("SqliteBusyTimeout");
+  if(str!=NULL) sqliteBusyTimeout=atoi(str);
+
+  return sqliteBusyTimeout;
+}
+
+/********************************************
+initialize work db implemented with sqlite
+********************************************/
+int initWorkDb(void){
+  char *pErrMsg=NULL;
+  sqlite3 *db;
+
+  char *createCmd="CREATE TABLE IF NOT EXISTS maccheck "
+    "(macAddress TEXT PRIMARY KEY, "
+    "ipv4 TEXT DEFAULT '', ipv6 TEXT DEFAULT '', "
+    " pid INTEGER DEFAULT 0, ruleIpv4 INTEGER DEFAULT 0, "
+    " ruleIpv6 INTEGER DEFAULT 0, detectTime INTEGER DEFAULT 0)";
+
+  char *createCmd2="CREATE TABLE IF NOT EXISTS cookietable "
+    "(cookie TEXT PRIMARY KEY, "
+    " saveTime INTEGER DEFAULT 0,"
+    " userId TEXT DEFAULT '',"
+    " extraId TEXT DEFAULT '',"
+    " userType INTEGER DEFAULT 0,"
+    " mailDefault TEXT DEFAULT '',"
+    " macAddress TEXT DEFAULT '')";
+
+  char *createCmd3="CREATE TABLE IF NOT EXISTS sessionmd "
+    "(ipAddress TEXT PRIMARY KEY, "
+    "userId TEXT, extraId TEXT, openTime INTEGER, checkTime INTEGER, "
+    "macAddress TEXT, ruleNumber INTEGER)";
+
+  char *createCmd4="CREATE TABLE IF NOT EXISTS macinfo "
+    "(macAddress TEXT PRIMARY KEY ON CONFLICT REPLACE, "
+    "detectTime INTEGER, ttl INTEGER, isNat INTEGER)";
+
+  /* setup static variable value for SqLite3_busy_timeout from conf */
+  SetupSqliteBusyTimeoutValue();
+
+  /* Open sqlite for opengateMmng */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* create table */
+  if(sqlite3_exec(db, createCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  /* create table2 */
+  if(sqlite3_exec(db, createCmd2, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  /* close opengateMmng */
+  sqlite3_close(db);
+
+  /* Open sqlite for opengateMd */
+  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* create table3 */
+  if(sqlite3_exec(db, createCmd3, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  /* create table4 */
+  if(sqlite3_exec(db, createCmd4, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    terminateProg(0);
+  }
+
+  /* close opengateMd */
+  sqlite3_close(db);
+  return TRUE;
+}
+
+/************************************************
+ create work table for mac checking  
+*************************************************/
+int createMacCheckTableInWorkDb(void){
+
+  char *pErrMsg=NULL;
+  sqlite3 *db;
+
+  char *delCmd="DELETE FROM maccheck";
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* renew mac check table */
+   if(sqlite3_exec(db, delCmd, NULL, NULL, &pErrMsg)!=SQLITE_OK){
+     err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+     terminateProg(0);
+   }
+
+  /* get arp entry and add to mac check table */
+  Initqueue();
+  GetMacAddrListFromArp(GetConfValue("Device"));
+  AddIpv4ToMacCheckTable();
+  
+  /* get ndp entry and add to mac check table */
+  Initqueue();
+  GetMacAddrListFromNdp(GetConfValue("Device"));
+  AddIpv6ToMacCheckTable();
+  Freequeue();
+
+  sqlite3_close(db);
+  return TRUE;
+}
+
+/****************************************
+add mac ipv4 pair to mac check table
+ execute both of update and insert commands
+ because the mac address exists or not exist in table
+****************************************/
+int addIpv4ToMacCheckTable(void){
+
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+  char macAddr[ADDRMAXLN];
+  char ipAddr[ADDRMAXLN];
+  char* serverAddr="";
+  int detectTime=0;
+
+  /* SQL COMMAND, where %x is replaced in snprintf */
+  char *insertFormat="INSERT INTO maccheck "
+    " (ipv4, macAddress, detectTime) values ('%s','%s', %d)";
+
+  char *insertCmd;
+  int resultFlag=TRUE;
+
+  /* get server and remote client address */
+  serverAddr=getenv("SERVER_ADDR");
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* get queued items */
+  while(Dequeue(macAddr, ipAddr)){
+
+    /* if server addr, ignore */
+    if(strcmp(serverAddr,ipAddr)==0)continue;
+
+    /* get detect time from md.db */
+    detectTime=GetDetectTimeFromMacinfoTable(macAddr);
+
+     /* execute insert command */
+    insertCmd=sqlite3_mprintf(insertFormat, ipAddr, macAddr, detectTime);
+    if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+      resultFlag=FALSE;
+      err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+    }
+    sqlite3_free(insertCmd);
+  }
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/****************************************
+add mac ipv6 pair to mac check table
+ execute both of update and insert commands
+ because the mac address exists or not exist in table
+****************************************/
+int addIpv6ToMacCheckTable(void){
+
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+  char macAddr[ADDRMAXLN];
+  char ipAddr[ADDRMAXLN];
+  char* serverAddr="";
+  int detectTime=0;
+
+  /* get server and remote client address */
+  serverAddr=getenv("SERVER_ADDR");
+
+  /* SQL COMMAND, where %x is replaced in snprintf */
+  char *updateFormat="UPDATE maccheck "
+    " SET ipv6='%s',detectTime=%d where macAddress='%s'";
+  char *insertFormat="INSERT INTO maccheck "
+    " (ipv6, macAddress, detectTime) values ('%s','%s', %d)";
+
+  char *updateCmd;
+  char *insertCmd;
+  int resultFlag=TRUE;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* get queued items */
+  while(Dequeue(macAddr, ipAddr)){
+
+    /* if server addr, ignore */
+    if(strcmp(serverAddr,ipAddr)==0)continue;
+
+    /* get detect time from md.db */
+    detectTime=GetDetectTimeFromMacinfoTable(macAddr);
+
+    /* execute update command */
+    updateCmd=sqlite3_mprintf(updateFormat, ipAddr, detectTime, macAddr);
+    if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+
+      /* if failed, execute insert command */
+      insertCmd=sqlite3_mprintf(insertFormat, ipAddr, macAddr, detectTime);
+      if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+       resultFlag=FALSE;
+       err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+      }
+      sqlite3_free(insertCmd);
+    }
+    sqlite3_free(updateCmd);
+  }
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+
+/************************************************
+ get maccheck table row
+*************************************************/
+int getNextRowInMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
+
+  static sqlite3_stmt *stmt=NULL;
+  static sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  /* get info order by detecting time */
+  char *selectCmd="SELECT macAddress,ipv4,ipv6 "
+    " FROM maccheck order by detectTime desc ";
+  int resultFlag=TRUE;
+
+  /* set default */
+  *macAddress='\0';
+  *ipv4='\0';
+  *ipv6='\0';
+
+  /* execute at the first time */
+  if(stmt==NULL){
+
+    /* Open sqlite */
+    if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+      err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+      sqlite3_close(db);
+      terminateProg(0);
+    }
+    sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+    /* compile to internal statement */
+    if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+      resultFlag=FALSE;
+      err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+      
+      /* finalize */
+      sqlite3_finalize(stmt);
+      sqlite3_close(db);
+      terminateProg(0);
+    }
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(macAddress, (char*)sqlite3_column_text(stmt, 0), ADDRMAXLN);
+    strncpy(ipv4, (char*)sqlite3_column_text(stmt, 1), ADDRMAXLN);
+    strncpy(ipv6, (char*)sqlite3_column_text(stmt, 2), ADDRMAXLN);
+    resultFlag=TRUE;
+  }
+  
+  /* if not get record, end */
+  else{
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    resultFlag=FALSE;
+  }
+
+  return resultFlag;
+}
+
+/************************************************
+ get info from db input = macAddress, output = ipv4.ipv6
+*************************************************/
+int getIpFromMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
+
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT ipv4,ipv6 "
+    " FROM maccheck where macAddress='%s'";
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* set default */
+  *ipv4='\0';
+  *ipv6='\0';
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(ipv4, (char*)sqlite3_column_text(stmt, 0), ADDRMAXLN);
+    strncpy(ipv6, (char*)sqlite3_column_text(stmt, 1), ADDRMAXLN);
+    resultFlag=TRUE;
+  }
+  
+  /* if not get record, end */
+  else{
+    resultFlag=FALSE;
+  }
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/************************************************
+ get pid and rule number from db
+*************************************************/
+int getPidFromMacCheckTable(char* macAddress, int* pid, int* ruleIpv4, int* ruleIpv6){
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT pid,ruleIpv4,ruleIpv6 "
+    " FROM maccheck where macAddress='%s'";
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* set default */
+  *pid=0;
+  *ruleIpv4=0;
+  *ruleIpv6=0;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    *pid = (int)sqlite3_column_int(stmt, 0);
+    *ruleIpv4 = (int)sqlite3_column_int(stmt, 1);
+    *ruleIpv6 = (int)sqlite3_column_int(stmt, 2);
+    resultFlag=TRUE;
+  }
+  
+  /* if not get record, end */
+  else{
+    resultFlag=FALSE;
+  }
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/************************************************
+ save pid and rule number from db
+*************************************************/
+int savePidToMacCheckTable(char* macAddress, int pid, int ruleIpv4, int ruleIpv6){
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+
+  /* SQL COMMAND, where %x is replaced in snprintf */
+  char *updateFormat="UPDATE maccheck "
+    " SET pid=%d, ruleIpv4=%d, ruleIpv6=%d where macAddress='%s'";
+  char *updateCmd;
+  int resultFlag=TRUE;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute update command */
+  updateCmd=sqlite3_mprintf(updateFormat, pid,
+                           ruleIpv4, ruleIpv6, macAddress);
+  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+  sqlite3_free(updateCmd);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/************************************************
+ get info from 'Md.db' input = macAddress
+*************************************************/
+int getDetectTimeFromMacinfoTable(char* macAddress){
+
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+  int detectTime=0;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT detectTime "
+    " FROM macinfo where macAddress='%s'";
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return 0;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    detectTime = (int)sqlite3_column_int(stmt, 0);
+  }
+  
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return detectTime;
+}
+
+/*****************************
+ is the cookie found in db 
+ in: cookie, userType; out: userId,extraId
+******************************/
+int isCookieFoundInWorkDb(char* cookie, char* userId, char* extraId, int userType){
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT userId,extraId "
+    " FROM cookietable WHERE cookie='%s' and userType=%d" ;
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return FALSE;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, cookie, userType);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(userId, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
+    strncpy(extraId, (char*)sqlite3_column_text(stmt, 1), USERMAXLN);
+    resultFlag=TRUE;
+  }
+  else resultFlag=FALSE;
+
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/************************************************
+is session found in 'Md.db'  input=macAddress
+*************************************************/
+int isSessionFoundInSessionTable(char* macAddress){
+
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+  int  count=0;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT count(*) "
+    " FROM sessionmd where macAddress='%s' limit 1";
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return 0;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return 0;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    count = (int)sqlite3_column_int(stmt, 0);
+  }
+  
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return count;
+}
+
+
+/***********************************
+ save cookie sended to client
+***********************************/
+int saveCookieToWorkDb(char* cookie, char* userId, char* extraId, int userType){
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+
+  /* SQL COMMAND */
+  char* delFormat="DELETE FROM cookietable where saveTime < %d";
+  char* delCmd;
+  char* insertFormat="INSERT INTO cookietable "
+    " (cookie, saveTime, userId, extraId, userType) "
+    " values ('%s', %d, '%s', '%s', %d)";
+  char* insertCmd;
+  int resultFlag=TRUE;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute delete command */
+  delCmd=sqlite3_mprintf(delFormat, time(NULL)-(60*60*24));
+  if((rc=sqlite3_exec(db, delCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  /* execute insert command */
+  insertCmd=sqlite3_mprintf(insertFormat, cookie, time(NULL), userId, extraId, userType);
+  if((rc=sqlite3_exec(db, insertCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  sqlite3_free(delCmd);
+  sqlite3_free(insertCmd);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/***********************************
+ save mac address corresponding to cookie
+***********************************/
+int saveMacForCookieToWorkDb(char* cookie, char* macAddress){
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+
+  /* SQL COMMAND */
+  char* updateFormat="UPDATE cookietable "
+    " SET macAddress='%s' where cookie='%s'";
+  char* updateCmd;
+  int resultFlag=TRUE;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute update command */
+  updateCmd=sqlite3_mprintf(updateFormat, macAddress, cookie);
+  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  sqlite3_free(updateCmd);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/***********************************
+ save mail address default corresponding to cookie
+***********************************/
+int saveMailDefalutForCookieToWorkDb(char* cookie, char* mailDefault){
+  int rc;
+  sqlite3 *db;
+  char *pErrMsg=NULL;
+
+  /* SQL COMMAND */
+  char* updateFormat="UPDATE cookietable "
+    " SET mailDefault='%s' where cookie='%s'";
+  char* updateCmd;
+  int resultFlag=TRUE;
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    terminateProg(0);
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute update command */
+  updateCmd=sqlite3_mprintf(updateFormat, mailDefault, cookie);
+  if((rc=sqlite3_exec(db, updateCmd, NULL, NULL, &pErrMsg))!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_exec: %s",__FILE__,__LINE__,pErrMsg);
+  }
+
+  sqlite3_free(updateCmd);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/*****************************
+get maildefault corresponding to cookie
+******************************/
+int getMailDefaultFromWorkDb(char* cookie, char* mailDefault){
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT mailDefault "
+    " FROM cookietable WHERE cookie='%s'" ;
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return FALSE;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, cookie);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(mailDefault, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
+    resultFlag=TRUE;
+  }
+  else resultFlag=FALSE;
+
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+/*****************************
+ read mac address corresponding to cookie in work db
+******************************/
+int loadMacForCookieFromWorkDb(char* cookie, char* macAddress){
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT macAddress "
+    " FROM cookietable WHERE cookie='%s'" ;
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMmng"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return FALSE;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, cookie);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    strncpy(macAddress, (char*)sqlite3_column_text(stmt, 0), USERMAXLN);
+    resultFlag=TRUE;
+  }
+  else resultFlag=FALSE;
+
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return resultFlag;
+}
+
+
+
+/****************************************
+ is the mac address nat 
+(suspected from the info in opengatemd workdb) 
+ **if db access fails, return false**
+****************************************/
+int isNatSuspectedInWorkDb(char* macAddr){
+
+  sqlite3 *db;
+  sqlite3_stmt *stmt;
+  int isNat;
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char *selectFormat="SELECT isNat "
+ "FROM macinfo WHERE macAddress='%s'";
+  char *selectCmd;
+  int resultFlag;
+
+  /* open sqlite */
+  if(sqlite3_open(GetConfValue("SqliteDbMd"),&db)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_open",__FILE__,__LINE__);
+    sqlite3_close(db);
+    return FALSE;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* prepare command string */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddr);
+  
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return FALSE;
+  }
+
+  /* get first record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    isNat=(int)sqlite3_column_int(stmt, 0);
+    resultFlag=isNat;
+  }else{
+    resultFlag=FALSE;
+  }
+
+  /* finalize */
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  
+  return resultFlag;
+}
+
+
+
+/************************************************
+is active session found in 'opengate.db' (for openatesrv)  input=macAddress
+*************************************************/
+int isActiveSessionFoundInOpengateSessionTable(char* macAddress){
+
+  sqlite3_stmt *stmt=NULL;
+  sqlite3 *db;
+  int  count=0;
+
+  /* SQL SELECT COMMAND, where %x is replaced in snprintf */
+  char* selectFormat="SELECT count(*) "
+    " FROM session where (clientAddr4='%s' or clientAddr6='%s') "
+    " and closeTime='-' limit 1";
+  int resultFlag=TRUE;
+  char* selectCmd; 
+
+  /* Open sqlite (failed if no opengate usage) */
+  if(sqlite3_open(GetConfValue("SqliteDb"),&db)!=SQLITE_OK){
+    sqlite3_close(db);
+    return 0;
+  }
+  sqlite3_busy_timeout(db, sqliteBusyTimeout);
+
+  /* execute command */
+  selectCmd=sqlite3_mprintf(selectFormat, macAddress, macAddress);
+
+  /* compile to internal statement */
+  if(sqlite3_prepare(db, selectCmd, BUFFMAXLN, &stmt, NULL)!=SQLITE_OK){
+    resultFlag=FALSE;
+    err_msg("ERR at %s#%d: sqlite3_prepare",__FILE__,__LINE__);
+    
+    /* finalize */
+    sqlite3_free(selectCmd);
+    sqlite3_finalize(stmt);
+    sqlite3_close(db);
+    return 0;
+  }
+
+  /* get a record */
+  if(sqlite3_step(stmt)==SQLITE_ROW){
+    count = (int)sqlite3_column_int(stmt, 0);
+  }
+  
+  sqlite3_free(selectCmd);
+  sqlite3_finalize(stmt);
+  sqlite3_close(db);
+  return count;
+}
+
+
+/*********************************************************
+ routines for debugging output
+*********************************************************/
+int SetupSqliteBusyTimeoutValue(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>setupSqliteBusyTimeoutValue()");
+  ret=setupSqliteBusyTimeoutValue();
+  if(debug>1) err_msg("DEBUG:(%d)<=setupSqliteBusyTimeoutValue()",ret);
+  return ret;
+}
+
+int InitWorkDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>initWorkDb( )");
+  ret = initWorkDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=initWorkDb( )",ret);
+  return ret;
+}
+
+int CreateMacCheckTableInWorkDb(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>createmacChecktableinWorkDb( )");
+  ret = createMacCheckTableInWorkDb();
+  if(debug>1) err_msg("DEBUG:(%d)<=createMacCheckTableInWorkDb()", ret);
+  return ret;
+}
+
+int AddIpv4ToMacCheckTable(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=> addIpv4ToMacCheckTable( )");
+  ret = addIpv4ToMacCheckTable();
+  if(debug>1) err_msg("DEBUG:(%d)<= addIpv4ToMacCheckTable( )", ret);
+  return ret;
+}
+
+int AddIpv6ToMacCheckTable(void){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>addIpv6ToMacCheckTable( )");
+  ret = addIpv6ToMacCheckTable();
+  if(debug>1) err_msg("DEBUG:(%d)<=addIpv6ToMacCheckTable( )", ret);
+  return ret;
+}
+
+int GetNextRowInMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getNextRowInMacCheckTable( )");
+  ret = getNextRowInMacCheckTable(macAddress, ipv4, ipv6);
+  if(debug>1) err_msg("DEBUG:(%d)<=getNextRowInMacCheckTable(%s,%s,%s)",
+                     ret,macAddress,ipv4,ipv6);
+  return ret;
+}
+
+int GetIpFromMacCheckTable(char* macAddress, char* ipv4, char* ipv6){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getIpFromMacCheckTable(%s)",macAddress);
+  ret = getIpFromMacCheckTable(macAddress, ipv4, ipv6);
+  if(debug>1) err_msg("DEBUG:(%d)<=getIpFromMacCheckTable(,%s,%s)",
+                     ret,ipv4,ipv6);
+  return ret;
+}
+int GetPidFromMacCheckTable(char* macAddress, int* pid, int* ruleIpv4, int* ruleIpv6){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getPidFromMacCheckTable(%s)",macAddress);
+  ret = getPidFromMacCheckTable(macAddress, pid, ruleIpv4, ruleIpv6);
+  if(debug>1) err_msg("DEBUG:(%d)<=getPidFromMacCheckTable(,%d,%d,%d)",
+                     ret,*pid,*ruleIpv4,*ruleIpv6);
+  return ret;
+}
+int SavePidToMacCheckTable(char* macAddress, int pid, int ruleIpv4, int ruleIpv6){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>savePidToMacCheckTable(%s,%d,%d,%d)",
+                     macAddress, pid, ruleIpv4, ruleIpv6);
+  ret = savePidToMacCheckTable(macAddress, pid, ruleIpv4, ruleIpv6);
+  if(debug>1) err_msg("DEBUG:(%d)<=savePidToMacCheckTable( )",ret);
+  return ret;
+}
+
+int GetDetectTimeFromMacinfoTable(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>getDetectTimeFromMacinfoTable(%s)",macAddress);
+  ret = getDetectTimeFromMacinfoTable(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=getDetectTimeFromMacinfoTable( )",ret);
+  return ret;
+}
+int IsSessionFoundInSessionTable(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isSessionFoundInSessionTable(%s)",macAddress);
+  ret = isSessionFoundInSessionTable(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isSessionFoundInSessionTable( )",ret);
+  return ret;
+}
+
+int SaveCookieToWorkDb(char* cookie, char* userId, char* extraId, int userType){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>saveCookieToWorkDb(%s,%s,%s,%d)",cookie,userId,extraId,userType);
+  ret = saveCookieToWorkDb(cookie,userId,extraId,userType);
+  if(debug>1) err_msg("DEBUG:(%d)<=saveCookieToWorkDb( )",ret);
+  return ret;
+}
+
+int IsCookieFoundInWorkDb(char* cookie, char* userId, char* extraId, int userType){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=> isCookieFoundInWorkDb(%s,%d)",cookie, userType);
+  ret = isCookieFoundInWorkDb(cookie,userId,extraId,userType);
+  if(debug>1) err_msg("DEBUG:(%d)<=isCookieFoundInWorkDb(%s,%s)",ret, userId,extraId);
+  return ret;
+}
+
+int GetMailDefaultFromWorkDb(char* cookie, char* mailDefault){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=> getMailDefaultFromWorkDb(%s)",cookie);
+  ret = getMailDefaultFromWorkDb(cookie,mailDefault);
+  if(debug>1) err_msg("DEBUG:(%d)<=getMailDefaultFromWorkDb(%s)",ret,mailDefault);
+  return ret;
+}
+
+int IsNatSuspectedInWorkDb(char* macAddr){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isNatSuspectedInWorkDb(%s)", macAddr);
+  ret = isNatSuspectedInWorkDb(macAddr);
+  if(debug>1) err_msg("DEBUG:(%d)<=isNatSuspectedInWorkDb( )", ret);
+  return ret;
+}
+
+int SaveMacForCookieToWorkDb(char* cookie, char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>saveMacForCookieToWorkDb(%s,%s)", cookie,macAddress);
+  ret = saveMacForCookieToWorkDb(cookie,macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=saveMacForCookieToWorkDb( )", ret);
+  return ret;
+}
+
+int SaveMailDefalutForCookieToWorkDb(char* cookie, char* mailDefault){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>saveMailDefalutForCookieToWorkDb(%s,%s)", cookie,mailDefault);
+  ret = saveMailDefalutForCookieToWorkDb(cookie,mailDefault);
+  if(debug>1) err_msg("DEBUG:(%d)<=saveMailDefalutForCookieToWorkDb( )", ret);
+  return ret;
+}
+
+
+int LoadMacForCookieFromWorkDb(char* cookie, char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>loadMacForCookieFromWorkDb(%s)", cookie);
+  ret = loadMacForCookieFromWorkDb(cookie,macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=loadMacForCookieFromWorkDb(%s)", ret, macAddress);
+  return ret;
+}
+
+int IsActiveSessionFoundInOpengateSessionTable(char* macAddress){
+  int ret;
+  if(debug>1) err_msg("DEBUG:=>isActiveSessionFoundInOpengateSessionTable(%s)", macAddress);
+  ret = isActiveSessionFoundInOpengateSessionTable(macAddress);
+  if(debug>1) err_msg("DEBUG:(%d)<=isActiveSessionFoundInOpengateSessionTable( )", ret);
+  return ret;
+}
diff --git a/phpsrc/showlog.php b/phpsrc/showlog.php
new file mode 100644 (file)
index 0000000..80e3123
--- /dev/null
@@ -0,0 +1,74 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+
+<h2>Show Log</h2>
+
+<?php
+
+  // check basic auth 
+  if(getenv('REMOTE_USER')=='')  die('Cannot get auth');
+
+  // set default values
+  $userId=$device='%';
+  $now=date('Y-m-d H:i:s');
+  $fromTime=date('Y-m-d H:i:s', strtotime($now." -3 day"));
+  $toTime=$now;
+
+  // get request data
+  if(isset($_GET['userId']))$userId=$_GET['userId'];
+  if(isset($_GET['device']))$device=$_GET['device'];
+  if(isset($_GET['fromTime']))$fromTime=$_GET['fromTime'];
+  if(isset($_GET['toTime']))$toTime=$_GET['toTime'];
+
+  // show html table for query parameters
+  print("<p><table>");
+  print("<form method=GET action=showlog.php");
+  print("<tr><td>UserId</td><td><input size=30 type=text name=userId value='".$userId."'></td></tr>");
+  print("<tr><td>Device</td><td><input size=30 type=text name=device value='".$device."'></td></tr>");
+  print("<tr><td>FromTime</td><td><input size=30 type=text name=fromTime value='".$fromTime."'></td></tr>");
+  print("<tr><td>ToTime</td><td><input size=30 type=text name=toTime value='".$toTime."'></td></tr>");
+  print("<tr><td></td><td><input type=submit value='send'></td></tr>");
+  print("</table></p>");
+
+  // connect and access to MySql db
+  $link = mysql_connect('localhost', 'root', '');
+  if (!$link) die('Cannot connet to DB'.mysql_error());
+
+  $db_selected = mysql_select_db('opengatem', $link);
+  if (!$db_selected) die('Cannot select DB'.mysql_error());
+
+  mysql_set_charset('utf8');
+
+  $result = mysql_query('SELECT * FROM sessionview where userId like "'.$userId.'" and device like "'.$device.'" and "'.$fromTime.'"<openTime and openTime<"'.$toTime.'"');
+
+  if (!$result) die('Fail query'.mysql_error());
+
+  // show header line
+  print("<table border=1>");
+  print('<tr>');
+  $count=0;
+  while ($field = mysql_fetch_field($result)) {
+    print('<td>'.$field->name.'</td>');
+    $count++;
+  }
+  print('</tr>');
+
+  // show rows
+  while ($row = mysql_fetch_row($result)) {
+    print('<tr>');
+    for($i=0; $i<$count; $i++){
+      print('<td>'.$row[$i].'</td>');
+    }
+    print('</tr>');
+  }
+
+  print("</table>");
+  $close_flag = mysql_close($link);
+
+?>
+
+</body>
+</html>
diff --git a/phpsrc/showtable.php b/phpsrc/showtable.php
new file mode 100644 (file)
index 0000000..263347f
--- /dev/null
@@ -0,0 +1,60 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+
+<h2>Show Tables</h2>
+<p>
+<a href='showtable.php?table=macaddrs'>macaddrs</a> 
+<a href='showtable.php?table=sessionmd'>sessionmd</a> 
+<a href='showtable.php?table=sessionview'>sessionview</a> 
+<a href='showtable.php?table=nicvendors'>nicvendors</a> <br>
+(Show max 1000 rows of selected table).
+</p>
+
+<?php
+
+  // check basic auth
+  if(getenv('REMOTE_USER')=='')  die('Cannot get auth');
+
+  // no table is indicated 
+  if(!isset($_GET['table']))return;
+
+  // connect and access to MySql DB
+  $link = mysql_connect('localhost', 'root', '');
+  if (!$link) die('Cannot connect DB'.mysql_error());
+
+  $db_selected = mysql_select_db('opengatem', $link);
+  if (!$db_selected) die('Cannot select DB'.mysql_error());
+
+  mysql_set_charset('utf8');
+
+  $result = mysql_query('SELECT * FROM '.$_GET['table'].' limit 1000');
+  if (!$result) die('Fail query'.mysql_error());
+
+  // print header
+  print("<table border=1>");
+  print('<tr>');
+  $count=0;
+  while ($field = mysql_fetch_field($result)) {
+    print('<td>'.$field->name.'</td>');
+    $count++;
+  }
+  print('</tr>');
+
+  // print rows
+  while ($row = mysql_fetch_row($result)) {
+    print('<tr>');
+    for($i=0; $i<$count; $i++){
+      print('<td>'.$row[$i].'</td>');
+    }
+    print('</tr>');
+  }
+  print("</table>");
+  $close_flag = mysql_close($link);
+
+?>
+
+</body>
+</html>
diff --git a/phpsrc/updatemactable.php b/phpsrc/updatemactable.php
new file mode 100644 (file)
index 0000000..7b67e28
--- /dev/null
@@ -0,0 +1,113 @@
+<html>
+<head>
+<title></title>
+</head>
+<body>
+
+<h2>Update Mac Address Registration</h2>
+
+<?php
+
+  // check basic auth
+  if(getenv('REMOTE_USER')=='')  die('Cannot get auth');
+
+  // if userid is not set, request input and return
+  if(!isset($_POST['userId'])){
+    print('<form method=POST action=updatemac.php>');
+    print('UserId:<input type=text name=userId>');
+    print('<input type=submit value="Send">');
+    print('<input type=reset value="Reset">');
+    print('</form>');
+    return;
+  }
+  $userId=$_POST['userId'];
+  
+  // setup MySql DB
+  $link = mysql_connect('localhost', 'root', '');
+  if (!$link) die('Cannot connect DB'.mysql_error());
+
+  $db_selected = mysql_select_db('opengatem', $link);
+  if (!$db_selected) die('cannot select DB'.mysql_error());
+
+  mysql_set_charset('utf8');
+
+  // if data is posted, update DB
+  $i=0;
+  while(isset($_POST['macAddress'][$i])){
+
+    if($_POST['status'][$i]=='D'){
+      // on delete 
+      // UPDATE macaddrs SET status="D",device="postdata",limitdate=now(),mailAddress="postdata"
+      //       WHERE macAddress="postdata" and userId="postdata" and status!="D"
+
+      $result = mysql_query('UPDATE macaddrs SET status="'.$_POST['status'][$i]
+              .'", device="'.$_POST['device'][$i].'", limitDate=now()'
+              .', mailAddress="'.$_POST['mailAddress'][$i].'" WHERE macAddress="'
+              .$_POST['macAddress'][$i].'" and userId="'.$userId.'" and status!="D"');
+      if (!$result) die('Fail update query'.mysql_error());
+
+    }else if($_POST['status'][$i]=='A'||$_POST['status'][$i]=='I'){
+      // other cases
+      // UPDATE macaddrs SET status="D",device="postdata",limitdate="postdata",mailAddress="postdata"
+      //       WHERE macAddress="postdata" and userId="postdata" and status!="D"
+
+      $result = mysql_query('UPDATE macaddrs SET status="'.$_POST['status'][$i]
+              .'", device="'.$_POST['device'][$i].'", limitDate="'.$_POST['limitDate'][$i]
+              .'", mailAddress="'.$_POST['mailAddress'][$i].'" WHERE macAddress="'
+              .$_POST['macAddress'][$i].'" and userId="'.$userId.'" and status!="D"');
+      if (!$result) die('Fail update query'.mysql_error());
+
+    }else{
+      print("<font color=red>Illegal status value</font>");
+    }
+    $i++;
+  }
+
+  // get data from DB to show on web
+  $result = mysql_query('SELECT macAddress,status,device,limitDate,mailAddress FROM macaddrs where userId="'
+            .$userId.'"');
+  if (!$result) die('Fail select query'.mysql_error());
+
+ // print html form
+  print('<form method=POST action=updatemac.php>');
+  print('UserId:<input type=text name=userId value="'.$userId.'">');
+  print('<input type=submit value="Send">');
+  print('<input type=reset value="Reset">');
+
+  // print header
+  print("<table border=1>");
+  print('<tr>');
+  $count=0;
+  while ($field = mysql_fetch_field($result)) {
+    print('<td>'.$field->name.'</td>');
+    $fieldName[$count]=$field->name;
+    $count++;
+  }
+  print('</tr>');
+
+  // print rows
+  while ($row = mysql_fetch_row($result)) {
+    print('<tr>');
+    if($row[1]=='D'){  // deleted items
+      for($i=0; $i<$count; $i++){
+        print('<td>'.$row[$i].'</td>');
+      }
+    }else{                   // other items
+      for($i=0; $i<$count; $i++){
+        if($i==0){
+          print('<td><input size=30 type=text name='.$fieldName[$i].'[] value="'.$row[$i].'" readonly></td>');
+        }else{
+          print('<td><input size=30 type=text name='.$fieldName[$i].'[] value="'.$row[$i].'"></td>');
+        }
+      }
+    }
+    print('</tr>');
+  }
+  print('</table>');
+  print('</form>');
+  $close_flag = mysql_close($link);
+
+?>
+<p>status char: A=Actice, I=InActive, D=Deleted</p>
+</body>
+</html>
diff --git a/phpsrc/updatevendortable.php b/phpsrc/updatevendortable.php
new file mode 100644 (file)
index 0000000..8cba8e9
--- /dev/null
@@ -0,0 +1,62 @@
+<?php\r
+\r
+// Create or Update the vendor table in Management DB.\r
+// The table is used in opengatemchk\r
+//\r
+// At installation, run to create vendor table\r
+//\r
+// After installation, run periodically to update vendor table.\r
+\r
+\r
+//connect to Management DB (* set proper parameters *)\r
+$link = mysql_connect("localhost", "root", "");\r
+if (!$link) die('Cannot connect to DB.'.mysql_error());\r
+\r
+// select opengatem database\r
+$db_selected = mysql_select_db('opengatem', $link);\r
+if (!$db_selected) die('Cannot select DB.'.mysql_error());\r
+\r
+// create table if not exists\r
+$sql = "CREATE TABLE IF NOT EXISTS nicvendors(oui CHAR(8), org TINYTEXT)";\r
+mysql_query($sql);\r
+\r
+// connect to oui list in IEEE site\r
+$fp = fopen("http://standards.ieee.org/develop/regauth/oui/oui.txt", "r");\r
+if(!$fp) die('Cannot connect to IEEE site. Check network connection');\r
+\r
+// scan the download list\r
+while (!feof($fp)) {\r
+\r
+  // get one line\r
+  $line = fgets($fp);\r
+\r
+  // columns 0-7 may be oui \r
+  $oui = substr($line, 0, 8);\r
+\r
+  //if $oui is not "**-**-**", skip the line\r
+  if(preg_match('/^[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}$/',$oui)!=1)continue;\r
+\r
+  // reformat $oui from "01-56-AB" to "01:56:ab"\r
+  $oui = str_replace("-",":",$oui);\r
+  $oui = strtolower($oui);\r
+\r
+  // column 16- should be vendor name (trim CR code)\r
+  $org = substr($line, 16);\r
+\r
+  // remove CR code and quotation code\r
+  $org = str_replace(array("\r\n","\n","\r"), "", $org);\r
+  $org = str_replace("\"", "", $org);\r
+  $org = str_replace("\t", "", $org);\r
+\r
+  // insert to db\r
+  $sql = sprintf(\r
+    'REPLACE INTO nicvendors (oui,org) VALUES( "%s", "%s")',\r
+    $oui, $org);\r
+  mysql_query($sql);\r
+\r
+  // log to console\r
+  print $oui." ".$org."<br>\n";\r
+}\r
+fclose($fp);\r
+?>\r
+\r
diff --git a/rc.d/opengatemd b/rc.d/opengatemd
new file mode 100755 (executable)
index 0000000..4685408
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+
+# PROVIDE: opengatemd
+# REQUIRE: DAEMON
+# BEFORE: 
+
+. /etc/rc.subr
+
+name="opengatemd"
+rcvar=`set_rcvar`
+command="/usr/local/bin/opengatemd"
+
+load_rc_config $name
+run_rc_command "$1"
diff --git a/sqlscript/createtablescript b/sqlscript/createtablescript
new file mode 100644 (file)
index 0000000..8db0523
--- /dev/null
@@ -0,0 +1,47 @@
+/* Create MySql tables at installation
+ USE AS
+  mysql < createscript
+*/
+create database if not exists opengatem;
+use opengatem;
+create table if not exists macaddrs(
+       macAddress CHAR(18),
+       status CHAR(1),
+       device TINYTEXT,
+       userId TINYTEXT,
+       extraId TINYTEXT,
+       mailAddress TINYTEXT,
+       entryDate DATETIME,
+       renewDate DATETIME,
+       limitDate DATETIME);
+
+create table if not exists sessionmd(
+       macAddress CHAR(18),
+       ipAddress TINYTEXT,
+       gatewayName TINYTEXT,
+       openTime DATETIME,
+       closeTime DATETIME);
+
+create table if not exists macmodify(
+       userId TINYTEXT,
+       extraId TINYTEXT,
+       macAddress CHAR(18),
+       modifyType CHAR(1),
+       modifyDate DATETIME);
+
+create table if not exists nicvendors(
+       oui CHAR(8),
+       org TINYTEXT);
+
+create view sessionview as select
+       userId,
+       extraId,
+       macaddrs.macAddress,
+       device,
+       openTime,
+       closeTime,
+       gatewayName,
+       ipAddress
+       from macaddrs,sessionmd 
+       where macaddrs.macAddress=sessionmd.macAddress 
+       and entryDate<openTime and openTime<limitDate;
diff --git a/sqlscript/insertmacscript b/sqlscript/insertmacscript
new file mode 100644 (file)
index 0000000..5243dc2
--- /dev/null
@@ -0,0 +1,23 @@
+insert into opengatem.macaddrs values(
+       '01:23:45:67:89:ab',
+       'A',
+       'iPad2',
+       'watanaby',
+       '',
+       'watanaby@is.saga-u.ac.jp',
+       now(),
+       now(),
+       adddate(now(), interval 1 month));
+
+insert into opengatem.macaddrs values(
+       '67:89:ab:cd:ef:01',
+       'A',
+       'Android tablet',
+       'watanaby',
+       '',
+       'watanaby@is.saga-u.ac.jp',
+       now(),
+       now(),
+       adddate(now(), interval 1 month));
+
+
diff --git a/sqlscript/updatescript1 b/sqlscript/updatescript1
new file mode 100644 (file)
index 0000000..e8a1622
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+Change the mac address to deleted mode 
+for device passing limit date and belonging to specific user (extraId indicated).
+Use as
+ mysql < createscript1
+*/
+use opengatem;
+update macaddrs set status='D' where extraId!='' and limitDate<now() and status!='D';
diff --git a/sqlscript/updatescript2 b/sqlscript/updatescript2
new file mode 100644 (file)
index 0000000..1e5d8dc
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+Change the mac address to deleted mode 
+for device passing 6 month after limit date.
+Use as
+ mysql < createscript2
+*/
+use opengatem;
+update macaddrs set status='D' where limitDate<adddate(now(), interval -6 month) and status!='D';
+
diff --git a/sqlscript/updatescript3 b/sqlscript/updatescript3
new file mode 100644 (file)
index 0000000..3d0ec3c
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+Remove the mac address record 
+for device passing 1 year after limit date.
+Use as
+ mysql < createscript3
+*/
+use opengatem;
+delete from macaddrs where limitDate<adddate(now(), interval -1 year);
+
+