home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
WEBSERVE
/
SAMBAR
/
DATA.1
/
security.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-22
|
18KB
|
796 lines
/*
** SECURITY
**
** HTTP Wrapper for the Security Management Routines
**
** Confidential Property of Tod Sambar
** (c) Copyright Tod Sambar 1996-1997
** All rights reserved.
**
**
** Public Functions:
**
** security_init
** security_exit
** security_request
** security_connect
** security_filter
**
** Note:
** By default, all objects placed in the sysadmin folder (under docs)
** are required to have system administrator access. All other
** security features are implemented through external event handlers.
**
** History:
** Chg# Date Description Resp
** ---- ------- ------------------------------------------------------- ----
** 4FEB97 Created sambar
** 23APR97 Added network connect security sambar
** 09APR97 Added AD/site security filtering sambar
** 07JUL97 Added multiple users/groups on the security line sambar
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <security.h>
/*
** Local Functions
*/
SA_RETCODE security__load(SA_CTX *ctx, SA_VOID *argp,
SA_CHAR *name, SA_CHAR *value);
static SA_INT security__casecmp(SA_CHAR *str1, SA_CHAR *str2,
SA_INT len);
/*
** Local Structures
*/
typedef struct security__entry
{
SA_INT id;
SA_CHAR *symbol;
SA_CHAR *descr;
} SECURITY_ENTRY;
/*
** Local Defines
*/
#define DENIED_HEADER "HTTP/1.0 404 Request denied.\nContent-type: text/html\n\n<HTML><BODY>"
#define DENIED_BODY "Request denied by Sambar Server Proxy filter.<P>"
#define DENIED_FOOTER "</BODY></HTML>"
static SECURITY_ENTRY Security_entries[] =
{
{ SECURITY_REDIRECT, "redirect",
"URI to Redirect / URL to Redirect to" },
{ SECURITY_RESTRICT, "restrict",
"URI to Restrict / User or Group granted access" },
{ SECURITY_DENY, "deny",
"IP to deny access to / URL to redirect offending hosts to" },
{ SECURITY_HTTPACCEPT, "httpaccept",
"IP addresses to accept HTTP hosts from" },
{ SECURITY_HTTPDENY, "httpdeny",
"IP addresses of hosts to deny HTTP access to" },
{ SECURITY_FTPACCEPT, "ftpaccept",
"IP addresses to accept FTP hosts from" },
{ SECURITY_FTPDENY, "ftpdeny",
"IP addresses of hosts to deny FTP access to" },
{ SECURITY_NNTPACCEPT, "nntpaccept",
"IP addresses to accept NNTP hosts from" },
{ SECURITY_NNTPDENY, "nntpdeny",
"IP addresses of hosts to deny NNTP access to" },
{ SECURITY_PROXYACCEPT, "proxyaccept",
"IP addresses to accept Proxy hosts from" },
{ SECURITY_PROXYDENY, "proxydeny",
"IP addresses of hosts to deny Proxy access to" },
{ SECURITY_HOSTFILTER, "hostfilter",
"Hosts to restrict proxy requests from (AD/Content filtering)" },
{ SECURITY_URLFILTER, "urlfilter",
"URLs to restrict proxy requests from (AD/Content filtering)" }
};
#define NUM_ENTRIES sizeof(Security_entries) / sizeof(SECURITY_ENTRY)
static SECURITY *Entries[NUM_ENTRIES];
/*
** SECURITY_INIT
**
** Initialize the Security Rules for use by the Sambar Server plugins.
** Rules are only loaded at application initialization time and (as this
** is a threaded application) cannot be modified without a restart of
** the server (or mutexing).
**
**
** Parameters:
** sactx Sambar Server context
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_init(sactx)
SA_CTX *sactx;
{
SA_INT i;
for (i = 0; i < NUM_ENTRIES; i++)
Entries[i] = (SECURITY *)NULL;
/*
** Load the security rules from the security.ini file
*/
for (i = 0; i < NUM_ENTRIES; i++)
{
if (sa_props_load(sactx, "security.ini", Security_entries[i].symbol,
&Security_entries[i].id, (SA_PROPFUNC)security__load) != SA_SUCCEED)
{
SA_CHAR buffer[256];
sprintf(buffer, "Failure loading [%s] security section.",
Security_entries[i].symbol);
sa_log(sactx, buffer);
}
}
/* Initialize the "showsec" RPC */
if (sa_cmd_init(sactx, "showsec", SA_AUTHORIZATION_ADMIN,
"Security rule display.", (SA_VOID *)security_showsec) != SA_SUCCEED)
{
sa_log(sactx, "Unable to initialize Security RPCs");
return (SA_FAIL);
}
sa_log(sactx, "Security Interfaces Initialized");
return (SA_SUCCEED);
}
/*
** SECURITY_EXIT
**
** Free the Security Rules.
**
** Parameters:
** sactx Sambar Server context
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_exit(sactx)
SA_CTX *sactx;
{
SA_INT i;
SECURITY *snext;
SECURITY *security;
ENTRY *enext;
ENTRY *entry;
/*
** Free the security rules previously loaded from the security.ini file
*/
for (i = 0; i < NUM_ENTRIES; i++)
{
security = Entries[i];
while (security != (SECURITY *)NULL)
{
snext = security->next;
free(security->name);
entry = security->entries;
while (entry != (ENTRY *)NULL)
{
enext = entry->next;
free(entry->value);
free(entry);
entry = enext;
}
free(security);
security = snext;
}
}
sa_log(sactx, "Security Interfaces Exited");
return (SA_SUCCEED);
}
/*
** SECURITY_REQUEST
**
** Determine if the request should be fulfilled.
**
** Parameters:
** sactx Sambar Server context
** saconn Client connection handle.
** uri The URI associated with the request.
** urilen The length of the URI string.
** params The parameters associated with the request.
** infop The error status returned on failure.
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_request(sactx, saconn, uri, urilen, params, infop)
SA_CTX *sactx;
SA_CONN *saconn;
SA_CHAR *uri;
SA_INT urilen;
SA_PARAMS *params;
SA_INT *infop;
{
SA_BOOL found;
SA_INT namelen;
SA_CHAR name[40];
SA_INT pwdlen;
SA_CHAR pwd[40];
ENTRY *entry;
SECURITY *security;
/*
** REDIRECT
*/
security = Entries[SECURITY_REDIRECT];
while (security != (SECURITY *)NULL)
{
if ((urilen >= security->namelen) &&
(security__casecmp(uri, security->name, security->namelen) == 0))
{
*infop = SA_E_REDIRECT;
entry = security->entries;
(SA_VOID)sa_conn_redirect(saconn, entry->value,
"Request redirected.", SA_NULLTERM);
return (SA_FAIL);
}
security = security->next;
}
/*
** RESTRICT
*/
security = Entries[SECURITY_RESTRICT];
while (security != (SECURITY *)NULL)
{
SA_PASSWD passwd;
if ((urilen >= security->namelen) &&
(security__casecmp(uri, security->name, security->namelen) == 0))
{
if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_NAME, name, 40,
&namelen) != SA_SUCCEED)
{
*infop = SA_E_INVALIDLOGIN;
return (SA_FAIL);
}
/* Now lookup the name/password in the passwd file */
if (sa_passwd_lookup(sactx, name, namelen, &passwd) != SA_SUCCEED)
{
*infop = SA_E_INVALIDLOGIN;
return (SA_FAIL);
}
/* Get the password and verify the match */
if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_PASSWORD, pwd, 40,
&pwdlen) != SA_SUCCEED)
{
*infop = SA_E_INVALIDLOGIN;
return (SA_FAIL);
}
if ((passwd.passwordlen != pwdlen) ||
(strncmp(passwd.password, pwd, pwdlen) != 0))
{
*infop = SA_E_INVALIDLOGIN;
return (SA_FAIL);
}
/*
** Lastly, verify the security entry(s) match either the name
** or group name of the user.
*/
found = 0;
entry = security->entries;
while ((!found) && (entry != (ENTRY *)NULL))
{
/* Match with the username? */
if ((namelen == entry->valuelen) &&
(memcmp(entry->value, name, namelen) == 0))
{
found = 1;
continue;
}
/* Match with the user group? */
if ((passwd.grouplen == entry->valuelen) &&
(memcmp(entry->value, passwd.group, passwd.grouplen) == 0))
{
found = 1;
continue;
}
entry = entry->next;
}
if (!found)
{
*infop = SA_E_INVALIDLOGIN;
return (SA_FAIL);
}
}
security = security->next;
}
/*
** DENY
*/
if ((Entries[SECURITY_DENY] != (SECURITY *)NULL) &&
(sa_conn_props(saconn, SA_GET, SA_CONNPROP_HOST, name, 40,
&namelen) == SA_SUCCEED))
{
security = Entries[SECURITY_DENY];
while (security != (SECURITY *)NULL)
{
if ((namelen >= security->namelen) &&
(strncmp(name, security->name, security->namelen) == 0))
{
entry = security->entries;
*infop = SA_E_REDIRECT;
(SA_VOID)sa_conn_redirect(saconn, entry->value,
"Request redirected.", SA_NULLTERM);
return (SA_FAIL);
}
security = security->next;
}
}
return (SA_SUCCEED);
}
/*
** SECURITY_CONNECT
**
** Determine if the connection should be allowed.
**
** Parameters:
** sactx Sambar Server context
** ipaddr The IP address of the client requesting a connection.
** servertype The server the client is attempting to connect to.
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_connect(sactx, ipaddr, servertype)
SA_CTX *sactx;
SA_CHAR *ipaddr;
SA_INT servertype;
{
SA_INT denyid;
SA_INT acceptid;
SA_INT ipaddrlen;
SA_BOOL found;
SA_CHAR *server;
SECURITY *security;
SA_CHAR buffer[256];
/* Initialization */
ipaddrlen = strlen(ipaddr);
switch((int)servertype)
{
case SA_SERVERTYPE_HTTP:
server = "HTTP";
denyid = SECURITY_HTTPDENY;
acceptid = SECURITY_HTTPACCEPT;
break;
case SA_SERVERTYPE_FTP:
server = "FTP";
denyid = SECURITY_FTPDENY;
acceptid = SECURITY_FTPACCEPT;
break;
case SA_SERVERTYPE_NNTP:
server = "NNTP";
denyid = SECURITY_NNTPDENY;
acceptid = SECURITY_NNTPACCEPT;
break;
case SA_SERVERTYPE_SMTPPROXY:
case SA_SERVERTYPE_POP3PROXY:
case SA_SERVERTYPE_IMAP4PROXY:
server = "PROXY";
denyid = SECURITY_PROXYDENY;
acceptid = SECURITY_PROXYACCEPT;
break;
default:
sprintf(buffer, "NETCONNECT: Unrecognized server (%d)", servertype);
sa_log(sactx, buffer);
return (SA_FAIL);
}
/*
** NETACCEPT
**
** The client must be in the accept list.
*/
found = 0;
security = Entries[acceptid];
while ((!found) && (security != (SECURITY *)NULL))
{
if (sa_wildcmp(sactx, security->name, security->namelen,
ipaddr, ipaddrlen) == 0)
{
found = 1;
continue;
}
security = security->next;
}
if (!found)
{
sprintf(buffer,
"NETCONNECT: Client %s not in accept list for server %s.",
ipaddr, server);
sa_log(sactx, buffer);
return (SA_FAIL);
}
/*
** NETDENY
**
** The client cannot be in the deny list.
*/
security = Entries[denyid];
while (security != (SECURITY *)NULL)
{
if (sa_wildcmp(sactx, security->name, security->namelen,
ipaddr, ipaddrlen) == 0)
{
sprintf(buffer,
"NETCONNECT: Client %s is in deny list for server %s.",
ipaddr, server);
sa_log(sactx, buffer);
return (SA_FAIL);
}
security = security->next;
}
return (SA_SUCCEED);
}
/*
** SECURITY_FILTER
**
** Filter all HTTP Proxy requests. If the requested URL is found
** in the [httpfilter] section, either return the file specified
** in the file in response to the request, or return a 404 request
** denied message if no file is specified.
**
** Parameters:
** sactx Sambar Server context
** ipaddr The IP address of the client requesting a connection.
** servertype The server the client is attempting to connect to.
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_filter(sactx, saconn, host, hostlen, url, urllen)
SA_CTX *sactx;
SA_CONN *saconn;
SA_CHAR *host;
SA_INT hostlen;
SA_CHAR *url;
SA_INT urllen;
{
SECURITY *security;
security = Entries[SECURITY_HOSTFILTER];
while (security != (SECURITY *)NULL)
{
if (sa_wildcmp(sactx, security->name, security->namelen,
host, hostlen) == 0)
{
ENTRY *entry;
SA_CHAR buffer[1024];
(SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
(SA_VOID)sa_conn_send(saconn, DENIED_BODY, SA_NULLTERM);
entry = security->entries;
if (hostlen + entry->valuelen < 1000)
{
sprintf(buffer, "HTTPPROXY: Host %s blocked by filter: %s",
host, entry->value);
(SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
sa_log(sactx, buffer);
}
(SA_VOID)sa_conn_send(saconn, DENIED_FOOTER, SA_NULLTERM);
return (SA_FAIL);
}
security = security->next;
}
security = Entries[SECURITY_URLFILTER];
while (security != (SECURITY *)NULL)
{
if (sa_wildcmp(sactx, security->name, security->namelen,
url, urllen) == 0)
{
ENTRY *entry;
SA_CHAR buffer[1024];
(SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
(SA_VOID)sa_conn_send(saconn, DENIED_BODY, SA_NULLTERM);
entry = security->entries;
if (urllen + entry->valuelen < 1000)
{
sprintf(buffer, "HTTPPROXY: URL %s blocked by filter: %s",
url, entry->value);
(SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
sa_log(sactx, buffer);
}
(SA_VOID)sa_conn_send(saconn, DENIED_FOOTER, SA_NULLTERM);
return (SA_FAIL);
}
security = security->next;
}
/* HTTP Request should be allowed through. */
return (SA_SUCCEED);
}
/*
** SECURITY__LOAD
**
** Load a single security rule.
**
** Parameters:
** sactx Sambar Server context
** argp Security parameter.
** name Left hand argument.
** value Right hand argument.
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE
security__load(sactx, argp, name, value)
SA_CTX *sactx;
SA_VOID *argp;
SA_CHAR *name;
SA_CHAR *value;
{
SA_INT valuelen;
ENTRY *entry;
SECURITY *security;
security = (SECURITY *)malloc(sizeof(SECURITY));
if (security == (SECURITY *)NULL)
return (SA_FAIL);
memset(security, 0, sizeof(SECURITY));
security->namelen = strlen(name);
valuelen = strlen(value);
if ((security->namelen == 0) || (valuelen == 0))
return (SA_FAIL);
security->name = strdup(name);
/* Restriction list have multiple entries */
if (*(SA_INT *)argp == SECURITY_RESTRICT)
{
SA_INT pos;
SA_INT head;
pos = 0;
while (pos < valuelen)
{
head = pos;
while ((pos < valuelen) && !isspace(value[pos]))
pos++;
value[pos] = '\0';
entry = (ENTRY *)malloc(sizeof(ENTRY));
if (entry == (ENTRY *)NULL)
return (SA_FAIL);
memset(entry, 0, sizeof(ENTRY));
entry->value = strdup(&value[head]);
entry->valuelen = pos - head;;
entry->next = security->entries;
security->entries = entry;
pos++;
while ((pos < valuelen) && isspace(value[pos]))
pos++;
}
}
else
{
entry = (ENTRY *)malloc(sizeof(ENTRY));
if (entry == (ENTRY *)NULL)
return (SA_FAIL);
memset(entry, 0, sizeof(ENTRY));
entry->valuelen = valuelen;
entry->value = strdup(value);
security->entries = entry;
}
security->next = Entries[*(SA_INT *)argp];
Entries[*(SA_INT *)argp] = security;
return (SA_SUCCEED);
}
/*
** SECURITY_SHOWSEC
**
** Show the security associated with a particular symbol.
**
** Parameters:
** sactx Sambar Server context
** saconn Sambar Server connection
** saparams RPC Parameters
** infop Error parameters
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE SA_PUBLIC
security_showsec(sactx, saconn, saparams, infop)
SA_CTX *sactx;
SA_CONN *saconn;
SA_PARAMS *saparams;
SA_INT *infop;
{
SA_INT i;
SA_BOOL found;
SA_INT datalen;
SA_CHAR *data;
ENTRY *entry;
SECURITY *security;
SA_CHAR buffer[1024];
/* Get the present sum */
if ((sa_param(sactx, saparams, "type", &data, &datalen) != SA_SUCCEED) ||
(datalen == 0))
{
/* No report type given */
return (SA_SUCCEED);
}
i = 0;
found = 0;
while ((i < NUM_ENTRIES) && (!found))
{
if (strcmp(Security_entries[i].symbol, (SA_CHAR *)data) == 0)
found = 1;
else
i++;
}
if (!found)
{
*infop = SA_E_INVALIDDATA;
return (SA_FAIL);
}
sprintf(buffer, "<FONT SIZE=+1><B>%s</B></FONT><P>\n",
Security_entries[i].descr);
if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
return (SA_FAIL);
security = Entries[i];
if (security == (SECURITY *)NULL)
{
if (sa_conn_send(saconn, "<I>No Security Controls defined.",
SA_NULLTERM) != SA_SUCCEED)
{
return (SA_FAIL);
}
return (SA_SUCCEED);
}
if (sa_conn_send(saconn, "<TABLE border=1 cellspacing=4>\n", SA_NULLTERM)
!= SA_SUCCEED)
{
return (SA_FAIL);
}
while (security != (SECURITY *)NULL)
{
sprintf(buffer, "<TR><TD>%s</TD><TD>", security->name);
if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
return (SA_FAIL);
entry = security->entries;
while (entry != (ENTRY *)NULL)
{
sprintf(buffer, "%s ", entry->value);
if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
return (SA_FAIL);
entry = entry->next;
}
if (sa_conn_send(saconn, "</TD></TR>\n", SA_NULLTERM) != SA_SUCCEED)
return (SA_FAIL);
security = security->next;
}
if (sa_conn_send(saconn, "</TABLE>\n", SA_NULLTERM) != SA_SUCCEED)
return (SA_FAIL);
return (SA_SUCCEED);
}
/*
** SECURITY__CASECMP
**
** Compare two case-insensitive strings.
**
** Parameters:
** str1 String to compare.
** str2 String to compare.
** len Length of the comparison.
**
** Returns:
** SA_INT
*/
static SA_INT
security__casecmp(str1, str2, len)
SA_CHAR *str1;
SA_CHAR *str2;
SA_INT len;
{
SA_INT i;
SA_INT diff;
if (len == 0)
return (0);
i = 0;
while (i < len)
{
if ((str1[i] == '\0') || (str2[i] == '\0'))
return (str1[i] - str2[i]);
diff = tolower(str1[i]) - tolower(str2[i]);
if (diff != 0)
return (diff);
i++;
}
return (0);
}