/* #Specification: html mode / access limitation
We can specify the network or host which are allowed to access linuxconf
in web mode. We can simply define a set of network and netmask pairs.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "internal.h"
#include "netconf.h"
#include "netconf.m"
#include
#include "hostinfo.h"
static NETCONF_HELP_FILE help_access ("html_access");
static CONFIG_FILE htmllog (VAR_LOG_HTML_LOG,help_access
,CONFIGF_MANAGED|CONFIGF_OPTIONAL
,"root","root",0600);
class HTML_ACCESS: public ARRAY_OBJ{
public:
SSTRING net;
SSTRING mask;
unsigned long badr;
unsigned long bmask;
int err; // Is this entry is valid (usable)
/*~PROTOBEG~ HTML_ACCESS */
public:
HTML_ACCESS (const char *_net, const char *_mask);
/*~PROTOEND~ HTML_ACCESS */
};
PUBLIC HTML_ACCESS::HTML_ACCESS(const char *_net, const char *_mask)
{
net.setfrom (_net);
mask.setfrom (_mask);
err = 0;
badr = bmask = 0;
}
class HTML_ACCESS_TB: public ARRAY{
public:
char dolog;
char enabled;
/*~PROTOBEG~ HTML_ACCESS_TB */
public:
HTML_ACCESS_TB (void);
private:
void addfield (DIALOG&dia, HTML_ACCESS *a);
void addfields (DIALOG&dia);
public:
int check (unsigned long badr, int printlog);
int compute (SSTRING&errmsg);
int edit (void);
HTML_ACCESS *getitem (int no);
void setdefaults (void);
int write (void);
/*~PROTOEND~ HTML_ACCESS_TB */
};
static const char HTMLACCESS[]="htmlaccess";
static const char FROM[]="from";
static const char DOLOG[]="dolog";
static const char ENABLE[]="enable";
PUBLIC HTML_ACCESS_TB::HTML_ACCESS_TB()
{
SSTRINGS tb;
int n = linuxconf_getall (HTMLACCESS,FROM,tb,0);
for (int i=0; iget(),"%s %s",net,mask);
add (new HTML_ACCESS(net,mask));
}
dolog = linuxconf_getvalnum (HTMLACCESS,DOLOG,0);
enabled = linuxconf_getvalnum (HTMLACCESS,ENABLE,0);
}
PUBLIC HTML_ACCESS *HTML_ACCESS_TB::getitem(int no)
{
return (HTML_ACCESS *)ARRAY::getitem(no);
}
PUBLIC int HTML_ACCESS_TB::write()
{
linuxconf_setcursys (subsys_netaccess);
int n=getnb();
linuxconf_removeall(HTMLACCESS,FROM);
for (int i=0; inet.is_empty()){
char buf[400];
snprintf (buf,sizeof(buf)-1,"%s %s",a->net.get(),a->mask.get());
linuxconf_add (HTMLACCESS,FROM,buf);
}
}
linuxconf_replace (HTMLACCESS,DOLOG,dolog);
linuxconf_replace (HTMLACCESS,ENABLE,enabled);
return linuxconf_save();
}
/*
Add one network to the dialog
*/
PRIVATE void HTML_ACCESS_TB::addfield(DIALOG &dia, HTML_ACCESS *a)
{
dia.newf_str (MSG_U(F_NETWORKHOST,"network or host"),a->net);
dia.newf_str (MSG_U(F_NETMASKOPT,"netmask(opt)"),a->mask);
}
/*
Add two empty networks to the dialog
*/
PRIVATE void HTML_ACCESS_TB::addfields(DIALOG &dia)
{
for (int i=0; i<2; i++){
HTML_ACCESS *a = new HTML_ACCESS ("","");
add (a);
addfield (dia,a);
}
}
static HTML_ACCESS_TB *tblookup;// Use to speed up html_access_check
// avoiding reloading the struct all
// the time.
PUBLIC int HTML_ACCESS_TB::edit()
{
DIALOG dia;
/* #Specification: html access / dialog / add button
The add button simply add few more empty lines at the
end of the dialog
*/
int n=getnb();
dia.newf_chk ("",enabled,MSG_U(F_ENABLEHTML,"Enable network access"));
char logmsg[100];
snprintf (logmsg,sizeof(logmsg)-1,MSG_U(I_LOGACCESS,"in %s"),htmllog.getpath());
dia.newf_chk (MSG_U(F_LOGACCESS,"Log access"),dolog,logmsg);
for (int i=0; inet.is_filled() && a->mask.is_filled()
&& !ipnum_validnet(a->net.get(),a->mask.get())){
error = true;
nof = 2 + i*2;
xconf_error (MSG_U(E_IVLDNETWORK
,"Invalid network number %s\n"
"It does not comply with the supplied\n"
"or default netmask"),a->net.get());
}
}
if (!error){
if (!simul_isdemo()){
delete tblookup;
tblookup = NULL;
write();
}
break;
}
}
}
return 0;
}
void html_access_edit()
{
HTML_ACCESS_TB htb;
htb.edit ();
}
/*
To speed up peer lookup, we walk the list of hosts/networks allowed
and resolved the addresses and netmask
This function is also used to validate the dialog inputs.
Return -1 if any error in the data.
*/
PUBLIC int HTML_ACCESS_TB::compute(SSTRING &errmsg)
{
errmsg.setempty();
int ret = 0;
int n = getnb();
for (int i=0; ierr = 0;
const char *net = a->net.get();
if (net[0] != '\0'){
/* #Specification: html access / host or net spec
We can use the following things to specify a network or
host access. A default suitable netmask is computed
and is used unless one is supplied in the dialog.
#
-An IP number
-A host name
-A network name
-A device name (eth0). In this case the spec will be
extracted
#
*/
char ipstr[16],mskstr[16];
if (netconf_convert (net,ipstr,mskstr)==-1){
ret = -1;
a->err = 1;
errmsg.appendf (MSG_U(E_IVLDHOSTNET
,"invalid host or network: %s\n")
,net);
}else{
int n[4];
ipnum_aip24(ipstr,n);
a->badr = ((unsigned)n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3];
const char *msk = a->mask.get();
if (msk[0] == '\0') msk = mskstr;
if (ipnum_aip24(msk,n)!=-1){
a->bmask = ((unsigned)n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3];
}else{
ret = -1;
a->err = 1;
errmsg.appendf (MSG_U(E_IVLDMASK,"invalid netmask: %s\n")
,msk);
}
}
/* #Specification: html access / using a host to spec a net
One can use a host to specify a network by using the
proper netmask. This allows one to say "I accept all
machine of the same network as this one".
*/
a->badr &= a->bmask;
}
}
return ret;
}
/*
Tell if one host address is acceptable (in this list)
Return -1 if not
*/
PUBLIC int HTML_ACCESS_TB::check(unsigned long badr, int printlog)
{
int ret = -1;
int n = getnb();
for (int i=0; ierr){
if (a->badr==(badr & a->bmask)){
ret = 0;
}else if (printlog){
char buf1[16],buf2[16],buf3[16];
ipnum_ip2a (a->badr,buf1);
ipnum_ip2a (a->bmask,buf2);
ipnum_ip2a (badr,buf3);
syslog (LOG_ERR,MSG_U(E_IPNOMATCH,"IP %s do not match %s/%s")
,buf3,buf1,buf2);
}
}
}
return ret;
}
/*
Record default rules when noone are defined
See the spec at the top of this file
*/
PUBLIC void HTML_ACCESS_TB::setdefaults()
{
/* #Specification: html mode / access limitation / default rule
The default behavior is to accept connection originating from
only from the machine itself (loopback 127.0.0.1).
Once one rule is entered, the default is gone, even the loopback won't
be accepted.
Note also that web access is completly disabled by default.
*/
if (getnb()==0){
// Set the default behavior
add (new HTML_ACCESS("127.0.0.1","255.255.255.255"));
#if 0
HOSTINFO info;
if (netconf_loadinfos(info)!=-1){
const char *ipadr = info.a[0].ipaddr.get();
char stdmask[16];
const char *mask = info.a[0].netmask.get();
if (mask[0] == '\0'){
mask = stdmask;
device_setstdnetmask(ipadr,stdmask);
}
add (new HTML_ACCESS(ipadr,mask));
}
#endif
}
}
/*
Check if a socket connection is coming from an accepted host
Return 0 if the "client" is allowed, -1 if not.
*/
static int html_access_check (
int fd,
const char *msg)
{
int ret = -1;
struct sockaddr_in adr;
unsigned int len = sizeof(adr);
if (getpeername (fd,(struct sockaddr*)&adr,&len) != -1){
if (linuxconf_reloadif()){
delete tblookup;
tblookup = NULL;
}
if (tblookup == NULL){
tblookup = new HTML_ACCESS_TB;
tblookup->setdefaults();
SSTRING errmsg;
tblookup->compute(errmsg);
}
if (tblookup->enabled){
unsigned long addr = ntohl(adr.sin_addr.s_addr);
ret = tblookup->check(addr,0);
if (ret == -1){
tblookup->check(addr,1);
}else if (msg != NULL && tblookup->dolog){
FILE_CFG *fout = htmllog.fopen_ok ("a");
if (fout != NULL){
struct hostent *host = gethostbyaddr(
(char*)&adr.sin_addr.s_addr,sizeof(addr)
,AF_INET);
time_t tim = time(NULL);
char datestr[100];
strftime (datestr,sizeof(datestr)-1,"%b %d %H:%M:%S"
,localtime(&tim));
char buf[16];
const char *hostptr;
if (host == NULL){
ipnum_ip2a (addr,buf);
hostptr = buf;
}else{
hostptr = host->h_name;
}
fprintf (fout,"%s %s %s\n",datestr,hostptr,msg);
fclose (fout);
}
}
}
}
return ret;
}
/*
Check if a socket connection is coming from an accepted host
Return 0 if the "client" is allowed, -1 if not.
*/
int html_access_check (
int fd)
{
return html_access_check(fd,NULL);
}
/*
Append a message to the /var/log/htmlaccess.log if configured.
*/
void html_access_log (
int fd,
const char *msg)
{
html_access_check(fd,msg);
}
#include
static PUBLISH_VARIABLES_MSG html_var_list[]={
{"enable",P_MSG_R(F_ENABLEHTML)},
{"logmsg",P_MSG_R(F_LOGACCESS)},
{"network",P_MSG_R(F_NETWORKHOST)},
{"netmask",P_MSG_R(F_NETMASKOPT)},
{ NULL, NULL }
};
static REGISTER_VARIABLES html_registry1("html_access",html_var_list
,NULL,html_access_edit);