Logo Search packages:      
Sourcecode: nut version File versions  Download package

upsset.c

/* upsset - CGI program to manage read/write variables

   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include "common.h"

#include <netdb.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include "upsclient.h"
#include "cgilib.h"
#include "parseconf.h"

struct list_t {
      char  *name;
      struct      list_t      *next;
};

/* see the stock upsset.conf for the whole rant on what this is */
#define MAGIC_ENABLE_STRING "I_HAVE_SECURED_MY_CGI_DIRECTORY"

#define HARD_UPSVAR_LIMIT_NUM 64
#define HARD_UPSVAR_LIMIT_LEN 256

      char  *monups, *username, *password, *function, *upscommand;

      /* set once the MAGIC_ENABLE_STRING is found in the upsset.conf */
      int   magic_string_set = 0;

static      int   port;
static      char  *upsname, *hostname;
static      UPSCONN_t   ups;

typedef struct {
      char  *var;
      char  *value;
      void  *next;
}     uvtype_t;

      uvtype_t    *firstuv = NULL;

void parsearg(char *var, char *value)
{
      char  *ptr;
      uvtype_t    *last, *tmp = NULL;
      static      int upsvc = 0;

      /* store variables from a SET command for the later commit */
      if (!strncmp(var, "UPSVAR_", 7)) {

            /* if someone bombs us with variables, stop at some point */
            if (upsvc > HARD_UPSVAR_LIMIT_NUM)
                  return;

            /* same idea: throw out anything that's much too long */
            if (strlen(value) > HARD_UPSVAR_LIMIT_LEN)
                  return;

            ptr = strchr(var, '_');

            if (!ptr)         /* sanity check */
                  return;

            ptr++;

            tmp = last = firstuv;
            while (tmp) {
                  last = tmp;
                  tmp = tmp->next;
            }

            tmp = xmalloc(sizeof(uvtype_t));
            tmp->var = xstrdup(ptr);
            tmp->value = xstrdup(value);
            tmp->next = NULL;

            if (last)
                  last->next = tmp;
            else
                  firstuv = tmp;

            upsvc++;

            return;
      }

      if (!strcmp(var, "username")) {
            free(username);
            username = xstrdup(value);
      }

      if (!strcmp(var, "password")) {
            free(password);
            password = xstrdup(value);
      }

      if (!strcmp(var, "function")) {
            free(function);
            function = xstrdup(value);
      }

      if (!strcmp(var, "monups")) {
            free(monups);
            monups = xstrdup(value);
      }

      if (!strcmp(var, "upscommand")) {
            free(upscommand);
            upscommand = xstrdup(value);
      }
}

static void do_header(const char *title)
{
      printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
      printf("    \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
      printf("<HTML>\n");
      printf("<HEAD><TITLE>upsset: %s</TITLE></HEAD>\n", title);

      printf("<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000EE\" VLINK=\"#551A8B\">\n"); 

      printf("<TABLE BGCOLOR=\"#50A0A0\" ALIGN=\"CENTER\">\n");
      printf("<TR><TD>\n");
}

static void start_table(void)
{
      printf("<TABLE CELLPADDING=\"5\" CELLSPACING=\"0\" ALIGN=\"CENTER\" WIDTH=\"100%%\">\n");
      printf("<TR><TH COLSPAN=2 BGCOLOR=\"#60B0B0\">\n");
      printf("<FONT SIZE=\"+2\">Network UPS Tools upsset %s</FONT>\n", 
            UPS_VERSION);
      printf("</TH></TR>\n");
}

/* propagate login details across pages - no cookies here! */
static void do_hidden(const char *next)
{
      printf("<INPUT TYPE=\"HIDDEN\" NAME=\"username\" VALUE=\"%s\">\n",
            username);
      printf("<INPUT TYPE=\"HIDDEN\" NAME=\"password\" VALUE=\"%s\">\n",
            password);

      if (next)
            printf("<INPUT TYPE=\"HIDDEN\" NAME=\"function\" VALUE=\"%s\">\n", 
                  next);
}

/* generate SELECT chooser from hosts.conf entries */
static void upslist_arg(int numargs, char **arg)
{
      if (numargs < 3)
            return;

      /* MONITOR <ups> <description> */
      if (!strcmp(arg[0], "MONITOR")) {
            printf("<OPTION VALUE=\"%s\"", arg[1]);

            if (monups)
                  if (!strcmp(monups, arg[1]))
                        printf("SELECTED");

            printf(">%s</OPTION>\n", arg[2]);
      }
}

/* called for fatal errors in parseconf like malloc failures */
static void upsset_hosts_err(const char *errmsg)
{
      upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg);
}

/* this defaults to wherever we are now, ups and function-wise */
static void do_pickups(const char *currfunc)
{
      char  hostfn[SMALLBUF];
      PCONF_CTX_t ctx;

      snprintf(hostfn, sizeof(hostfn), "%s/hosts.conf", confpath());

      printf("<FORM METHOD=\"POST\" ACTION=\"upsset.cgi\">\n");

      printf("Select UPS and function:\n<BR>\n");

      pconf_init(&ctx, upsset_hosts_err);

      if (!pconf_file_begin(&ctx, hostfn)) {
            pconf_finish(&ctx);

            printf("Error: hosts.conf unavailable\n");
            printf("</FORM>\n");

            /* stderr is for the admin - should wind up in error.log */
            fprintf(stderr, "upsset: %s\n", ctx.errmsg);

            return;
      }

      printf("<SELECT NAME=\"monups\">\n");

      while (pconf_file_next(&ctx)) {
            if (pconf_parse_error(&ctx)) {
                  upslogx(LOG_ERR, "Parse error: %s:%d: %s",
                        hostfn, ctx.linenum, ctx.errmsg);

                  continue;
            }

            upslist_arg(ctx.numargs, ctx.arglist);          
      }

      pconf_finish(&ctx);

      printf("</SELECT>\n");

      printf("<SELECT NAME=\"function\">\n");

      /* FUTURE */
      /*    printf("<OPTION VALUE=\"showstatus\">Status</OPTION>\n");  */

      /* TODO: clean this up */

      if (!strcmp(currfunc, "showsettings"))
            printf("<OPTION VALUE=\"showsettings\" SELECTED>Settings</OPTION>\n");
      else
            printf("<OPTION VALUE=\"showsettings\">Settings</OPTION>\n");

      if (!strcmp(currfunc, "showcmds"))
            printf("<OPTION VALUE=\"showcmds\" SELECTED>Commands</OPTION>\n");
      else
            printf("<OPTION VALUE=\"showcmds\">Commands</OPTION>\n");

      printf("</SELECT>\n");
      do_hidden(NULL);

      printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"View\">\n");
      printf("</FORM>\n");
}

static void error_page(const char *next, const char *title,
      const char *fmt, ...)
{
      char  msg[SMALLBUF];
      va_list     ap;

      va_start(ap, fmt);
      vsnprintf(msg, sizeof(msg), fmt, ap);
      va_end(ap);

      do_header(title);

      start_table();
      printf("<TR><TH COLSPAN=2 BGCOLOR=\"#60B0B0\">\n");
      printf("Error: %s\n", msg);
      printf("</TH></TR>\n");

      printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
      do_pickups(next);
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</TD></TR></TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

static void loginscreen(void)
{
      do_header("Login");
      printf("<FORM METHOD=\"POST\" ACTION=\"upsset.cgi\">\n");
      start_table();

      printf("<TR BGCOLOR=\"#60B0B0\">\n");
      printf("<TH>Username</TH>\n");
      printf("<TD><INPUT TYPE=\"TEXT\" NAME=\"username\" VALUE=\"\"></TD>\n");
      printf("</TR>\n");

      printf("<TR BGCOLOR=\"#60B0B0\">\n");
      printf("<TH>Password</TH>\n");
      printf("<TD><INPUT TYPE=\"PASSWORD\" NAME=\"password\" VALUE=\"\"></TD>\n");
      printf("</TR>\n");

      printf("<TR><TD COLSPAN=2 ALIGN=\"CENTER\">\n");
      printf("<INPUT TYPE=\"HIDDEN\" NAME=\"function\" VALUE=\"pickups\">\n");
      printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Login\">\n");
      printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset fields\">\n");
      printf("</TD></TR></TABLE>\n");
      printf("</FORM>\n");
      printf("</TD></TR></TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

/* try to connect to upsd - generate an error page if it fails */
static void upsd_connect(void)
{
      if (upscli_splitname(monups, &upsname, &hostname, &port) != 0) {
            error_page("showsettings", "UPS name is unusable",
                  "Unable to split UPS name [%s]", monups);
            /* NOTREACHED */
      }

      if (upscli_connect(&ups, hostname, port, 0) < 0) {
            error_page("showsettings", "Connect failure",
                  "Unable to connect to %s: %s",
                  monups, upscli_strerror(&ups));
            /* NOTREACHED */
      }
}

static void print_cmd(const char *cmd)
{
      int   ret;
      unsigned int      numq, numa;
      char  **answer;
      const char  *query[4];

      query[0] = "CMDDESC";
      query[1] = upsname;
      query[2] = cmd;
      numq = 3;

      ret = upscli_get(&ups, numq, query, &numa, &answer);

      if ((ret < 0) || (numa < numq))
            return;

      /* CMDDESC <upsname> <cmdname> <desc> */

      printf("<OPTION VALUE=\"%s\">%s</OPTION>\n", cmd, answer[3]);
}

/* generate a list of instant commands */
static void showcmds(void)
{
      int   ret;
      unsigned int      numq, numa;
      const char  *query[2];
      char  **answer;
      struct      list_t      *lhead, *llast, *ltmp, *lnext;
      char  *desc;

      if (!checkhost(monups, &desc))
            error_page("showsettings", "Access denied",
                  "Access to that host is not authorized");

      upsd_connect();

      llast = lhead = NULL;

      query[0] = "CMD";
      query[1] = upsname;
      numq = 2;

      ret = upscli_list_start(&ups, numq, query);

      if (ret < 0) {
            fprintf(stderr, "LIST CMD %s failed: %s\n",
                  upsname, upscli_strerror(&ups));

            error_page("showcmds", "Server protocol error",
                  "LIST CMD command failed");

            /* NOTREACHED */
      }

      ret = upscli_list_next(&ups, numq, query, &numa, &answer);

      while (ret == 1) {

            /* CMD upsname cmdname */
            if (numa < 3) {
                  fprintf(stderr, "Error: insufficient data "
                        "(got %d args, need at least 3)\n", numa);

                  return;
            }

            ltmp = xmalloc(sizeof(struct list_t));
            ltmp->name = xstrdup(answer[2]);
            ltmp->next = NULL;

            if (llast)
                  llast->next = ltmp;
            else
                  lhead = ltmp;

            llast = ltmp;

            ret = upscli_list_next(&ups, numq, query, &numa, &answer);
      }

      if (!lhead)
            error_page("showcmds", "No instant commands supported",
                  "This UPS doesn't support any instant commands.");

      do_header("Instant commands");
      printf("<FORM ACTION=\"upsset.cgi\" METHOD=\"POST\">\n");
      start_table();

      /* include the description from checkhost() if present */
      if (desc)
            printf("<TR><TH BGCOLOR=\"#60B0B0\"COLSPAN=2>%s</TH></TR>\n",
                  desc);

      printf("<TR BGCOLOR=\"#60B0B0\" ALIGN=\"CENTER\">\n");
      printf("<TD>Instant commands</TD>\n");

      printf("<TD>\n");
      printf("<SELECT NAME=\"upscommand\">\n");

      /* provide a dummy do-nothing default choice */
      printf("<OPTION VALUE=\"\" SELECTED></OPTION>\n");

      ltmp = lhead;

      while (ltmp) {
            lnext = ltmp->next;

            print_cmd(ltmp->name);

            free(ltmp->name);
            free(ltmp);
            ltmp = lnext;
      }

      printf("</SELECT>\n");
      printf("</TD></TR>\n");

      printf("<TR BGCOLOR=\"#60B0B0\">\n");
      printf("<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n");
      do_hidden("docmd");
      printf("<INPUT TYPE=\"HIDDEN\" NAME=\"monups\" VALUE=\"%s\">\n", monups);
      printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Issue command\">\n");
      printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset\">\n");
      printf("</TD></TR>\n");
      printf("</TABLE>\n");
      printf("</FORM>\n");

      printf("<TR><TD ALIGN=\"CENTER\">\n");
      do_pickups("showcmds");
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}     

/* handle setting authentication data in the server */
static void send_auth(const char *next)
{
      char  buf[SMALLBUF];

      snprintf(buf, sizeof(buf), "USERNAME %s\n", username);

      if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
            fprintf(stderr, "Can't set username: %s\n",
                  upscli_strerror(&ups));

            error_page(next, "Can't set username",
                  "Set username failed: %s", upscli_strerror(&ups));
      }

      if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {

            /* test for old upsd that doesn't do USERNAME */
            if (upscli_upserror(&ups) == UPSCLI_ERR_UNKCOMMAND) {
                  error_page(next, "Protocol mismatch",
                        "upsd version too old - USERNAME not supported");
            }

            error_page(next, "Can't set user name", 
                  "Set user name failed: %s", upscli_strerror(&ups));
      }

      snprintf(buf, sizeof(buf), "PASSWORD %s\n", password);

      if (upscli_sendline(&ups, buf, strlen(buf)) < 0)
            error_page(next, "Can't set password",
                  "Password set failed: %s", upscli_strerror(&ups));

      if (upscli_readline(&ups, buf, sizeof(buf)) < 0)
            error_page(next, "Can't set password",
                  "Password set failed: %s", upscli_strerror(&ups));
}     

static void docmd(void)
{
      char  buf[SMALLBUF], *desc;

      if (!checkhost(monups, &desc))
            error_page("showsettings", "Access denied",
                  "Access to that host is not authorized");

      /* the user is messing with us */
      if (!upscommand)  
            error_page("showcmds", "Form error", 
                  "No instant command selected");

      /* (l)user took the default blank option */
      if (strlen(upscommand) == 0)
            error_page("showcmds", "Form error", 
                  "No instant command selected");

      upsd_connect();

      send_auth("showcmds");

      snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, upscommand);

      if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
            do_header("Error while issuing command");

            start_table();

            printf("<TR><TD>Error sending command: %s\n</TD></TR>",
                  upscli_strerror(&ups));

            printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
            do_pickups("showcmds");
            printf("</TD></TR>\n");

            printf("</TABLE>\n");

            printf("</TD></TR></TABLE>\n");
            printf("</BODY></HTML>\n");

            upscli_sendline(&ups, "LOGOUT\n", 7);
            upscli_disconnect(&ups);
            exit(EXIT_SUCCESS);
      }

      if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {
            do_header("Error while reading command response");

            start_table();

            printf("<TR><TD>Error reading command response: %s\n</TD></TR>",
                  upscli_strerror(&ups));

            printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
            do_pickups("showcmds");
            printf("</TD></TR>\n");

            printf("</TABLE>\n");

            printf("</TD></TR></TABLE>\n");
            printf("</BODY></HTML>\n");

            upscli_sendline(&ups, "LOGOUT\n", 7);
            upscli_disconnect(&ups);
            exit(EXIT_SUCCESS);
      }

      do_header("Issuing command");
      start_table();

      printf("<TR><TD><PRE>\n");
      printf("Sending command: %s\n", upscommand);
      printf("Response: %s\n", buf);
      printf("</PRE></TD></TR>\n");

      printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
      do_pickups("showcmds");
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</TD></TR></TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

static const char *get_data(const char *type, const char *varname)
{
      int   ret;
      unsigned int      numq, numa;
      char  **answer;
      const char  *query[4];

      query[0] = type;
      query[1] = upsname;
      query[2] = varname;
      numq = 3;

      ret = upscli_get(&ups, numq, query, &numa, &answer);

      if ((ret < 0) || (numa < numq))
            return NULL;

      /* <type> <upsname> <varname> <desc> */
      return answer[3];
}

static void do_string(const char *varname, int maxlen)
{
      const char  *val;

      val = get_data("VAR", varname);

      if (!val) {
            printf("Unavailable\n");
            fprintf(stderr, "do_string: can't get current value of %s\n",
                  varname);
            return;
      }

      printf("<INPUT TYPE=\"TEXT\" NAME=\"UPSVAR_%s\" VALUE=\"%s\" "
            "SIZE=\"%d\">\n", varname, val, maxlen);
}

static void do_enum(const char *varname)
{
      int   ret;
      unsigned int      numq, numa;
      char  **answer, *val;
      const char  *query[4], *tmp;

      /* get current value */
      tmp = get_data("VAR", varname);

      if (!tmp) {
            printf("Unavailable\n");
            fprintf(stderr, "do_enum: can't get current value of %s\n",
                  varname);
            return;
      }

      /* tmp is a pointer into answer - have to save it somewhere else */
      val = xstrdup(tmp);

      query[0] = "ENUM";
      query[1] = upsname;
      query[2] = varname;
      numq = 3;

      ret = upscli_list_start(&ups, numq, query);

      if (ret < 0) {
            printf("Unavailable\n");
            fprintf(stderr, "Error doing ENUM %s %s: %s\n", 
                  upsname, varname, upscli_strerror(&ups));
            return;
      }

      ret = upscli_list_next(&ups, numq, query, &numa, &answer);

      printf("<SELECT NAME=\"UPSVAR_%s\">\n", varname);

      while (ret == 1) {

            /* ENUM <upsname> <varname> <value> */

            if (numa < 4) {
                  fprintf(stderr, "Error: insufficient data "
                        "(got %d args, need at least 4)\n", numa);

                  free(val);
                  return;
            }

            printf("<OPTION VALUE=\"%s\" ", answer[3]);

            if (!strcmp(answer[3], val))
                  printf(" SELECTED");

            printf(">%s</OPTION>\n", answer[3]);

            ret = upscli_list_next(&ups, numq, query, &numa, &answer);
      }

      free(val);
      printf("</SELECT>\n");
}

static void do_type(const char *varname)
{
      int   ret;
      unsigned int      i, numq, numa;
      char  **answer;
      const char  *query[4];

      query[0] = "TYPE";
      query[1] = upsname;
      query[2] = varname;
      numq = 3;

      ret = upscli_get(&ups, numq, query, &numa, &answer);

      if ((ret < 0) || (numa < numq)) {
            printf("Unknown type\n");     
            return;
      }

      /* TYPE <upsname> <varname> <type>... */
      for (i = 3; i < numa; i++) {

            if (!strcasecmp(answer[i], "ENUM")) {
                  do_enum(varname);
                  return;
            }

            if (!strncasecmp(answer[i], "STRING:", 7)) {
                  char  *ptr, len;

                  /* split out the :<len> data */
                  ptr = strchr(answer[i], ':');
                  *ptr++ = '\0';
                  len = strtol(ptr, (char **) NULL, 10);

                  do_string(varname, len);
                  return;
            }

            /* ignore this one */
            if (!strcasecmp(answer[i], "RW"))
                  continue;

            printf("Unrecognized\n");
      }
}

static void print_rw(const char *upsname, const char *varname)
{
      const char  *tmp;

      printf("<TR BGCOLOR=\"#60B0B0\" ALIGN=\"CENTER\">\n");

      printf("<TD>");

      tmp = get_data("DESC", varname);

      if ((tmp) && (strcmp(tmp, "Unavailable") != 0))
            printf("%s", tmp);
      else
            printf("%s", varname);

      printf("</TD>\n");

      printf("<TD>\n");
      do_type(varname);
      printf("</TD>\n");

      printf("</TR>\n");
}

static void showsettings(void)
{
      int   ret;
      unsigned int      numq, numa;
      const char  *query[2];
      char  **answer, *desc = NULL;
      struct      list_t      *lhead, *llast, *ltmp, *lnext;

      if (!checkhost(monups, &desc))
            error_page("showsettings", "Access denied",
                  "Access to that host is not authorized");

      upsd_connect();

      query[0] = "RW";
      query[1] = upsname;
      numq = 2;

      ret = upscli_list_start(&ups, numq, query);

      if (ret < 0) {
            fprintf(stderr, "LIST RW %s failed: %s\n",
                  upsname, upscli_strerror(&ups));

            error_page("showsettings", "Server protocol error",
                  "LIST RW command failed");

            /* NOTREACHED */
      }

      llast = lhead = NULL;

      ret = upscli_list_next(&ups, numq, query, &numa, &answer);

      while (ret == 1) {

            /* sock this entry away for later */

            ltmp = xmalloc(sizeof(struct list_t));
            ltmp->name = xstrdup(answer[2]);
            ltmp->next = NULL;

            if (llast)
                  llast->next = ltmp;
            else
                  lhead = ltmp;

            llast = ltmp;

            ret = upscli_list_next(&ups, numq, query, &numa, &answer);
      }

      do_header("Current settings");
      printf("<FORM ACTION=\"upsset.cgi\" METHOD=\"POST\">\n");
      start_table();

      /* include the description from checkhost() if present */
      if (desc)
            printf("<TR><TH BGCOLOR=\"#60B0B0\"COLSPAN=2>%s</TH></TR>\n",
                  desc);

      printf("<TR BGCOLOR=\"#60B0B0\">\n");
      printf("<TH>Setting</TH>\n");
      printf("<TH>Value</TH></TR>\n");

      /* use the list to get descriptions and types */

      ltmp = lhead;

      while (ltmp) {
            lnext = ltmp->next;

            print_rw(upsname, ltmp->name);

            free(ltmp->name);
            free(ltmp);
            ltmp = lnext;
      }

      printf("<TR BGCOLOR=\"#60B0B0\">\n");
      printf("<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n");
      do_hidden("savesettings");
      printf("<INPUT TYPE=\"HIDDEN\" NAME=\"monups\" VALUE=\"%s\">\n", monups);
      printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Save changes\">\n");
      printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset\">\n");
      printf("</TD></TR>\n");
      printf("</TABLE>\n");
      printf("</FORM>\n");

      printf("<TR><TD ALIGN=\"CENTER\">\n");
      do_pickups("showsettings");
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

static int setvar(const char *var, const char *val)
{
      char  buf[SMALLBUF], enc[SMALLBUF];
      const char  *tmp;

      /* get old value */
      tmp = get_data("VAR", var);

      if (!tmp) {
            printf("Can't get old value for %s, aborting SET\n", var);
            return 0;
      }

      /* don't send a SET if it hasn't chnaged */
      if (!strcmp(tmp, val))
            return 0;

      printf("set %s to %s (was %s)\n", var, val, tmp);

      snprintf(buf, sizeof(buf), "SET VAR %s %s \"%s\"\n",
            upsname, var, pconf_encode(val, enc, sizeof(enc)));

      if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
            printf("Error: SET failed: %s\n", upscli_strerror(&ups));
            return 0;
      }

      if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {
            printf("Error: SET failed: %s\n", upscli_strerror(&ups));
            return 0;
      }

      if (strncmp(buf, "OK", 2) != 0) {
            printf("Unexpected response: %s\n", buf);
            return 0;
      }

      printf("OK\n");
      return 1;
}

/* turn a form submission of settings into SET commands for upsd */
static void savesettings(void)
{
      int   changed = 0;
      char  *desc;
      uvtype_t    *upsvar;

      if (!checkhost(monups, &desc)) 
            error_page("showsettings", "Access denied",
                  "Access to that host is not authorized");

      upsd_connect();

      upsvar = firstuv;

      send_auth("showsettings");

      do_header("Saving settings");
      start_table();

      printf("<TR><TD><PRE>\n");

      while (upsvar) {
            changed += setvar(upsvar->var, upsvar->value);
            upsvar = upsvar->next;
      }

      if (changed == 0)
            printf("No settings changed.\n");
      else
            printf("Updated %d setting%s.\n",
                  changed, changed == 1 ? "" : "s");

      printf("</PRE></TD></TR>\n");

      printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=\"2\">\n");
      do_pickups("showsettings");
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</TD></TR></TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

static void initial_pickups(void)
{
      do_header("Select a UPS");
      start_table();

      printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=\"2\">\n");
      do_pickups("");
      printf("</TD></TR>\n");

      printf("</TABLE>\n");
      printf("</TD></TR></TABLE>\n");
      printf("</BODY></HTML>\n");

      upscli_sendline(&ups, "LOGOUT\n", 7);
      upscli_disconnect(&ups);
      exit(EXIT_SUCCESS);
}

static void upsset_conf_err(const char *errmsg)
{
      upslogx(LOG_ERR, "Fatal error in parseconf(upsset.conf): %s", errmsg);
}

/* see if the user has confirmed their cgi directory's secure state */
static void check_conf(void)
{
      char  fn[SMALLBUF];
      PCONF_CTX_t ctx;

      snprintf(fn, sizeof(fn), "%s/upsset.conf", confpath());

      pconf_init(&ctx, upsset_conf_err);

      if (!pconf_file_begin(&ctx, fn)) {
            pconf_finish(&ctx);

            printf("<PRE>\n");
            printf("Error: Can't open upsset.conf to verify security settings.\n");
            printf("Refusing to start until this is fixed.\n");
            printf("</PRE>\n");

            /* leave something in the httpd log for the admin */
            fprintf(stderr, "upsset.conf does not exist to permit execution\n");
            exit(EXIT_FAILURE);
      }

      while (pconf_file_next(&ctx)) {
            if (pconf_parse_error(&ctx)) {
                  upslogx(LOG_ERR, "Parse error: %s:%d: %s",
                        fn, ctx.linenum, ctx.errmsg);
                  continue;
            }

            if (ctx.numargs < 1)
                  continue;

            if (!strcmp(ctx.arglist[0], MAGIC_ENABLE_STRING))
                  magic_string_set = 1;
      }

      pconf_finish(&ctx);

      /* if we've been enabled, jump out of here and go to work */
      if (magic_string_set == 1)
            return;

      printf("<PRE>\n");
      printf("Error: Secure mode has not been enabled in upsset.conf.\n");
      printf("Refusing to start until this is fixed.\n");
      printf("</PRE>\n");

      /* leave something in the httpd log for the admin */
      fprintf(stderr, "upsset.conf does not permit execution\n");

      exit(EXIT_FAILURE);
}     

int main(int argc, char **argv)
{
      username = password = function = monups = NULL;

      printf("Content-type: text/html\n\n");

      /* see if the magic string is present in the config file */
      check_conf();

      /* see if there's anything waiting .. the server my not close STDIN properly */
      if (1) {
          fd_set fds;
          struct timeval tv;

          FD_ZERO(&fds);
          FD_SET(STDIN_FILENO, &fds);
          tv.tv_sec = 0;
          tv.tv_usec = 250000; /* wait for up to 250ms  for a POST response */
          if ((select(STDIN_FILENO+1, &fds, 0, 0, &tv)) > 0)
            extractpostargs();
      }
      if ((!username) || (!password) || (!function))
            loginscreen();

      if ((!strcmp(function, "pickups")) || (!monups))
            initial_pickups();

      if (!strcmp(function, "showsettings"))
            showsettings();

      if (!strcmp(function, "savesettings"))
            savesettings();

#if 0       /* FUTURE */
      if (!strcmp(function, "showstatus"))
            showstatus();
#endif

      if (!strcmp(function, "showcmds"))
            showcmds();

      if (!strcmp(function, "docmd"))
            docmd();

      printf("Error: Unhandled function name [%s]\n", function);
      
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index