home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Komunik / sambar / sambar51p.exe / samples / source / security.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-01-26  |  27.5 KB  |  1,170 lines

  1. /*
  2. ** SECURITY
  3. **
  4. **      HTTP Wrapper for the Security Management Routines
  5. **
  6. **        Confidential Property of Tod Sambar
  7. **        (c) Copyright Tod Sambar 1996-1997
  8. **        All rights reserved.
  9. **
  10. **
  11. ** Public Functions:
  12. **
  13. **        security_init
  14. **        security_exit
  15. **        security_request
  16. **        security_connect
  17. **        security_filter
  18. **
  19. ** Note:
  20. **        By default, all objects placed in the sysadmin folder (under docs)
  21. **        are required to have system administrator access.  All other
  22. **        security features are implemented through external event handlers.
  23. **
  24. ** History:
  25. ** Chg#    Date    Description                                                Resp
  26. ** ----    -------    -------------------------------------------------------    ----
  27. **         4FEB97    Created                                                    sambar
  28. **         23APR97    Added network connect security                            sambar
  29. **         09APR97    Added AD/site security filtering                        sambar
  30. **         07JUL97    Added multiple users/groups on the security line        sambar
  31. **         13SEP98    Modified to send filtered.htm file on proxy denial         sambar
  32. **         31DEC98    Added Mail security filtering                            sambar
  33. */
  34.  
  35. #include    <stdio.h>
  36. #include    <stdlib.h>
  37. #include    <memory.h>
  38. #include    <string.h>
  39. #include    <ctype.h>
  40. #include    <security.h>
  41.  
  42. #ifndef    WIN32
  43. #define stricmp        strcasecmp
  44. #define strnicmp    strncasecmp
  45. extern int strcasecmp(const char *, const char *);
  46. extern int strncasecmp(const char *, const char *, int);
  47. extern char *strdup(const char *);
  48. #endif    /* WIN32 */
  49.  
  50. /*
  51. ** Local Functions
  52. */
  53. SA_RETCODE            security__load(SA_CTX *ctx, SA_VOID *argp, 
  54.                         SA_CHAR *name, SA_CHAR *value);
  55.  
  56. /*
  57. ** Show-security RPC parameters
  58. */
  59. static SA_RPCPARAM        showsecp [] =
  60. {
  61.     { "type",        1,    "Security filter to show." }
  62. };
  63.  
  64. /*
  65. ** Local Structures
  66. */
  67. typedef struct        security__entry
  68. {
  69.     SA_INT            id;
  70.     SA_CHAR            *symbol;
  71.     SA_CHAR            *descr;
  72.  
  73. } SECURITY_ENTRY;
  74.  
  75. /*
  76. ** Local Defines
  77. */
  78. #define DENIED_HEADER    "HTTP/1.0 404 Request denied.\nContent-type: text/html\n\n"
  79.  
  80. static SECURITY_ENTRY    Security_entries[] =
  81. {
  82.     { SECURITY_REDIRECT,        "redirect",
  83.       "URI to Redirect / URL to Redirect to"  },
  84.     { SECURITY_RESTRICT,        "restrict",
  85.       "URI to Restrict / User or Group granted access" },
  86.     { SECURITY_DENY,            "deny",
  87.       "IP to deny access to / URL to redirect offending hosts to" },
  88.     { SECURITY_HTTPACCEPT,        "httpaccept",
  89.       "IP addresses to accept HTTP hosts from" },
  90.     { SECURITY_HTTPDENY,        "httpdeny",
  91.       "IP addresses of hosts to deny HTTP access to" },
  92.     { SECURITY_FTPACCEPT,        "ftpaccept",
  93.       "IP addresses to accept FTP hosts from" },
  94.     { SECURITY_FTPDENY,            "ftpdeny",
  95.       "IP addresses of hosts to deny FTP access to" },
  96.     { SECURITY_PROXYACCEPT,        "proxyaccept",
  97.       "IP addresses to accept Proxy hosts from" },
  98.     { SECURITY_PROXYDENY,        "proxydeny",
  99.       "IP addresses of hosts to deny Proxy access to" },
  100.     { SECURITY_HOSTFILTER,        "hostfilter",
  101.       "Hosts to restrict proxy requests from (AD/Content filtering)" },
  102.     { SECURITY_URLFILTER,        "urlfilter",
  103.       "URLs to restrict proxy requests from (AD/Content filtering)" },
  104.     { SECURITY_IPRESTRICT,        "iprestrict",
  105.       "URI to Restrict / IP Address(s) to grant access" },
  106.     { SECURITY_HOSTRESTRICT,    "hostrestrict",
  107.       "Hosts to restrict proxy requests to (WWW kiosks)" },
  108.     { SECURITY_URLRESTRICT,        "urlrestrict",
  109.       "URLs to restrict proxy requests to (WWW kiosks)" },
  110.     { SECURITY_MAILACCEPT,        "mailaccept",
  111.       "IP addresses to accept Mail (SMTP/POP3/IMAP4) hosts from" },
  112.     { SECURITY_MAILDENY,        "maildeny",
  113.       "IP addresses of hosts to deny Mail (SMTP/POP3/IMAP4) access to" },
  114.     { SECURITY_DNSACCEPT,        "dnsaccept",
  115.       "IP addresses to accept DNS requests from" },
  116.     { SECURITY_DNSDENY,            "dnsdeny",
  117.       "IP addresses of hosts to deny DNS access to" },
  118.     { SECURITY_SIPACCEPT,        "sipaccept",
  119.       "IP addresses to accept SIP requests from" },
  120.     { SECURITY_SIPDENY,            "sipdeny",
  121.       "IP addresses of hosts to deny SIP access to" },
  122.     { SECURITY_HOSTREDIRECT,    "hostredirect",
  123.       "Hosts to redirect requests to (vhost management)" },
  124.     { SECURITY_TFTPACCEPT,        "tftpaccept",
  125.       "IP addresses to accept TFTP requests from" },
  126.     { SECURITY_TFTPDENY,        "tftpdeny",
  127.       "IP addresses of hosts to deny TFTP access to" },
  128. };
  129.  
  130. #define NUM_ENTRIES     sizeof(Security_entries) / sizeof(SECURITY_ENTRY)
  131. static SECURITY            *Entries[NUM_ENTRIES];
  132. static SECURITY            *TmpEntries[NUM_ENTRIES];
  133.  
  134.  
  135.  
  136. /*
  137. **  SECURITY_INIT
  138. **
  139. **    Initialize the Security Rules for use by the Sambar Server plugins.
  140. **    Rules are only loaded at application initialization time and (as this
  141. **    is a threaded application) cannot be modified without a restart of 
  142. **    the server (or mutexing).
  143. **
  144. **
  145. **  Parameters:
  146. **    sactx        Sambar Server context
  147. **
  148. **  Returns:
  149. **    SA_SUCCEED | SA_FAIL
  150. */
  151. SA_RETCODE SA_PUBLIC
  152. security_init(sactx)
  153. SA_CTX        *sactx;
  154. {
  155.     SA_INT        i;
  156.     SA_CHAR        buffer[256];
  157.  
  158.     /* 
  159.     ** Load the security rules from the security.ini file
  160.     */
  161.     for (i = 0; i < NUM_ENTRIES; i++)
  162.     {
  163.         TmpEntries[i] = (SECURITY *)NULL;
  164.  
  165.         if (sa_props_load(sactx, "security.ini", 
  166.             Security_entries[i].symbol, &Security_entries[i].id, 
  167.             (SA_PROPFUNC)security__load) != SA_SUCCEED)
  168.         {
  169.             sprintf(buffer, "Failure loading [%s] security section.", 
  170.                 Security_entries[i].symbol);
  171.             sa_log2(sactx, SA_LOG_ERROR, buffer);
  172.         }
  173.  
  174.         Entries[i] = TmpEntries[i];
  175.     }
  176.  
  177.     /* Initialize the "showsec" RPC                                        */
  178.     if (sa_cmd_init(sactx, "showsec", 
  179.         showsecp, sizeof(showsecp) / sizeof(SA_RPCPARAM),
  180.         SA_AUTHORIZATION_ADMIN, "Security rule display.", 
  181.         (SA_VOID *)security_showsec) != SA_SUCCEED)
  182.     {
  183.         sa_log2(sactx, SA_LOG_ERROR, "Unable to initialize Security RPCs");
  184.         return (SA_FAIL);
  185.     }
  186.  
  187.     if (sa_cmd_init(sactx, "reloadsec", (SA_RPCPARAM *)NULL, 0,
  188.         SA_AUTHORIZATION_ADMIN, "Reload security rules.", 
  189.         (SA_VOID *)security_reload) != SA_SUCCEED)
  190.     {
  191.         sa_log2(sactx, SA_LOG_ERROR, "Unable to initialize Security RPCs");
  192.         return (SA_FAIL);
  193.     }
  194.  
  195.     sa_log2(sactx, SA_LOG_TRACE, "Security Interfaces Initialized");
  196.  
  197.     return (SA_SUCCEED);
  198. }
  199.  
  200. /*
  201. **  SECURITY_EXIT
  202. **
  203. **    Free the Security Rules.
  204. **
  205. **  Parameters:
  206. **    sactx        Sambar Server context
  207. **
  208. **  Returns:
  209. **    SA_SUCCEED | SA_FAIL
  210. */
  211. SA_RETCODE SA_PUBLIC
  212. security_exit(sactx)
  213. SA_CTX        *sactx;
  214. {
  215.     SA_INT        i;
  216.     SECURITY    *snext;
  217.     SECURITY    *security;
  218.     ENTRY        *enext;
  219.     ENTRY        *entry;
  220.  
  221.     /* 
  222.     ** Free the security rules previously loaded from the security.ini file
  223.     */
  224.     for (i = 0; i < NUM_ENTRIES; i++)
  225.     {
  226.         security = Entries[i];
  227.         while (security != (SECURITY *)NULL)
  228.         {
  229.             snext = security->next;
  230.             free(security->name);
  231.  
  232.             entry = security->entries;
  233.             while (entry != (ENTRY *)NULL)
  234.             {
  235.                 enext = entry->next;
  236.                 free(entry->value);
  237.                 free(entry);
  238.                 entry = enext;
  239.             }
  240.  
  241.             free(security);
  242.             security = snext;
  243.         }
  244.     }
  245.  
  246.     sa_log2(sactx, SA_LOG_TRACE, "Security Interfaces Exited");
  247.  
  248.     return (SA_SUCCEED);
  249. }
  250.  
  251. /*
  252. **  SECURITY_REQUEST
  253. **
  254. **    Determine if the request should be fulfilled.
  255. **
  256. **  Parameters:
  257. **    sactx        Sambar Server context
  258. **    saconn        Client connection handle.
  259. **    uri            The URI associated with the request.
  260. **    urilen        The length of the URI string.
  261. **    params        The parameters associated with the request.
  262. **    infop        The error status returned on failure.
  263. **
  264. **  Returns:
  265. **    SA_SUCCEED | SA_FAIL
  266. */
  267. SA_RETCODE SA_PUBLIC
  268. security_request(sactx, saconn, uri, urilen, params, infop)
  269. SA_CTX        *sactx;
  270. SA_CONN        *saconn;
  271. SA_CHAR        *uri;
  272. SA_INT        urilen;
  273. SA_PARAMS    *params;
  274. SA_INT        *infop;
  275. {
  276.     SA_BOOL        ntauth;
  277.     SA_BOOL        sqlauth;
  278.     SA_BOOL        radiusauth;
  279.     SA_BOOL        found;
  280.     SA_BOOL        status;
  281.     ENTRY        *entry;
  282.     SECURITY    *security;
  283.     SA_INT        namelen;
  284.     SA_CHAR        name[60];
  285.     SA_INT        pwdlen;
  286.     SA_CHAR        pwd[60];
  287.     SA_CHAR        tmp[32];
  288.     SA_PASSWD    passwd;
  289.  
  290.     ntauth = 0;
  291.     if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_NTAUTH, tmp, 30, 
  292.         (SA_INT *)NULL) == SA_SUCCEED)
  293.     {
  294.         if (stricmp(tmp, "true") == 0)
  295.             ntauth = 1;
  296.     }
  297.  
  298.     radiusauth = 0;
  299.     if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_RADIUSAUTH, tmp, 30, 
  300.         (SA_INT *)NULL) == SA_SUCCEED)
  301.     {
  302.         if (stricmp(tmp, "true") == 0)
  303.             radiusauth = 1;
  304.     }
  305.  
  306.     sqlauth = 0;
  307.     if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_SQLAUTH, tmp, 30, 
  308.         (SA_INT *)NULL) == SA_SUCCEED)
  309.     {
  310.         if (stricmp(tmp, "true") == 0)
  311.             sqlauth = 1;
  312.     }
  313.  
  314.     /* 
  315.     ** REDIRECT
  316.     */
  317.     security = Entries[SECURITY_REDIRECT];
  318.     while (security != (SECURITY *)NULL)
  319.     {
  320.         if ((urilen >= security->namelen) && 
  321.             (strnicmp(uri, security->name, security->namelen) == 0))
  322.         {
  323.             *infop = SA_E_REDIRECT;
  324.             entry = security->entries;
  325.             (SA_VOID)sa_conn_redirect(saconn, entry->value, 
  326.                 "Request redirected.", SA_NULLTERM);
  327.             return (SA_FAIL);
  328.         }
  329.  
  330.         security = security->next;
  331.     }
  332.  
  333.     /*
  334.     ** RESTRICT
  335.     */
  336.     security = Entries[SECURITY_RESTRICT];
  337.     while (security != (SECURITY *)NULL)
  338.     {
  339.         if ((urilen >= security->namelen) && 
  340.             (strnicmp(uri, security->name, security->namelen) == 0))
  341.         {
  342.             if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_NAME, name, 60,
  343.                 &namelen) != SA_SUCCEED)
  344.             {
  345.                 *infop = SA_E_INVALIDLOGIN;
  346.                 return (SA_FAIL);
  347.             }
  348.  
  349.             /* Get the password and verify the match                    */
  350.             if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_PASSWORD, pwd, 60,
  351.                 &pwdlen) != SA_SUCCEED)
  352.             {
  353.                 *infop = SA_E_INVALIDLOGIN;
  354.                 return (SA_FAIL);
  355.             }
  356.  
  357.             /* 
  358.             ** Now lookup the name/password in the passwd file or
  359.             ** NT Domain or Radius Server (depending on configuration).
  360.             */
  361.             if ((ntauth) || (radiusauth))
  362.             {
  363.                 if (sa_passwd_verify(sactx, name, namelen, pwd, pwdlen, &status)
  364.                     != SA_SUCCEED)
  365.                 {
  366.                     *infop = SA_E_INVALIDLOGIN;
  367.                     return (SA_FAIL);
  368.                 }
  369.  
  370.                 if (!status)
  371.                 {
  372.                     *infop = SA_E_INVALIDLOGIN;
  373.                     return (SA_FAIL);
  374.                 }
  375.             }
  376.             else if (sqlauth)
  377.             {
  378.                 if (sa_passwd_sqlauth(sactx, saconn, name, namelen, pwd, pwdlen,
  379.                     &passwd) != SA_SUCCEED)
  380.                 {
  381.                     *infop = SA_E_INVALIDLOGIN;
  382.                     return (SA_FAIL);
  383.                 }
  384.             }
  385.             else
  386.             {
  387.                 if (sa_passwd_lookup(sactx, name, namelen, &passwd) 
  388.                     != SA_SUCCEED)
  389.                 {
  390.                     *infop = SA_E_INVALIDLOGIN;
  391.                     return (SA_FAIL);
  392.                 }
  393.  
  394.                 if (pwdlen != passwd.passwordlen)
  395.                 {
  396.                     *infop = SA_E_INVALIDLOGIN;
  397.                     return (SA_FAIL);
  398.                 }
  399.  
  400.                 if ((pwdlen > 0) && 
  401.                     (memcmp(passwd.password, pwd, pwdlen) != 0))
  402.                 {
  403.                     *infop = SA_E_INVALIDLOGIN;
  404.                     return (SA_FAIL);
  405.                 }
  406.             }
  407.  
  408.             /* 
  409.             ** Lastly, verify the security entry(s) match either the name
  410.             ** or group name of the user.
  411.             */
  412.             found = 0;
  413.             entry = security->entries;
  414.             while ((!found) && (entry != (ENTRY *)NULL))
  415.             {
  416.                 /* Match with the username?                                */
  417.                 if ((namelen == entry->valuelen) &&
  418.                      (memcmp(entry->value, name, namelen) == 0))
  419.                 {
  420.                     found = 1;
  421.                     continue;
  422.                 }
  423.  
  424.                 /* Match with the user group?                            */
  425.                 if ((!ntauth) && (!radiusauth) && 
  426.                     (passwd.grouplen == entry->valuelen) &&
  427.                     (memcmp(entry->value, passwd.group, passwd.grouplen) == 0))
  428.                 {
  429.                     found = 1;
  430.                     continue;
  431.                 }
  432.  
  433.                 entry = entry->next;
  434.             }
  435.  
  436.             if (!found)
  437.             {
  438.                 *infop = SA_E_INVALIDLOGIN;
  439.                 return (SA_FAIL);
  440.             }
  441.  
  442.             /*
  443.             ** Finally, if a full "user" should be created (with server-side
  444.             ** state), do so here.
  445.             */
  446.             if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_AUTHLOGINS, tmp, 30,
  447.                 (SA_INT *)NULL) == SA_SUCCEED)
  448.             {
  449.                 if ((strcmp(tmp, "true") == 0) &&
  450.                     (sa_conn_login(saconn, name, namelen, pwd, pwdlen, infop)
  451.                     != SA_SUCCEED))
  452.                 {
  453.                     return (SA_FAIL);
  454.                 }
  455.             }
  456.         }
  457.  
  458.         security = security->next;
  459.     }
  460.     
  461.     /*
  462.     ** DENY
  463.     */
  464.     if ((Entries[SECURITY_DENY] != (SECURITY *)NULL) &&
  465.         (sa_conn_props(saconn, SA_GET, SA_CONNPROP_HOST, name, 60,
  466.         &namelen) == SA_SUCCEED))
  467.     {
  468.         security = Entries[SECURITY_DENY];
  469.         while (security != (SECURITY *)NULL)
  470.         {
  471.             if (sa_wildcmp(sactx, security->name, security->namelen, 
  472.                 name, strlen(name)) == 0)
  473.             {
  474.                 entry = security->entries;
  475.                 *infop = SA_E_REDIRECT;
  476.                 (SA_VOID)sa_conn_redirect(saconn, entry->value, 
  477.                     "Request redirected.", SA_NULLTERM);
  478.                 return (SA_FAIL);
  479.             }
  480.  
  481.             security = security->next;
  482.         }
  483.     }
  484.  
  485.     /*
  486.     ** IP-RESTRICT
  487.     */
  488.     security = Entries[SECURITY_IPRESTRICT];
  489.     while (security != (SECURITY *)NULL)
  490.     {
  491.         if ((urilen >= security->namelen) && 
  492.             (strnicmp(uri, security->name, security->namelen) == 0))
  493.         {
  494.             /* Get the IP address of the client.                        */
  495.             if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_IPADDR, name, 60,
  496.                 &namelen) != SA_SUCCEED)
  497.             {
  498.                 return (SA_FAIL);
  499.             }
  500.  
  501.             /* 
  502.             ** Lastly, verify the security entry(s) match the IP
  503.             ** address of the client.
  504.             */
  505.             found = 0;
  506.             entry = security->entries;
  507.             while ((!found) && (entry != (ENTRY *)NULL))
  508.             {
  509.                 if (sa_wildcmp(sactx, entry->value, entry->valuelen, 
  510.                     name, namelen) == 0)
  511.                 {
  512.                     found = 1;
  513.                     continue;
  514.                 }
  515.  
  516.                 entry = entry->next;
  517.             }
  518.  
  519.             if (!found)
  520.             {
  521.                 *infop = SA_E_FORBIDDEN;
  522.                 return (SA_FAIL);
  523.             }
  524.         }
  525.  
  526.         security = security->next;
  527.     }
  528.     
  529.     /* 
  530.     ** HOSTREDIRECT
  531.     */
  532.     security = Entries[SECURITY_HOSTREDIRECT];
  533.     if ((security != (SECURITY *)NULL) &&
  534.         (sa_conn_props(saconn, SA_GET, SA_CONNPROP_REQUESTHOST, name, 60,
  535.         &namelen) == SA_SUCCEED))
  536.     {
  537.         while (security != (SECURITY *)NULL)
  538.         {
  539.             if (sa_wildcmp(sactx, security->name, security->namelen, 
  540.                 name, namelen) == 0)
  541.             {
  542.                 entry = security->entries;
  543.                 *infop = SA_E_REDIRECT;
  544.                 (SA_VOID)sa_conn_redirect(saconn, entry->value, 
  545.                     "Request redirected.", SA_NULLTERM);
  546.                 return (SA_FAIL);
  547.             }
  548.  
  549.             security = security->next;
  550.         }
  551.     }
  552.  
  553.     return (SA_SUCCEED);
  554. }
  555.  
  556. /*
  557. **  SECURITY_CONNECT
  558. **
  559. **    Determine if the connection should be allowed.
  560. **
  561. **  Parameters:
  562. **    sactx        Sambar Server context
  563. **    ipaddr        The IP address of the client requesting a connection.
  564. **    servertype    The server the client is attempting to connect to.
  565. **
  566. **  Returns:
  567. **    SA_SUCCEED | SA_FAIL
  568. */
  569. SA_RETCODE SA_PUBLIC
  570. security_connect(sactx, ipaddr, servertype)
  571. SA_CTX        *sactx;
  572. SA_CHAR        *ipaddr;
  573. SA_INT        servertype;
  574. {
  575.     SA_INT        denyid;
  576.     SA_INT        acceptid;
  577.     SA_INT        ipaddrlen;
  578.     SA_BOOL        found;
  579.     SA_CHAR        *server;
  580.     SECURITY    *security;
  581.     SA_CHAR        buffer[256];
  582.  
  583.     /* Initialization                                                    */
  584.     ipaddrlen = strlen(ipaddr);
  585.  
  586.     switch((int)servertype)
  587.     {
  588.     case SA_SERVERTYPE_HTTP:
  589.         server = "HTTP";
  590.         denyid = SECURITY_HTTPDENY;
  591.         acceptid = SECURITY_HTTPACCEPT;
  592.         break;
  593.  
  594.     case SA_SERVERTYPE_FTP:
  595.         server = "FTP";
  596.         denyid = SECURITY_FTPDENY;
  597.         acceptid = SECURITY_FTPACCEPT;
  598.         break;
  599.  
  600.     case SA_SERVERTYPE_HTTPPROXY:
  601.     case SA_SERVERTYPE_SMTPPROXY:
  602.     case SA_SERVERTYPE_POP3PROXY:
  603.     case SA_SERVERTYPE_IMAP4PROXY:
  604.     case SA_SERVERTYPE_BRIDGEPROXY:
  605.     case SA_SERVERTYPE_NNTPPROXY:
  606.     case SA_SERVERTYPE_FTPPROXY:
  607.     case SA_SERVERTYPE_SOCKSPROXY:
  608.     case SA_SERVERTYPE_TELNETPROXY:
  609.     case SA_SERVERTYPE_REALPROXY:
  610.     case SA_SERVERTYPE_TCPPROXY:
  611.     case SA_SERVERTYPE_UDPPROXY:
  612.         server = "PROXY";
  613.         denyid = SECURITY_PROXYDENY;
  614.         acceptid = SECURITY_PROXYACCEPT;
  615.         break;
  616.  
  617.     case SA_SERVERTYPE_SMTP:
  618.     case SA_SERVERTYPE_POP3:
  619.     case SA_SERVERTYPE_IMAP4:
  620.         server = "Mail";
  621.         denyid = SECURITY_MAILDENY;
  622.         acceptid = SECURITY_MAILACCEPT;
  623.         break;
  624.  
  625.     case SA_SERVERTYPE_DNS:
  626.         server = "DNS";
  627.         denyid = SECURITY_DNSDENY;
  628.         acceptid = SECURITY_DNSACCEPT;
  629.         break;
  630.  
  631.     case SA_SERVERTYPE_SIP:
  632.         server = "SIP";
  633.         denyid = SECURITY_SIPDENY;
  634.         acceptid = SECURITY_SIPACCEPT;
  635.         break;
  636.  
  637.     case SA_SERVERTYPE_TFTP:
  638.         server = "TFTP";
  639.         denyid = SECURITY_TFTPDENY;
  640.         acceptid = SECURITY_TFTPACCEPT;
  641.         break;
  642.  
  643.     default:
  644.         sprintf(buffer, "NETCONNECT: Unrecognized server (%ld)", servertype);
  645.         sa_log2(sactx, SA_LOG_ERROR, buffer);
  646.         return (SA_FAIL);
  647.     }
  648.  
  649.     /* 
  650.     ** NETACCEPT
  651.     **
  652.     ** The client must be in the accept list.
  653.     */
  654.     found = 0;
  655.     security = Entries[acceptid];
  656.     while ((!found) && (security != (SECURITY *)NULL))
  657.     {
  658.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  659.             ipaddr, ipaddrlen) == 0)
  660.         {
  661.             found = 1;
  662.             continue;
  663.         }
  664.  
  665.         security = security->next;
  666.     }
  667.  
  668.     if (!found)
  669.     {
  670.         sprintf(buffer, 
  671.             "NETCONNECT: Client %s not in accept list for server %s.",
  672.             ipaddr, server);
  673.         sa_log2(sactx, SA_LOG_WARN, buffer);
  674.         return (SA_FAIL);
  675.     }
  676.  
  677.     /* 
  678.     ** NETDENY
  679.     **
  680.     ** The client cannot be in the deny list.
  681.     */
  682.     security = Entries[denyid];
  683.     while (security != (SECURITY *)NULL)
  684.     {
  685.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  686.             ipaddr, ipaddrlen) == 0)
  687.         {
  688.             sprintf(buffer, 
  689.                 "NETCONNECT: Client %s is in deny list for server %s.", 
  690.                 ipaddr, server);
  691.             sa_log2(sactx, SA_LOG_WARN, buffer);
  692.             return (SA_FAIL);
  693.         }
  694.  
  695.         security = security->next;
  696.     }
  697.  
  698.     return (SA_SUCCEED);
  699. }
  700.  
  701. /*
  702. **  SECURITY_FILTER
  703. **
  704. **    Filter all HTTP Proxy requests.
  705. **
  706. **  If the requested URL is found in the [httpfilter] section, either 
  707. **    return the file specified in the file in response to the request, 
  708. **    or return a 404 request denied message if no file is specified.
  709. **
  710. **  If the requested URL is NOT found in the [httprestrict] section, 
  711. **    return a 404 request denied message.
  712. **
  713. **  If the requested URL is found in the [urlfilter] section, 
  714. **    return a 404 request denied message.
  715. **
  716. **
  717. **  Parameters:
  718. **    sactx        Sambar Server context
  719. **
  720. **  Returns:
  721. **    SA_SUCCEED | SA_FAIL
  722. */
  723. SA_RETCODE SA_PUBLIC
  724. security_filter(sactx, saconn, host, hostlen, url, urllen)
  725. SA_CTX        *sactx;
  726. SA_CONN        *saconn;
  727. SA_CHAR        *host;
  728. SA_INT        hostlen;
  729. SA_CHAR        *url;
  730. SA_INT        urllen;
  731. {
  732.     SA_INT        i;
  733.     SA_INT        len;
  734.     SA_INT        urlcaselen;
  735.     SA_BOOL        found;
  736.     ENTRY        *entry;
  737.     SECURITY    *security;
  738.     SA_CHAR        urlcase[1024];
  739.     SA_CHAR        buffer[2048];
  740.  
  741.     /*
  742.     ** Convert the host and URL to lower case.
  743.     */
  744.     for (i = 0; i < hostlen; i++)
  745.         host[i] = tolower(host[i]);
  746.  
  747.     urlcaselen = 0;
  748.     while ((urlcaselen < urllen) && (urlcaselen < 1000))
  749.     {
  750.         urlcase[urlcaselen] = tolower(url[urlcaselen]);
  751.         urlcaselen++;
  752.     }
  753.  
  754.     urlcase[urlcaselen] = '\0';
  755.  
  756.     security = Entries[SECURITY_HOSTFILTER];
  757.     while (security != (SECURITY *)NULL)
  758.     {
  759.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  760.             host, hostlen) == 0)
  761.         {
  762.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  763.             if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_HOMEDIR, buffer,
  764.                 1000, &len) == SA_SUCCEED)
  765.             {
  766.                 strcat(buffer, "\\messages\\filtered.htm");
  767.                 (SA_VOID)sa_send_file(saconn, buffer);
  768.             }
  769.  
  770.             entry = security->entries;
  771.             if (hostlen + entry->valuelen < 1000)
  772.             {
  773.                 sprintf(buffer, 
  774.                     "<!-- HTTPPROXY: Host %s blocked by filter: %s -->", 
  775.                     host, entry->value);
  776.                 (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  777.  
  778.                 sprintf(buffer, "HTTPPROXY: Host %s blocked by filter: %s", 
  779.                     host, entry->value);
  780.                 sa_log2(sactx, SA_LOG_WARN, buffer);
  781.             }
  782.  
  783.             return (SA_FAIL);
  784.         }
  785.  
  786.         security = security->next;
  787.     }
  788.  
  789.     security = Entries[SECURITY_URLFILTER];
  790.     while (security != (SECURITY *)NULL)
  791.     {
  792.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  793.             urlcase, urlcaselen) == 0)
  794.         {
  795.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  796.             if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_HOMEDIR, buffer,
  797.                 1000, &len) == SA_SUCCEED)
  798.             {
  799.                 strcat(buffer, "\\messages\\filtered.htm");
  800.                 (SA_VOID)sa_send_file(saconn, buffer);
  801.             }
  802.  
  803.             entry = security->entries;
  804.             if (urlcaselen + entry->valuelen < 1000)
  805.             {
  806.                 sprintf(buffer, 
  807.                     "<!-- HTTPPROXY: URL %s blocked by filter: %s -->", 
  808.                     urlcase, entry->value);
  809.                 (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  810.  
  811.                 sprintf(buffer, "HTTPPROXY: URL %s blocked by filter: %s", 
  812.                     urlcase, entry->value);
  813.                 sa_log2(sactx, SA_LOG_WARN, buffer);
  814.             }
  815.  
  816.             return (SA_FAIL);
  817.         }
  818.  
  819.         security = security->next;
  820.     }
  821.  
  822.     /* 
  823.     ** If a [hostrestrict] entry is found, the host must match 
  824.     ** an entry on the list provided or it will be denied.
  825.     */
  826.     security = Entries[SECURITY_HOSTRESTRICT];
  827.     if (security != (SECURITY *)NULL)
  828.     {
  829.         found = 0;
  830.         while ((!found) && (security != (SECURITY *)NULL))
  831.         {
  832.             if (sa_wildcmp(sactx, security->name, security->namelen, 
  833.                 host, hostlen) == 0)
  834.             {
  835.                 found = 1;
  836.                 continue;
  837.             }
  838.  
  839.             security = security->next;
  840.         }
  841.  
  842.         if (!found)
  843.         {
  844.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  845.             if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_HOMEDIR, buffer,
  846.                 1000, &len) == SA_SUCCEED)
  847.             {
  848.                 strcat(buffer, "\\messages\\filtered.htm");
  849.                 (SA_VOID)sa_send_file(saconn, buffer);
  850.             }
  851.  
  852.             sprintf(buffer, 
  853.                     "<!-- HTTPPROXY: Host '%s' not on [hostrestrict] list -->", 
  854.                     host);
  855.             (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  856.  
  857.             sprintf(buffer, "HTTPPROXY: Host '%s' not on [hostrestrict] list", 
  858.                     host);
  859.             sa_log2(sactx, SA_LOG_WARN, buffer);
  860.             return (SA_FAIL);
  861.         }
  862.     }
  863.  
  864.     /* 
  865.     ** If a [urlrestrict] entry is found, the URL must match 
  866.     ** an entry on the list provided or it will be denied.
  867.     */
  868.     security = Entries[SECURITY_URLRESTRICT];
  869.     if (security != (SECURITY *)NULL)
  870.     {
  871.         found = 0;
  872.         while ((!found) && (security != (SECURITY *)NULL))
  873.         {
  874.             if (sa_wildcmp(sactx, security->name, security->namelen, 
  875.                 urlcase, urlcaselen) == 0)
  876.             {
  877.                 found = 1;
  878.                 continue;
  879.             }
  880.  
  881.             security = security->next;
  882.         }
  883.  
  884.         if (!found)
  885.         {
  886.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  887.             if (sa_ctx_props(sactx, SA_GET, SA_CTXPROP_HOMEDIR, buffer,
  888.                 1000, &len) == SA_SUCCEED)
  889.             {
  890.                 strcat(buffer, "\\messages\\filtered.htm");
  891.                 (SA_VOID)sa_send_file(saconn, buffer);
  892.             }
  893.  
  894.             sprintf(buffer, 
  895.                 "<!-- HTTPPROXY: URL '%s' not on [urlrestrict] list -->", 
  896.                 urlcase);
  897.             (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  898.  
  899.             sprintf(buffer, "HTTPPROXY: URL '%s' not on [urlrestrict] list", 
  900.                 urlcase);
  901.             sa_log2(sactx, SA_LOG_WARN, buffer);
  902.             return (SA_FAIL);
  903.         }
  904.     }
  905.  
  906.     /* HTTP Request should be allowed through.                            */
  907.     return (SA_SUCCEED);
  908. }
  909.  
  910. /*
  911. **  SECURITY__LOAD
  912. **
  913. **    Load a single security rule.
  914. **
  915. **  Parameters:
  916. **    sactx        Sambar Server context
  917. **    argp        Security parameter.
  918. **    name        Left hand argument.
  919. **    value        Right hand argument.
  920. **
  921. **  Returns:
  922. **    SA_SUCCEED | SA_FAIL
  923. */
  924. SA_RETCODE
  925. security__load(sactx, argp, name, value)
  926. SA_CTX        *sactx;
  927. SA_VOID        *argp;
  928. SA_CHAR        *name;
  929. SA_CHAR        *value;
  930. {
  931.     SA_INT        pos;
  932.     SA_INT        head;
  933.     SA_INT        valuelen;
  934.     ENTRY        *entry;
  935.     SECURITY    *security;
  936.  
  937.     security = (SECURITY *)malloc(sizeof(SECURITY));
  938.     if (security == (SECURITY *)NULL)
  939.         return (SA_FAIL);
  940.  
  941.     memset(security, 0, sizeof(SECURITY));
  942.     security->namelen = strlen(name);
  943.     valuelen = strlen(value);
  944.  
  945.     if (security->namelen == 0) 
  946.         return (SA_FAIL);
  947.  
  948.     /* Is a value required?                                                */
  949.     if ((valuelen == 0) &&
  950.         (*(SA_INT *)argp != SECURITY_DENY) &&
  951.         (*(SA_INT *)argp != SECURITY_HTTPACCEPT) &&
  952.         (*(SA_INT *)argp != SECURITY_HTTPDENY) &&
  953.         (*(SA_INT *)argp != SECURITY_FTPACCEPT) &&
  954.         (*(SA_INT *)argp != SECURITY_FTPDENY) &&
  955.         (*(SA_INT *)argp != SECURITY_MAILACCEPT) &&
  956.         (*(SA_INT *)argp != SECURITY_MAILDENY) &&
  957.         (*(SA_INT *)argp != SECURITY_DNSACCEPT) &&
  958.         (*(SA_INT *)argp != SECURITY_DNSDENY) &&
  959.         (*(SA_INT *)argp != SECURITY_SIPACCEPT) &&
  960.         (*(SA_INT *)argp != SECURITY_SIPDENY) &&
  961.         (*(SA_INT *)argp != SECURITY_TFTPACCEPT) &&
  962.         (*(SA_INT *)argp != SECURITY_TFTPDENY) &&
  963.         (*(SA_INT *)argp != SECURITY_HOSTFILTER) &&
  964.         (*(SA_INT *)argp != SECURITY_IPRESTRICT) &&
  965.         (*(SA_INT *)argp != SECURITY_URLRESTRICT) &&
  966.         (*(SA_INT *)argp != SECURITY_URLFILTER))
  967.     {
  968.         return (SA_FAIL);
  969.     }
  970.  
  971.     security->name = strdup(name);
  972.  
  973.     /* Restriction & IP-restriction lists have multiple entries            */
  974.     if ((*(SA_INT *)argp == SECURITY_RESTRICT) ||
  975.         (*(SA_INT *)argp == SECURITY_IPRESTRICT))
  976.     {
  977.         pos = 0;
  978.         while (pos < valuelen)
  979.         {
  980.             head = pos;
  981.             while ((pos < valuelen) && !isspace(value[pos]))
  982.                 pos++;
  983.  
  984.             value[pos] = '\0';
  985.  
  986.             entry = (ENTRY *)malloc(sizeof(ENTRY));
  987.             if (entry == (ENTRY *)NULL)
  988.                 return (SA_FAIL);
  989.  
  990.             memset(entry, 0, sizeof(ENTRY));
  991.             entry->value = strdup(&value[head]);
  992.             entry->valuelen = pos - head;;
  993.             entry->next = security->entries;
  994.             security->entries = entry;
  995.  
  996.             pos++;
  997.             while ((pos < valuelen) && isspace(value[pos]))
  998.                 pos++;
  999.         }
  1000.     }
  1001.     else
  1002.     {
  1003.         entry = (ENTRY *)malloc(sizeof(ENTRY));
  1004.         if (entry == (ENTRY *)NULL)
  1005.             return (SA_FAIL);
  1006.  
  1007.         memset(entry, 0, sizeof(ENTRY));
  1008.         entry->valuelen = valuelen;
  1009.         entry->value = strdup(value);
  1010.         security->entries = entry;
  1011.     }
  1012.  
  1013.     security->next = TmpEntries[*(SA_INT *)argp];
  1014.     TmpEntries[*(SA_INT *)argp] = security;
  1015.  
  1016.     return (SA_SUCCEED);
  1017. }
  1018.  
  1019. /*
  1020. **  SECURITY_SHOWSEC
  1021. **
  1022. **    Show the security associated with a particular symbol.
  1023. **
  1024. **  Parameters:
  1025. **    sactx        Sambar Server context
  1026. **    saconn        Sambar Server connection
  1027. **    saparams    RPC Parameters
  1028. **    infop        Error parameters
  1029. **
  1030. **  Returns:
  1031. **    SA_SUCCEED | SA_FAIL
  1032. */
  1033. SA_RETCODE SA_PUBLIC
  1034. security_showsec(sactx, saconn, saparams, infop)
  1035. SA_CTX        *sactx;
  1036. SA_CONN        *saconn;
  1037. SA_PARAMS    *saparams;
  1038. SA_INT        *infop;
  1039. {
  1040.     SA_INT        i;
  1041.     SA_BOOL        found;
  1042.     SA_INT        datalen;
  1043.     SA_CHAR        *data;
  1044.     ENTRY        *entry;
  1045.     SECURITY    *security;
  1046.     SA_CHAR        buffer[1024];
  1047.  
  1048.     if ((sa_param(sactx, saparams, "type", &data, &datalen) != SA_SUCCEED) 
  1049.         || (datalen == 0) || (datalen > 64))
  1050.     {
  1051.         /* No report type given                                            */
  1052.         return (SA_SUCCEED);
  1053.     }
  1054.  
  1055.     i = 0;
  1056.     found = 0;
  1057.     while ((i < NUM_ENTRIES) && (!found))
  1058.     {
  1059.         if (strcmp(Security_entries[i].symbol, (SA_CHAR *)data) == 0)
  1060.             found = 1;
  1061.         else
  1062.             i++;
  1063.     }
  1064.  
  1065.     if (!found)
  1066.     {
  1067.         *infop = SA_E_INVALIDDATA;
  1068.         return (SA_FAIL);
  1069.     }
  1070.  
  1071.     sprintf(buffer, "<FONT SIZE=+1><B>%s</B></FONT><P>\n", 
  1072.         Security_entries[i].descr);
  1073.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  1074.         return (SA_FAIL);
  1075.  
  1076.     security = Entries[i];
  1077.     if (security == (SECURITY *)NULL)
  1078.     {
  1079.         if (sa_conn_send(saconn, "<I>No Security Controls defined.", 
  1080.             SA_NULLTERM) != SA_SUCCEED)
  1081.         {
  1082.             return (SA_FAIL);
  1083.         }
  1084.  
  1085.         return (SA_SUCCEED);
  1086.     }
  1087.  
  1088.     if (sa_conn_send(saconn, "<TABLE border=1 cellspacing=4>\n", SA_NULLTERM) 
  1089.         != SA_SUCCEED)
  1090.     {
  1091.         return (SA_FAIL);
  1092.     }
  1093.  
  1094.     while (security != (SECURITY *)NULL)
  1095.     {
  1096.         sprintf(buffer, "<TR><TD>%s</TD><TD>", security->name);
  1097.         if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  1098.             return (SA_FAIL);
  1099.  
  1100.         entry = security->entries;
  1101.         while (entry != (ENTRY *)NULL)
  1102.         {
  1103.             sprintf(buffer, "%s ", entry->value);
  1104.             if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  1105.                 return (SA_FAIL);
  1106.  
  1107.             entry = entry->next;
  1108.         }
  1109.  
  1110.         if (sa_conn_send(saconn, "</TD></TR>\n", SA_NULLTERM) != SA_SUCCEED)
  1111.             return (SA_FAIL);
  1112.  
  1113.         security = security->next;
  1114.     }
  1115.  
  1116.     if (sa_conn_send(saconn, "</TABLE>\n", SA_NULLTERM) != SA_SUCCEED)
  1117.         return (SA_FAIL);
  1118.  
  1119.     return (SA_SUCCEED);
  1120. }
  1121.  
  1122. /*
  1123. **  SECURITY_RELOAD
  1124. **
  1125. **    Reload the security rules.
  1126. **    Note: The final step (swapping security rules) should be mutexed.
  1127. **    It results in a memory leak and could lead to request failure.
  1128. **
  1129. **  Parameters:
  1130. **    sactx        Sambar Server context
  1131. **    saconn        Sambar Server connection
  1132. **    saparams    RPC Parameters
  1133. **    infop        Error parameters
  1134. **
  1135. **  Returns:
  1136. **    SA_SUCCEED | SA_FAIL
  1137. */
  1138. SA_RETCODE SA_PUBLIC
  1139. security_reload(sactx, saconn, saparams, infop)
  1140. SA_CTX        *sactx;
  1141. SA_CONN        *saconn;
  1142. SA_PARAMS    *saparams;
  1143. SA_INT        *infop;
  1144. {
  1145.     SA_INT    i;
  1146.     SA_CHAR    buffer[255];
  1147.  
  1148.     for (i = 0; i < NUM_ENTRIES; i++)
  1149.     {
  1150.         TmpEntries[i] = (SECURITY *)NULL;
  1151.  
  1152.         if (sa_props_load(sactx, "security.ini", 
  1153.             Security_entries[i].symbol, &Security_entries[i].id, 
  1154.             (SA_PROPFUNC)security__load) != SA_SUCCEED)
  1155.         {
  1156.             sprintf(buffer, "Failure loading [%s] security section.", 
  1157.                 Security_entries[i].symbol);
  1158.             sa_log2(sactx, SA_LOG_ERROR, buffer);
  1159.             *infop = SA_E_INTERNALSYSTEM;
  1160.             return (SA_FAIL);
  1161.         }
  1162.     }
  1163.  
  1164.     /* Swap the security rules (leaks memory)                            */
  1165.     for (i = 0; i < NUM_ENTRIES; i++)
  1166.         Entries[i] = TmpEntries[i];
  1167.  
  1168.     return (SA_SUCCEED);
  1169. }
  1170.