home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / WEBSERVE / SAMBAR / DATA.1 / security.c < prev    next >
C/C++ Source or Header  |  1997-08-22  |  18KB  |  796 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. */
  32.  
  33. #include    <stdio.h>
  34. #include    <stdlib.h>
  35. #include    <memory.h>
  36. #include    <string.h>
  37. #include    <ctype.h>
  38. #include    <security.h>
  39.  
  40. /*
  41. ** Local Functions
  42. */
  43. SA_RETCODE            security__load(SA_CTX *ctx, SA_VOID *argp, 
  44.                         SA_CHAR *name, SA_CHAR *value);
  45. static SA_INT        security__casecmp(SA_CHAR *str1, SA_CHAR *str2, 
  46.                         SA_INT len);
  47.  
  48. /*
  49. ** Local Structures
  50. */
  51. typedef struct        security__entry
  52. {
  53.     SA_INT            id;
  54.     SA_CHAR            *symbol;
  55.     SA_CHAR            *descr;
  56.  
  57. } SECURITY_ENTRY;
  58.  
  59. /*
  60. ** Local Defines
  61. */
  62. #define DENIED_HEADER    "HTTP/1.0 404 Request denied.\nContent-type: text/html\n\n<HTML><BODY>"
  63. #define DENIED_BODY        "Request denied by Sambar Server Proxy filter.<P>"
  64. #define DENIED_FOOTER    "</BODY></HTML>"
  65.  
  66. static SECURITY_ENTRY    Security_entries[] =
  67. {
  68.     { SECURITY_REDIRECT,        "redirect",
  69.       "URI to Redirect / URL to Redirect to"  },
  70.     { SECURITY_RESTRICT,        "restrict",
  71.       "URI to Restrict / User or Group granted access" },
  72.     { SECURITY_DENY,            "deny",
  73.       "IP to deny access to / URL to redirect offending hosts to" },
  74.     { SECURITY_HTTPACCEPT,        "httpaccept",
  75.       "IP addresses to accept HTTP hosts from" },
  76.     { SECURITY_HTTPDENY,        "httpdeny",
  77.       "IP addresses of hosts to deny HTTP access to" },
  78.     { SECURITY_FTPACCEPT,        "ftpaccept",
  79.       "IP addresses to accept FTP hosts from" },
  80.     { SECURITY_FTPDENY,            "ftpdeny",
  81.       "IP addresses of hosts to deny FTP access to" },
  82.     { SECURITY_NNTPACCEPT,        "nntpaccept",
  83.       "IP addresses to accept NNTP hosts from" },
  84.     { SECURITY_NNTPDENY,        "nntpdeny",
  85.       "IP addresses of hosts to deny NNTP access to" },
  86.     { SECURITY_PROXYACCEPT,        "proxyaccept",
  87.       "IP addresses to accept Proxy hosts from" },
  88.     { SECURITY_PROXYDENY,        "proxydeny",
  89.       "IP addresses of hosts to deny Proxy access to" },
  90.     { SECURITY_HOSTFILTER,        "hostfilter",
  91.       "Hosts to restrict proxy requests from (AD/Content filtering)" },
  92.     { SECURITY_URLFILTER,        "urlfilter",
  93.       "URLs to restrict proxy requests from (AD/Content filtering)" }
  94. };
  95.  
  96. #define NUM_ENTRIES     sizeof(Security_entries) / sizeof(SECURITY_ENTRY)
  97. static SECURITY            *Entries[NUM_ENTRIES];
  98.  
  99.  
  100.  
  101. /*
  102. **  SECURITY_INIT
  103. **
  104. **    Initialize the Security Rules for use by the Sambar Server plugins.
  105. **    Rules are only loaded at application initialization time and (as this
  106. **    is a threaded application) cannot be modified without a restart of 
  107. **    the server (or mutexing).
  108. **
  109. **
  110. **  Parameters:
  111. **    sactx        Sambar Server context
  112. **
  113. **  Returns:
  114. **    SA_SUCCEED | SA_FAIL
  115. */
  116. SA_RETCODE SA_PUBLIC
  117. security_init(sactx)
  118. SA_CTX        *sactx;
  119. {
  120.     SA_INT        i;
  121.  
  122.     for (i = 0; i < NUM_ENTRIES; i++)
  123.         Entries[i] = (SECURITY *)NULL;
  124.  
  125.     /* 
  126.     ** Load the security rules from the security.ini file
  127.     */
  128.     for (i = 0; i < NUM_ENTRIES; i++)
  129.     {
  130.         if (sa_props_load(sactx, "security.ini", Security_entries[i].symbol, 
  131.             &Security_entries[i].id, (SA_PROPFUNC)security__load) != SA_SUCCEED)
  132.         {
  133.             SA_CHAR        buffer[256];
  134.  
  135.             sprintf(buffer, "Failure loading [%s] security section.", 
  136.                 Security_entries[i].symbol);
  137.             sa_log(sactx, buffer);
  138.         }
  139.     }
  140.  
  141.     /* Initialize the "showsec" RPC                                        */
  142.     if (sa_cmd_init(sactx, "showsec", SA_AUTHORIZATION_ADMIN, 
  143.         "Security rule display.", (SA_VOID *)security_showsec) != SA_SUCCEED)
  144.     {
  145.         sa_log(sactx, "Unable to initialize Security RPCs");
  146.         return (SA_FAIL);
  147.     }
  148.  
  149.     sa_log(sactx, "Security Interfaces Initialized");
  150.  
  151.     return (SA_SUCCEED);
  152. }
  153.  
  154. /*
  155. **  SECURITY_EXIT
  156. **
  157. **    Free the Security Rules.
  158. **
  159. **  Parameters:
  160. **    sactx        Sambar Server context
  161. **
  162. **  Returns:
  163. **    SA_SUCCEED | SA_FAIL
  164. */
  165. SA_RETCODE SA_PUBLIC
  166. security_exit(sactx)
  167. SA_CTX        *sactx;
  168. {
  169.     SA_INT        i;
  170.     SECURITY    *snext;
  171.     SECURITY    *security;
  172.     ENTRY        *enext;
  173.     ENTRY        *entry;
  174.  
  175.     /* 
  176.     ** Free the security rules previously loaded from the security.ini file
  177.     */
  178.     for (i = 0; i < NUM_ENTRIES; i++)
  179.     {
  180.         security = Entries[i];
  181.         while (security != (SECURITY *)NULL)
  182.         {
  183.             snext = security->next;
  184.             free(security->name);
  185.  
  186.             entry = security->entries;
  187.             while (entry != (ENTRY *)NULL)
  188.             {
  189.                 enext = entry->next;
  190.                 free(entry->value);
  191.                 free(entry);
  192.                 entry = enext;
  193.             }
  194.  
  195.             free(security);
  196.             security = snext;
  197.         }
  198.     }
  199.  
  200.     sa_log(sactx, "Security Interfaces Exited");
  201.  
  202.     return (SA_SUCCEED);
  203. }
  204.  
  205. /*
  206. **  SECURITY_REQUEST
  207. **
  208. **    Determine if the request should be fulfilled.
  209. **
  210. **  Parameters:
  211. **    sactx        Sambar Server context
  212. **    saconn        Client connection handle.
  213. **    uri            The URI associated with the request.
  214. **    urilen        The length of the URI string.
  215. **    params        The parameters associated with the request.
  216. **    infop        The error status returned on failure.
  217. **
  218. **  Returns:
  219. **    SA_SUCCEED | SA_FAIL
  220. */
  221. SA_RETCODE SA_PUBLIC
  222. security_request(sactx, saconn, uri, urilen, params, infop)
  223. SA_CTX        *sactx;
  224. SA_CONN        *saconn;
  225. SA_CHAR        *uri;
  226. SA_INT        urilen;
  227. SA_PARAMS    *params;
  228. SA_INT        *infop;
  229. {
  230.     SA_BOOL        found;
  231.     SA_INT        namelen;
  232.     SA_CHAR        name[40];
  233.     SA_INT        pwdlen;
  234.     SA_CHAR        pwd[40];
  235.     ENTRY        *entry;
  236.     SECURITY    *security;
  237.  
  238.     /* 
  239.     ** REDIRECT
  240.     */
  241.     security = Entries[SECURITY_REDIRECT];
  242.     while (security != (SECURITY *)NULL)
  243.     {
  244.         if ((urilen >= security->namelen) && 
  245.             (security__casecmp(uri, security->name, security->namelen) == 0))
  246.         {
  247.             *infop = SA_E_REDIRECT;
  248.             entry = security->entries;
  249.             (SA_VOID)sa_conn_redirect(saconn, entry->value, 
  250.                 "Request redirected.", SA_NULLTERM);
  251.             return (SA_FAIL);
  252.         }
  253.  
  254.         security = security->next;
  255.     }
  256.  
  257.     /*
  258.     ** RESTRICT
  259.     */
  260.     security = Entries[SECURITY_RESTRICT];
  261.     while (security != (SECURITY *)NULL)
  262.     {
  263.         SA_PASSWD    passwd;
  264.  
  265.         if ((urilen >= security->namelen) && 
  266.             (security__casecmp(uri, security->name, security->namelen) == 0))
  267.         {
  268.             if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_NAME, name, 40,
  269.                 &namelen) != SA_SUCCEED)
  270.             {
  271.                 *infop = SA_E_INVALIDLOGIN;
  272.                 return (SA_FAIL);
  273.             }
  274.  
  275.             /* Now lookup the name/password in the passwd file            */
  276.             if (sa_passwd_lookup(sactx, name, namelen, &passwd) != SA_SUCCEED)
  277.             {
  278.                 *infop = SA_E_INVALIDLOGIN;
  279.                 return (SA_FAIL);
  280.             }
  281.  
  282.             /* Get the password and verify the match                    */
  283.             if (sa_conn_props(saconn, SA_GET, SA_CONNPROP_PASSWORD, pwd, 40,
  284.                 &pwdlen) != SA_SUCCEED)
  285.             {
  286.                 *infop = SA_E_INVALIDLOGIN;
  287.                 return (SA_FAIL);
  288.             }
  289.  
  290.             if ((passwd.passwordlen != pwdlen) ||
  291.                 (strncmp(passwd.password, pwd, pwdlen) != 0))
  292.             {
  293.                 *infop = SA_E_INVALIDLOGIN;
  294.                 return (SA_FAIL);
  295.             }
  296.  
  297.             /* 
  298.             ** Lastly, verify the security entry(s) match either the name
  299.             ** or group name of the user.
  300.             */
  301.             found = 0;
  302.             entry = security->entries;
  303.             while ((!found) && (entry != (ENTRY *)NULL))
  304.             {
  305.                 /* Match with the username?                                */
  306.                 if ((namelen == entry->valuelen) &&
  307.                      (memcmp(entry->value, name, namelen) == 0))
  308.                 {
  309.                     found = 1;
  310.                     continue;
  311.                 }
  312.  
  313.                 /* Match with the user group?                            */
  314.                 if ((passwd.grouplen == entry->valuelen) &&
  315.                     (memcmp(entry->value, passwd.group, passwd.grouplen) == 0))
  316.                 {
  317.                     found = 1;
  318.                     continue;
  319.                 }
  320.  
  321.                 entry = entry->next;
  322.             }
  323.  
  324.             if (!found)
  325.             {
  326.                 *infop = SA_E_INVALIDLOGIN;
  327.                 return (SA_FAIL);
  328.             }
  329.         }
  330.  
  331.         security = security->next;
  332.     }
  333.     
  334.     /*
  335.     ** DENY
  336.     */
  337.     if ((Entries[SECURITY_DENY] != (SECURITY *)NULL) &&
  338.         (sa_conn_props(saconn, SA_GET, SA_CONNPROP_HOST, name, 40,
  339.         &namelen) == SA_SUCCEED))
  340.     {
  341.         security = Entries[SECURITY_DENY];
  342.         while (security != (SECURITY *)NULL)
  343.         {
  344.             if ((namelen >= security->namelen) && 
  345.                 (strncmp(name, security->name, security->namelen) == 0))
  346.             {
  347.                 entry = security->entries;
  348.                 *infop = SA_E_REDIRECT;
  349.                 (SA_VOID)sa_conn_redirect(saconn, entry->value, 
  350.                     "Request redirected.", SA_NULLTERM);
  351.                 return (SA_FAIL);
  352.             }
  353.  
  354.             security = security->next;
  355.         }
  356.     }
  357.  
  358.     return (SA_SUCCEED);
  359. }
  360.  
  361. /*
  362. **  SECURITY_CONNECT
  363. **
  364. **    Determine if the connection should be allowed.
  365. **
  366. **  Parameters:
  367. **    sactx        Sambar Server context
  368. **    ipaddr        The IP address of the client requesting a connection.
  369. **    servertype    The server the client is attempting to connect to.
  370. **
  371. **  Returns:
  372. **    SA_SUCCEED | SA_FAIL
  373. */
  374. SA_RETCODE SA_PUBLIC
  375. security_connect(sactx, ipaddr, servertype)
  376. SA_CTX        *sactx;
  377. SA_CHAR        *ipaddr;
  378. SA_INT        servertype;
  379. {
  380.     SA_INT        denyid;
  381.     SA_INT        acceptid;
  382.     SA_INT        ipaddrlen;
  383.     SA_BOOL        found;
  384.     SA_CHAR        *server;
  385.     SECURITY    *security;
  386.     SA_CHAR        buffer[256];
  387.  
  388.     /* Initialization                                                    */
  389.     ipaddrlen = strlen(ipaddr);
  390.  
  391.     switch((int)servertype)
  392.     {
  393.     case SA_SERVERTYPE_HTTP:
  394.         server = "HTTP";
  395.         denyid = SECURITY_HTTPDENY;
  396.         acceptid = SECURITY_HTTPACCEPT;
  397.         break;
  398.  
  399.     case SA_SERVERTYPE_FTP:
  400.         server = "FTP";
  401.         denyid = SECURITY_FTPDENY;
  402.         acceptid = SECURITY_FTPACCEPT;
  403.         break;
  404.  
  405.     case SA_SERVERTYPE_NNTP:
  406.         server = "NNTP";
  407.         denyid = SECURITY_NNTPDENY;
  408.         acceptid = SECURITY_NNTPACCEPT;
  409.         break;
  410.  
  411.     case SA_SERVERTYPE_SMTPPROXY:
  412.     case SA_SERVERTYPE_POP3PROXY:
  413.     case SA_SERVERTYPE_IMAP4PROXY:
  414.         server = "PROXY";
  415.         denyid = SECURITY_PROXYDENY;
  416.         acceptid = SECURITY_PROXYACCEPT;
  417.         break;
  418.  
  419.     default:
  420.         sprintf(buffer, "NETCONNECT: Unrecognized server (%d)", servertype);
  421.         sa_log(sactx, buffer);
  422.         return (SA_FAIL);
  423.     }
  424.  
  425.     /* 
  426.     ** NETACCEPT
  427.     **
  428.     ** The client must be in the accept list.
  429.     */
  430.     found = 0;
  431.     security = Entries[acceptid];
  432.     while ((!found) && (security != (SECURITY *)NULL))
  433.     {
  434.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  435.             ipaddr, ipaddrlen) == 0)
  436.         {
  437.             found = 1;
  438.             continue;
  439.         }
  440.  
  441.         security = security->next;
  442.     }
  443.  
  444.     if (!found)
  445.     {
  446.         sprintf(buffer, 
  447.             "NETCONNECT: Client %s not in accept list for server %s.",
  448.             ipaddr, server);
  449.         sa_log(sactx, buffer);
  450.         return (SA_FAIL);
  451.     }
  452.  
  453.     /* 
  454.     ** NETDENY
  455.     **
  456.     ** The client cannot be in the deny list.
  457.     */
  458.     security = Entries[denyid];
  459.     while (security != (SECURITY *)NULL)
  460.     {
  461.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  462.             ipaddr, ipaddrlen) == 0)
  463.         {
  464.             sprintf(buffer, 
  465.                 "NETCONNECT: Client %s is in deny list for server %s.", 
  466.                 ipaddr, server);
  467.             sa_log(sactx, buffer);
  468.             return (SA_FAIL);
  469.         }
  470.  
  471.         security = security->next;
  472.     }
  473.  
  474.     return (SA_SUCCEED);
  475. }
  476.  
  477. /*
  478. **  SECURITY_FILTER
  479. **
  480. **    Filter all HTTP Proxy requests.  If the requested URL is found
  481. **    in the [httpfilter] section, either return the file specified
  482. **    in the file in response to the request, or return a 404 request
  483. **    denied message if no file is specified.
  484. **
  485. **  Parameters:
  486. **    sactx        Sambar Server context
  487. **    ipaddr        The IP address of the client requesting a connection.
  488. **    servertype    The server the client is attempting to connect to.
  489. **
  490. **  Returns:
  491. **    SA_SUCCEED | SA_FAIL
  492. */
  493. SA_RETCODE SA_PUBLIC
  494. security_filter(sactx, saconn, host, hostlen, url, urllen)
  495. SA_CTX        *sactx;
  496. SA_CONN        *saconn;
  497. SA_CHAR        *host;
  498. SA_INT        hostlen;
  499. SA_CHAR        *url;
  500. SA_INT        urllen;
  501. {
  502.     SECURITY    *security;
  503.  
  504.     security = Entries[SECURITY_HOSTFILTER];
  505.     while (security != (SECURITY *)NULL)
  506.     {
  507.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  508.             host, hostlen) == 0)
  509.         {
  510.             ENTRY        *entry;
  511.             SA_CHAR        buffer[1024];
  512.  
  513.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  514.             (SA_VOID)sa_conn_send(saconn, DENIED_BODY, SA_NULLTERM);
  515.  
  516.             entry = security->entries;
  517.             if (hostlen + entry->valuelen < 1000)
  518.             {
  519.                 sprintf(buffer, "HTTPPROXY: Host %s blocked by filter: %s", 
  520.                     host, entry->value);
  521.                 (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  522.                 sa_log(sactx, buffer);
  523.             }
  524.  
  525.             (SA_VOID)sa_conn_send(saconn, DENIED_FOOTER, SA_NULLTERM);
  526.  
  527.             return (SA_FAIL);
  528.         }
  529.  
  530.         security = security->next;
  531.     }
  532.  
  533.     security = Entries[SECURITY_URLFILTER];
  534.     while (security != (SECURITY *)NULL)
  535.     {
  536.         if (sa_wildcmp(sactx, security->name, security->namelen, 
  537.             url, urllen) == 0)
  538.         {
  539.             ENTRY        *entry;
  540.             SA_CHAR        buffer[1024];
  541.  
  542.             (SA_VOID)sa_send_header(saconn, DENIED_HEADER, SA_NULLTERM);
  543.             (SA_VOID)sa_conn_send(saconn, DENIED_BODY, SA_NULLTERM);
  544.  
  545.             entry = security->entries;
  546.             if (urllen + entry->valuelen < 1000)
  547.             {
  548.                 sprintf(buffer, "HTTPPROXY: URL %s blocked by filter: %s", 
  549.                     url, entry->value);
  550.                 (SA_VOID)sa_conn_send(saconn, buffer, SA_NULLTERM);
  551.                 sa_log(sactx, buffer);
  552.             }
  553.  
  554.             (SA_VOID)sa_conn_send(saconn, DENIED_FOOTER, SA_NULLTERM);
  555.  
  556.             return (SA_FAIL);
  557.         }
  558.  
  559.         security = security->next;
  560.     }
  561.  
  562.     /* HTTP Request should be allowed through.                            */
  563.     return (SA_SUCCEED);
  564. }
  565.  
  566. /*
  567. **  SECURITY__LOAD
  568. **
  569. **    Load a single security rule.
  570. **
  571. **  Parameters:
  572. **    sactx        Sambar Server context
  573. **    argp        Security parameter.
  574. **    name        Left hand argument.
  575. **    value        Right hand argument.
  576. **
  577. **  Returns:
  578. **    SA_SUCCEED | SA_FAIL
  579. */
  580. SA_RETCODE
  581. security__load(sactx, argp, name, value)
  582. SA_CTX        *sactx;
  583. SA_VOID        *argp;
  584. SA_CHAR        *name;
  585. SA_CHAR        *value;
  586. {
  587.     SA_INT        valuelen;
  588.     ENTRY        *entry;
  589.     SECURITY    *security;
  590.  
  591.     security = (SECURITY *)malloc(sizeof(SECURITY));
  592.     if (security == (SECURITY *)NULL)
  593.         return (SA_FAIL);
  594.  
  595.     memset(security, 0, sizeof(SECURITY));
  596.     security->namelen = strlen(name);
  597.     valuelen = strlen(value);
  598.  
  599.     if ((security->namelen == 0) || (valuelen == 0))
  600.         return (SA_FAIL);
  601.  
  602.     security->name = strdup(name);
  603.  
  604.     /* Restriction list have multiple entries                            */
  605.     if (*(SA_INT *)argp == SECURITY_RESTRICT)
  606.     {
  607.         SA_INT        pos;
  608.         SA_INT        head;
  609.  
  610.         pos = 0;
  611.         while (pos < valuelen)
  612.         {
  613.             head = pos;
  614.             while ((pos < valuelen) && !isspace(value[pos]))
  615.                 pos++;
  616.  
  617.             value[pos] = '\0';
  618.  
  619.             entry = (ENTRY *)malloc(sizeof(ENTRY));
  620.             if (entry == (ENTRY *)NULL)
  621.                 return (SA_FAIL);
  622.  
  623.             memset(entry, 0, sizeof(ENTRY));
  624.             entry->value = strdup(&value[head]);
  625.             entry->valuelen = pos - head;;
  626.             entry->next = security->entries;
  627.             security->entries = entry;
  628.  
  629.             pos++;
  630.             while ((pos < valuelen) && isspace(value[pos]))
  631.                 pos++;
  632.         }
  633.     }
  634.     else
  635.     {
  636.         entry = (ENTRY *)malloc(sizeof(ENTRY));
  637.         if (entry == (ENTRY *)NULL)
  638.             return (SA_FAIL);
  639.  
  640.         memset(entry, 0, sizeof(ENTRY));
  641.         entry->valuelen = valuelen;
  642.         entry->value = strdup(value);
  643.         security->entries = entry;
  644.     }
  645.  
  646.     security->next = Entries[*(SA_INT *)argp];
  647.     Entries[*(SA_INT *)argp] = security;
  648.  
  649.     return (SA_SUCCEED);
  650. }
  651.  
  652. /*
  653. **  SECURITY_SHOWSEC
  654. **
  655. **    Show the security associated with a particular symbol.
  656. **
  657. **  Parameters:
  658. **    sactx        Sambar Server context
  659. **    saconn        Sambar Server connection
  660. **    saparams    RPC Parameters
  661. **    infop        Error parameters
  662. **
  663. **  Returns:
  664. **    SA_SUCCEED | SA_FAIL
  665. */
  666. SA_RETCODE SA_PUBLIC
  667. security_showsec(sactx, saconn, saparams, infop)
  668. SA_CTX        *sactx;
  669. SA_CONN        *saconn;
  670. SA_PARAMS    *saparams;
  671. SA_INT        *infop;
  672. {
  673.     SA_INT        i;
  674.     SA_BOOL        found;
  675.     SA_INT        datalen;
  676.     SA_CHAR        *data;
  677.     ENTRY        *entry;
  678.     SECURITY    *security;
  679.     SA_CHAR        buffer[1024];
  680.  
  681.     /* Get the present sum                                                */
  682.     if ((sa_param(sactx, saparams, "type", &data, &datalen) != SA_SUCCEED) ||
  683.         (datalen == 0))
  684.     {
  685.         /* No report type given                                            */
  686.         return (SA_SUCCEED);
  687.     }
  688.  
  689.     i = 0;
  690.     found = 0;
  691.     while ((i < NUM_ENTRIES) && (!found))
  692.     {
  693.         if (strcmp(Security_entries[i].symbol, (SA_CHAR *)data) == 0)
  694.             found = 1;
  695.         else
  696.             i++;
  697.     }
  698.  
  699.     if (!found)
  700.     {
  701.         *infop = SA_E_INVALIDDATA;
  702.         return (SA_FAIL);
  703.     }
  704.  
  705.     sprintf(buffer, "<FONT SIZE=+1><B>%s</B></FONT><P>\n", 
  706.         Security_entries[i].descr);
  707.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  708.         return (SA_FAIL);
  709.  
  710.     security = Entries[i];
  711.     if (security == (SECURITY *)NULL)
  712.     {
  713.         if (sa_conn_send(saconn, "<I>No Security Controls defined.", 
  714.             SA_NULLTERM) != SA_SUCCEED)
  715.         {
  716.             return (SA_FAIL);
  717.         }
  718.  
  719.         return (SA_SUCCEED);
  720.     }
  721.  
  722.     if (sa_conn_send(saconn, "<TABLE border=1 cellspacing=4>\n", SA_NULLTERM) 
  723.         != SA_SUCCEED)
  724.     {
  725.         return (SA_FAIL);
  726.     }
  727.  
  728.     while (security != (SECURITY *)NULL)
  729.     {
  730.         sprintf(buffer, "<TR><TD>%s</TD><TD>", security->name);
  731.         if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  732.             return (SA_FAIL);
  733.  
  734.         entry = security->entries;
  735.         while (entry != (ENTRY *)NULL)
  736.         {
  737.             sprintf(buffer, "%s ", entry->value);
  738.             if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  739.                 return (SA_FAIL);
  740.  
  741.             entry = entry->next;
  742.         }
  743.  
  744.         if (sa_conn_send(saconn, "</TD></TR>\n", SA_NULLTERM) != SA_SUCCEED)
  745.             return (SA_FAIL);
  746.  
  747.         security = security->next;
  748.     }
  749.  
  750.     if (sa_conn_send(saconn, "</TABLE>\n", SA_NULLTERM) != SA_SUCCEED)
  751.         return (SA_FAIL);
  752.  
  753.     return (SA_SUCCEED);
  754. }
  755.  
  756. /*
  757. **  SECURITY__CASECMP
  758. **
  759. **    Compare two case-insensitive strings.
  760. **
  761. **  Parameters:
  762. **    str1        String to compare.
  763. **    str2        String to compare.
  764. **    len            Length of the comparison.
  765. **
  766. **  Returns:
  767. **    SA_INT
  768. */
  769. static SA_INT
  770. security__casecmp(str1, str2, len)
  771. SA_CHAR        *str1;
  772. SA_CHAR        *str2;
  773. SA_INT        len;
  774. {
  775.     SA_INT        i;
  776.     SA_INT        diff;
  777.  
  778.     if (len == 0)
  779.         return (0);
  780.  
  781.     i = 0;
  782.     while (i < len)
  783.     {
  784.         if ((str1[i] == '\0') || (str2[i] == '\0'))
  785.             return (str1[i] - str2[i]);
  786.  
  787.         diff = tolower(str1[i]) - tolower(str2[i]);
  788.         if (diff != 0)
  789.             return (diff);
  790.  
  791.         i++;
  792.     }
  793.  
  794.     return (0);
  795. }
  796.