/**************************************************
OpengateM - MAC address authentication system 

 Module for mac address registration cgi main
 This is used for registration of devices without Web browser
 (devices having Web is registered by using opengatemown page)
 This page is called from opengatemchk page and 
 registers the address selected in opengatemchk page. 
 
 Opengatemchk page(operated by administrator) requires ADMIN's auth
  and set ADMIN cookie. Opengatemreg page(operated by user) 
  requites ADMIN cookie and NORMAL user's auth.

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) */
  /* the register button in check page calls this cgi */ 
  GetLangFromQueryString(language);
  GetMacAddrFromQueryString(macAddress);

  /* if accessed via nat or router, return  */
  /* if nat, isNatRouter=NAT(1). if router, isNatRouter=ROUTER(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, */
  /* the existence of cookie certifies the jumping from check page. */
  if(!IsCorrectCookie(adminCookie, ADMINUSER)){
    SetMessage(NotSetAdminCookie);
    PutDenyToClient(language);
    return 0;
  }

  /* if get mac address in query string, save the 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 some request is sent 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( )");
}
