1 /* upsset - CGI program to manage read/write variables
2
3 Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "common.h"
21
22 #include <netdb.h>
23 #include <stdlib.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26
27 #include "upsclient.h"
28 #include "cgilib.h"
29 #include "parseconf.h"
30
31 struct list_t {
32 char *name;
33 struct list_t *next;
34 };
35
36 /* see the stock upsset.conf for the whole rant on what this is */
37 #define MAGIC_ENABLE_STRING "I_HAVE_SECURED_MY_CGI_DIRECTORY"
38
39 #define HARD_UPSVAR_LIMIT_NUM 64
40 #define HARD_UPSVAR_LIMIT_LEN 256
41
42 char *monups, *username, *password, *function, *upscommand;
43
44 /* set once the MAGIC_ENABLE_STRING is found in the upsset.conf */
45 int magic_string_set = 0;
46
47 static int port;
48 static char *upsname, *hostname;
49 static UPSCONN_t ups;
50
51 typedef struct {
52 char *var;
53 char *value;
54 void *next;
55 } uvtype_t;
56
57 uvtype_t *firstuv = NULL;
58
parsearg(char * var,char * value)59 void parsearg(char *var, char *value)
60 {
61 char *ptr;
62 uvtype_t *last, *tmp = NULL;
63 static int upsvc = 0;
64
65 /* store variables from a SET command for the later commit */
66 if (!strncmp(var, "UPSVAR_", 7)) {
67
68 /* if someone bombs us with variables, stop at some point */
69 if (upsvc > HARD_UPSVAR_LIMIT_NUM)
70 return;
71
72 /* same idea: throw out anything that's much too long */
73 if (strlen(value) > HARD_UPSVAR_LIMIT_LEN)
74 return;
75
76 ptr = strchr(var, '_');
77
78 if (!ptr) /* sanity check */
79 return;
80
81 ptr++;
82
83 tmp = last = firstuv;
84 while (tmp) {
85 last = tmp;
86 tmp = tmp->next;
87 }
88
89 tmp = xmalloc(sizeof(uvtype_t));
90 tmp->var = xstrdup(ptr);
91 tmp->value = xstrdup(value);
92 tmp->next = NULL;
93
94 if (last)
95 last->next = tmp;
96 else
97 firstuv = tmp;
98
99 upsvc++;
100
101 return;
102 }
103
104 if (!strcmp(var, "username")) {
105 free(username);
106 username = xstrdup(value);
107 }
108
109 if (!strcmp(var, "password")) {
110 free(password);
111 password = xstrdup(value);
112 }
113
114 if (!strcmp(var, "function")) {
115 free(function);
116 function = xstrdup(value);
117 }
118
119 if (!strcmp(var, "monups")) {
120 free(monups);
121 monups = xstrdup(value);
122 }
123
124 if (!strcmp(var, "upscommand")) {
125 free(upscommand);
126 upscommand = xstrdup(value);
127 }
128 }
129
do_header(const char * title)130 static void do_header(const char *title)
131 {
132 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
133 printf(" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
134 printf("<HTML>\n");
135 printf("<HEAD><TITLE>upsset: %s</TITLE></HEAD>\n", title);
136
137 printf("<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000EE\" VLINK=\"#551A8B\">\n");
138
139 printf("<TABLE BGCOLOR=\"#50A0A0\" ALIGN=\"CENTER\">\n");
140 printf("<TR><TD>\n");
141 }
142
start_table(void)143 static void start_table(void)
144 {
145 printf("<TABLE CELLPADDING=\"5\" CELLSPACING=\"0\" ALIGN=\"CENTER\" WIDTH=\"100%%\">\n");
146 printf("<TR><TH COLSPAN=2 BGCOLOR=\"#60B0B0\">\n");
147 printf("<FONT SIZE=\"+2\">Network UPS Tools upsset %s</FONT>\n",
148 UPS_VERSION);
149 printf("</TH></TR>\n");
150 }
151
152 /* propagate login details across pages - no cookies here! */
do_hidden(const char * next)153 static void do_hidden(const char *next)
154 {
155 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"username\" VALUE=\"%s\">\n",
156 username);
157 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"password\" VALUE=\"%s\">\n",
158 password);
159
160 if (next)
161 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"function\" VALUE=\"%s\">\n",
162 next);
163 }
164
165 /* generate SELECT chooser from hosts.conf entries */
upslist_arg(int numargs,char ** arg)166 static void upslist_arg(int numargs, char **arg)
167 {
168 if (numargs < 3)
169 return;
170
171 /* MONITOR <ups> <description> */
172 if (!strcmp(arg[0], "MONITOR")) {
173 printf("<OPTION VALUE=\"%s\"", arg[1]);
174
175 if (monups)
176 if (!strcmp(monups, arg[1]))
177 printf("SELECTED");
178
179 printf(">%s</OPTION>\n", arg[2]);
180 }
181 }
182
183 /* called for fatal errors in parseconf like malloc failures */
upsset_hosts_err(const char * errmsg)184 static void upsset_hosts_err(const char *errmsg)
185 {
186 upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg);
187 }
188
189 /* this defaults to wherever we are now, ups and function-wise */
do_pickups(const char * currfunc)190 static void do_pickups(const char *currfunc)
191 {
192 char hostfn[SMALLBUF];
193 PCONF_CTX_t ctx;
194
195 snprintf(hostfn, sizeof(hostfn), "%s/hosts.conf", confpath());
196
197 printf("<FORM METHOD=\"POST\" ACTION=\"upsset.cgi\">\n");
198
199 printf("Select UPS and function:\n<BR>\n");
200
201 pconf_init(&ctx, upsset_hosts_err);
202
203 if (!pconf_file_begin(&ctx, hostfn)) {
204 pconf_finish(&ctx);
205
206 printf("Error: hosts.conf unavailable\n");
207 printf("</FORM>\n");
208
209 /* stderr is for the admin - should wind up in error.log */
210 fprintf(stderr, "upsset: %s\n", ctx.errmsg);
211
212 return;
213 }
214
215 printf("<SELECT NAME=\"monups\">\n");
216
217 while (pconf_file_next(&ctx)) {
218 if (pconf_parse_error(&ctx)) {
219 upslogx(LOG_ERR, "Parse error: %s:%d: %s",
220 hostfn, ctx.linenum, ctx.errmsg);
221
222 continue;
223 }
224
225 upslist_arg(ctx.numargs, ctx.arglist);
226 }
227
228 pconf_finish(&ctx);
229
230 printf("</SELECT>\n");
231
232 printf("<SELECT NAME=\"function\">\n");
233
234 /* FUTURE */
235 /* printf("<OPTION VALUE=\"showstatus\">Status</OPTION>\n"); */
236
237 /* TODO: clean this up */
238
239 if (!strcmp(currfunc, "showsettings"))
240 printf("<OPTION VALUE=\"showsettings\" SELECTED>Settings</OPTION>\n");
241 else
242 printf("<OPTION VALUE=\"showsettings\">Settings</OPTION>\n");
243
244 if (!strcmp(currfunc, "showcmds"))
245 printf("<OPTION VALUE=\"showcmds\" SELECTED>Commands</OPTION>\n");
246 else
247 printf("<OPTION VALUE=\"showcmds\">Commands</OPTION>\n");
248
249 printf("</SELECT>\n");
250 do_hidden(NULL);
251
252 printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"View\">\n");
253 printf("</FORM>\n");
254 }
255
error_page(const char * next,const char * title,const char * fmt,...)256 static void error_page(const char *next, const char *title,
257 const char *fmt, ...)
258 {
259 char msg[SMALLBUF];
260 va_list ap;
261
262 va_start(ap, fmt);
263 vsnprintf(msg, sizeof(msg), fmt, ap);
264 va_end(ap);
265
266 do_header(title);
267
268 start_table();
269 printf("<TR><TH COLSPAN=2 BGCOLOR=\"#60B0B0\">\n");
270 printf("Error: %s\n", msg);
271 printf("</TH></TR>\n");
272
273 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
274 do_pickups(next);
275 printf("</TD></TR>\n");
276
277 printf("</TABLE>\n");
278 printf("</TD></TR></TABLE>\n");
279 printf("</BODY></HTML>\n");
280
281 upscli_disconnect(&ups);
282 exit(EXIT_SUCCESS);
283 }
284
loginscreen(void)285 static void loginscreen(void)
286 {
287 do_header("Login");
288 printf("<FORM METHOD=\"POST\" ACTION=\"upsset.cgi\">\n");
289 start_table();
290
291 printf("<TR BGCOLOR=\"#60B0B0\">\n");
292 printf("<TH>Username</TH>\n");
293 printf("<TD><INPUT TYPE=\"TEXT\" NAME=\"username\" VALUE=\"\"></TD>\n");
294 printf("</TR>\n");
295
296 printf("<TR BGCOLOR=\"#60B0B0\">\n");
297 printf("<TH>Password</TH>\n");
298 printf("<TD><INPUT TYPE=\"PASSWORD\" NAME=\"password\" VALUE=\"\"></TD>\n");
299 printf("</TR>\n");
300
301 printf("<TR><TD COLSPAN=2 ALIGN=\"CENTER\">\n");
302 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"function\" VALUE=\"pickups\">\n");
303 printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Login\">\n");
304 printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset fields\">\n");
305 printf("</TD></TR></TABLE>\n");
306 printf("</FORM>\n");
307 printf("</TD></TR></TABLE>\n");
308 printf("</BODY></HTML>\n");
309
310 upscli_disconnect(&ups);
311 exit(EXIT_SUCCESS);
312 }
313
314 /* try to connect to upsd - generate an error page if it fails */
upsd_connect(void)315 static void upsd_connect(void)
316 {
317 if (upscli_splitname(monups, &upsname, &hostname, &port) != 0) {
318 error_page("showsettings", "UPS name is unusable",
319 "Unable to split UPS name [%s]", monups);
320 /* NOTREACHED */
321 }
322
323 if (upscli_connect(&ups, hostname, port, 0) < 0) {
324 error_page("showsettings", "Connect failure",
325 "Unable to connect to %s: %s",
326 monups, upscli_strerror(&ups));
327 /* NOTREACHED */
328 }
329 }
330
print_cmd(const char * cmd)331 static void print_cmd(const char *cmd)
332 {
333 int ret;
334 unsigned int numq, numa;
335 char **answer;
336 const char *query[4];
337
338 query[0] = "CMDDESC";
339 query[1] = upsname;
340 query[2] = cmd;
341 numq = 3;
342
343 ret = upscli_get(&ups, numq, query, &numa, &answer);
344
345 if ((ret < 0) || (numa < numq))
346 return;
347
348 /* CMDDESC <upsname> <cmdname> <desc> */
349
350 printf("<OPTION VALUE=\"%s\">%s</OPTION>\n", cmd, answer[3]);
351 }
352
353 /* generate a list of instant commands */
showcmds(void)354 static void showcmds(void)
355 {
356 int ret;
357 unsigned int numq, numa;
358 const char *query[2];
359 char **answer;
360 struct list_t *lhead, *llast, *ltmp, *lnext;
361 char *desc;
362
363 if (!checkhost(monups, &desc))
364 error_page("showsettings", "Access denied",
365 "Access to that host is not authorized");
366
367 upsd_connect();
368
369 llast = lhead = NULL;
370
371 query[0] = "CMD";
372 query[1] = upsname;
373 numq = 2;
374
375 ret = upscli_list_start(&ups, numq, query);
376
377 if (ret < 0) {
378 fprintf(stderr, "LIST CMD %s failed: %s\n",
379 upsname, upscli_strerror(&ups));
380
381 error_page("showcmds", "Server protocol error",
382 "LIST CMD command failed");
383
384 /* NOTREACHED */
385 }
386
387 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
388
389 while (ret == 1) {
390
391 /* CMD upsname cmdname */
392 if (numa < 3) {
393 fprintf(stderr, "Error: insufficient data "
394 "(got %d args, need at least 3)\n", numa);
395
396 return;
397 }
398
399 ltmp = xmalloc(sizeof(struct list_t));
400 ltmp->name = xstrdup(answer[2]);
401 ltmp->next = NULL;
402
403 if (llast)
404 llast->next = ltmp;
405 else
406 lhead = ltmp;
407
408 llast = ltmp;
409
410 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
411 }
412
413 if (!lhead)
414 error_page("showcmds", "No instant commands supported",
415 "This UPS doesn't support any instant commands.");
416
417 do_header("Instant commands");
418 printf("<FORM ACTION=\"upsset.cgi\" METHOD=\"POST\">\n");
419 start_table();
420
421 /* include the description from checkhost() if present */
422 if (desc)
423 printf("<TR><TH BGCOLOR=\"#60B0B0\"COLSPAN=2>%s</TH></TR>\n",
424 desc);
425
426 printf("<TR BGCOLOR=\"#60B0B0\" ALIGN=\"CENTER\">\n");
427 printf("<TD>Instant commands</TD>\n");
428
429 printf("<TD>\n");
430 printf("<SELECT NAME=\"upscommand\">\n");
431
432 /* provide a dummy do-nothing default choice */
433 printf("<OPTION VALUE=\"\" SELECTED></OPTION>\n");
434
435 ltmp = lhead;
436
437 while (ltmp) {
438 lnext = ltmp->next;
439
440 print_cmd(ltmp->name);
441
442 free(ltmp->name);
443 free(ltmp);
444 ltmp = lnext;
445 }
446
447 printf("</SELECT>\n");
448 printf("</TD></TR>\n");
449
450 printf("<TR BGCOLOR=\"#60B0B0\">\n");
451 printf("<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n");
452 do_hidden("docmd");
453 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"monups\" VALUE=\"%s\">\n", monups);
454 printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Issue command\">\n");
455 printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset\">\n");
456 printf("</TD></TR>\n");
457 printf("</TABLE>\n");
458 printf("</FORM>\n");
459
460 printf("<TR><TD ALIGN=\"CENTER\">\n");
461 do_pickups("showcmds");
462 printf("</TD></TR>\n");
463
464 printf("</TABLE>\n");
465 printf("</BODY></HTML>\n");
466
467 upscli_disconnect(&ups);
468 exit(EXIT_SUCCESS);
469 }
470
471 /* handle setting authentication data in the server */
send_auth(const char * next)472 static void send_auth(const char *next)
473 {
474 char buf[SMALLBUF];
475
476 snprintf(buf, sizeof(buf), "USERNAME %s\n", username);
477
478 if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
479 fprintf(stderr, "Can't set username: %s\n",
480 upscli_strerror(&ups));
481
482 error_page(next, "Can't set username",
483 "Set username failed: %s", upscli_strerror(&ups));
484 }
485
486 if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {
487
488 /* test for old upsd that doesn't do USERNAME */
489 if (upscli_upserror(&ups) == UPSCLI_ERR_UNKCOMMAND) {
490 error_page(next, "Protocol mismatch",
491 "upsd version too old - USERNAME not supported");
492 }
493
494 error_page(next, "Can't set user name",
495 "Set user name failed: %s", upscli_strerror(&ups));
496 }
497
498 snprintf(buf, sizeof(buf), "PASSWORD %s\n", password);
499
500 if (upscli_sendline(&ups, buf, strlen(buf)) < 0)
501 error_page(next, "Can't set password",
502 "Password set failed: %s", upscli_strerror(&ups));
503
504 if (upscli_readline(&ups, buf, sizeof(buf)) < 0)
505 error_page(next, "Can't set password",
506 "Password set failed: %s", upscli_strerror(&ups));
507 }
508
docmd(void)509 static void docmd(void)
510 {
511 char buf[SMALLBUF], *desc;
512
513 if (!checkhost(monups, &desc))
514 error_page("showsettings", "Access denied",
515 "Access to that host is not authorized");
516
517 /* the user is messing with us */
518 if (!upscommand)
519 error_page("showcmds", "Form error",
520 "No instant command selected");
521
522 /* (l)user took the default blank option */
523 if (strlen(upscommand) == 0)
524 error_page("showcmds", "Form error",
525 "No instant command selected");
526
527 upsd_connect();
528
529 send_auth("showcmds");
530
531 snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, upscommand);
532
533 if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
534 do_header("Error while issuing command");
535
536 start_table();
537
538 printf("<TR><TD>Error sending command: %s\n</TD></TR>",
539 upscli_strerror(&ups));
540
541 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
542 do_pickups("showcmds");
543 printf("</TD></TR>\n");
544
545 printf("</TABLE>\n");
546
547 printf("</TD></TR></TABLE>\n");
548 printf("</BODY></HTML>\n");
549
550 upscli_disconnect(&ups);
551 exit(EXIT_SUCCESS);
552 }
553
554 if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {
555 do_header("Error while reading command response");
556
557 start_table();
558
559 printf("<TR><TD>Error reading command response: %s\n</TD></TR>",
560 upscli_strerror(&ups));
561
562 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
563 do_pickups("showcmds");
564 printf("</TD></TR>\n");
565
566 printf("</TABLE>\n");
567
568 printf("</TD></TR></TABLE>\n");
569 printf("</BODY></HTML>\n");
570
571 upscli_disconnect(&ups);
572 exit(EXIT_SUCCESS);
573 }
574
575 do_header("Issuing command");
576 start_table();
577
578 printf("<TR><TD><PRE>\n");
579 printf("Sending command: %s\n", upscommand);
580 printf("Response: %s\n", buf);
581 printf("</PRE></TD></TR>\n");
582
583 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=2>\n");
584 do_pickups("showcmds");
585 printf("</TD></TR>\n");
586
587 printf("</TABLE>\n");
588 printf("</TD></TR></TABLE>\n");
589 printf("</BODY></HTML>\n");
590
591 upscli_disconnect(&ups);
592 exit(EXIT_SUCCESS);
593 }
594
get_data(const char * type,const char * varname)595 static const char *get_data(const char *type, const char *varname)
596 {
597 int ret;
598 unsigned int numq, numa;
599 char **answer;
600 const char *query[4];
601
602 query[0] = type;
603 query[1] = upsname;
604 query[2] = varname;
605 numq = 3;
606
607 ret = upscli_get(&ups, numq, query, &numa, &answer);
608
609 if ((ret < 0) || (numa < numq))
610 return NULL;
611
612 /* <type> <upsname> <varname> <desc> */
613 return answer[3];
614 }
615
do_string(const char * varname,int maxlen)616 static void do_string(const char *varname, int maxlen)
617 {
618 const char *val;
619
620 val = get_data("VAR", varname);
621
622 if (!val) {
623 printf("Unavailable\n");
624 fprintf(stderr, "do_string: can't get current value of %s\n",
625 varname);
626 return;
627 }
628
629 printf("<INPUT TYPE=\"TEXT\" NAME=\"UPSVAR_%s\" VALUE=\"%s\" "
630 "SIZE=\"%d\">\n", varname, val, maxlen);
631 }
632
do_enum(const char * varname)633 static void do_enum(const char *varname)
634 {
635 int ret;
636 unsigned int numq, numa;
637 char **answer, *val;
638 const char *query[4], *tmp;
639
640 /* get current value */
641 tmp = get_data("VAR", varname);
642
643 if (!tmp) {
644 printf("Unavailable\n");
645 fprintf(stderr, "do_enum: can't get current value of %s\n",
646 varname);
647 return;
648 }
649
650 /* tmp is a pointer into answer - have to save it somewhere else */
651 val = xstrdup(tmp);
652
653 query[0] = "ENUM";
654 query[1] = upsname;
655 query[2] = varname;
656 numq = 3;
657
658 ret = upscli_list_start(&ups, numq, query);
659
660 if (ret < 0) {
661 printf("Unavailable\n");
662 fprintf(stderr, "Error doing ENUM %s %s: %s\n",
663 upsname, varname, upscli_strerror(&ups));
664 return;
665 }
666
667 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
668
669 printf("<SELECT NAME=\"UPSVAR_%s\">\n", varname);
670
671 while (ret == 1) {
672
673 /* ENUM <upsname> <varname> <value> */
674
675 if (numa < 4) {
676 fprintf(stderr, "Error: insufficient data "
677 "(got %d args, need at least 4)\n", numa);
678
679 free(val);
680 return;
681 }
682
683 printf("<OPTION VALUE=\"%s\" ", answer[3]);
684
685 if (!strcmp(answer[3], val))
686 printf(" SELECTED");
687
688 printf(">%s</OPTION>\n", answer[3]);
689
690 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
691 }
692
693 free(val);
694 printf("</SELECT>\n");
695 }
696
do_type(const char * varname)697 static void do_type(const char *varname)
698 {
699 int ret;
700 unsigned int i, numq, numa;
701 char **answer;
702 const char *query[4];
703
704 query[0] = "TYPE";
705 query[1] = upsname;
706 query[2] = varname;
707 numq = 3;
708
709 ret = upscli_get(&ups, numq, query, &numa, &answer);
710
711 if ((ret < 0) || (numa < numq)) {
712 printf("Unknown type\n");
713 return;
714 }
715
716 /* TYPE <upsname> <varname> <type>... */
717 for (i = 3; i < numa; i++) {
718
719 if (!strcasecmp(answer[i], "ENUM")) {
720 do_enum(varname);
721 return;
722 }
723
724 if (!strncasecmp(answer[i], "STRING:", 7)) {
725 char *ptr, len;
726
727 /* split out the :<len> data */
728 ptr = strchr(answer[i], ':');
729 *ptr++ = '\0';
730 len = strtol(ptr, (char **) NULL, 10);
731
732 do_string(varname, len);
733 return;
734 }
735
736 /* ignore this one */
737 if (!strcasecmp(answer[i], "RW"))
738 continue;
739
740 printf("Unrecognized\n");
741 }
742 }
743
print_rw(const char * upsname,const char * varname)744 static void print_rw(const char *upsname, const char *varname)
745 {
746 const char *tmp;
747
748 printf("<TR BGCOLOR=\"#60B0B0\" ALIGN=\"CENTER\">\n");
749
750 printf("<TD>");
751
752 tmp = get_data("DESC", varname);
753
754 if ((tmp) && (strcmp(tmp, "Unavailable") != 0))
755 printf("%s", tmp);
756 else
757 printf("%s", varname);
758
759 printf("</TD>\n");
760
761 printf("<TD>\n");
762 do_type(varname);
763 printf("</TD>\n");
764
765 printf("</TR>\n");
766 }
767
showsettings(void)768 static void showsettings(void)
769 {
770 int ret;
771 unsigned int numq, numa;
772 const char *query[2];
773 char **answer, *desc = NULL;
774 struct list_t *lhead, *llast, *ltmp, *lnext;
775
776 if (!checkhost(monups, &desc))
777 error_page("showsettings", "Access denied",
778 "Access to that host is not authorized");
779
780 upsd_connect();
781
782 query[0] = "RW";
783 query[1] = upsname;
784 numq = 2;
785
786 ret = upscli_list_start(&ups, numq, query);
787
788 if (ret < 0) {
789 fprintf(stderr, "LIST RW %s failed: %s\n",
790 upsname, upscli_strerror(&ups));
791
792 error_page("showsettings", "Server protocol error",
793 "LIST RW command failed");
794
795 /* NOTREACHED */
796 }
797
798 llast = lhead = NULL;
799
800 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
801
802 while (ret == 1) {
803
804 /* sock this entry away for later */
805
806 ltmp = xmalloc(sizeof(struct list_t));
807 ltmp->name = xstrdup(answer[2]);
808 ltmp->next = NULL;
809
810 if (llast)
811 llast->next = ltmp;
812 else
813 lhead = ltmp;
814
815 llast = ltmp;
816
817 ret = upscli_list_next(&ups, numq, query, &numa, &answer);
818 }
819
820 do_header("Current settings");
821 printf("<FORM ACTION=\"upsset.cgi\" METHOD=\"POST\">\n");
822 start_table();
823
824 /* include the description from checkhost() if present */
825 if (desc)
826 printf("<TR><TH BGCOLOR=\"#60B0B0\"COLSPAN=2>%s</TH></TR>\n",
827 desc);
828
829 printf("<TR BGCOLOR=\"#60B0B0\">\n");
830 printf("<TH>Setting</TH>\n");
831 printf("<TH>Value</TH></TR>\n");
832
833 /* use the list to get descriptions and types */
834
835 ltmp = lhead;
836
837 while (ltmp) {
838 lnext = ltmp->next;
839
840 print_rw(upsname, ltmp->name);
841
842 free(ltmp->name);
843 free(ltmp);
844 ltmp = lnext;
845 }
846
847 printf("<TR BGCOLOR=\"#60B0B0\">\n");
848 printf("<TD COLSPAN=\"2\" ALIGN=\"CENTER\">\n");
849 do_hidden("savesettings");
850 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"monups\" VALUE=\"%s\">\n", monups);
851 printf("<INPUT TYPE=\"SUBMIT\" VALUE=\"Save changes\">\n");
852 printf("<INPUT TYPE=\"RESET\" VALUE=\"Reset\">\n");
853 printf("</TD></TR>\n");
854 printf("</TABLE>\n");
855 printf("</FORM>\n");
856
857 printf("<TR><TD ALIGN=\"CENTER\">\n");
858 do_pickups("showsettings");
859 printf("</TD></TR>\n");
860
861 printf("</TABLE>\n");
862 printf("</BODY></HTML>\n");
863
864 upscli_disconnect(&ups);
865 exit(EXIT_SUCCESS);
866 }
867
setvar(const char * var,const char * val)868 static int setvar(const char *var, const char *val)
869 {
870 char buf[SMALLBUF], enc[SMALLBUF];
871 const char *tmp;
872
873 /* get old value */
874 tmp = get_data("VAR", var);
875
876 if (!tmp) {
877 printf("Can't get old value for %s, aborting SET\n", var);
878 return 0;
879 }
880
881 /* don't send a SET if it hasn't chnaged */
882 if (!strcmp(tmp, val))
883 return 0;
884
885 printf("set %s to %s (was %s)\n", var, val, tmp);
886
887 snprintf(buf, sizeof(buf), "SET VAR %s %s \"%s\"\n",
888 upsname, var, pconf_encode(val, enc, sizeof(enc)));
889
890 if (upscli_sendline(&ups, buf, strlen(buf)) < 0) {
891 printf("Error: SET failed: %s\n", upscli_strerror(&ups));
892 return 0;
893 }
894
895 if (upscli_readline(&ups, buf, sizeof(buf)) < 0) {
896 printf("Error: SET failed: %s\n", upscli_strerror(&ups));
897 return 0;
898 }
899
900 if (strncmp(buf, "OK", 2) != 0) {
901 printf("Unexpected response: %s\n", buf);
902 return 0;
903 }
904
905 printf("OK\n");
906 return 1;
907 }
908
909 /* turn a form submission of settings into SET commands for upsd */
savesettings(void)910 static void savesettings(void)
911 {
912 int changed = 0;
913 char *desc;
914 uvtype_t *upsvar;
915
916 if (!checkhost(monups, &desc))
917 error_page("showsettings", "Access denied",
918 "Access to that host is not authorized");
919
920 upsd_connect();
921
922 upsvar = firstuv;
923
924 send_auth("showsettings");
925
926 do_header("Saving settings");
927 start_table();
928
929 printf("<TR><TD><PRE>\n");
930
931 while (upsvar) {
932 changed += setvar(upsvar->var, upsvar->value);
933 upsvar = upsvar->next;
934 }
935
936 if (changed == 0)
937 printf("No settings changed.\n");
938 else
939 printf("Updated %d setting%s.\n",
940 changed, changed == 1 ? "" : "s");
941
942 printf("</PRE></TD></TR>\n");
943
944 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=\"2\">\n");
945 do_pickups("showsettings");
946 printf("</TD></TR>\n");
947
948 printf("</TABLE>\n");
949 printf("</TD></TR></TABLE>\n");
950 printf("</BODY></HTML>\n");
951
952 upscli_disconnect(&ups);
953 exit(EXIT_SUCCESS);
954 }
955
initial_pickups(void)956 static void initial_pickups(void)
957 {
958 do_header("Select a UPS");
959 start_table();
960
961 printf("<TR><TD ALIGN=\"CENTER\" COLSPAN=\"2\">\n");
962 do_pickups("");
963 printf("</TD></TR>\n");
964
965 printf("</TABLE>\n");
966 printf("</TD></TR></TABLE>\n");
967 printf("</BODY></HTML>\n");
968
969 upscli_disconnect(&ups);
970 exit(EXIT_SUCCESS);
971 }
972
upsset_conf_err(const char * errmsg)973 static void upsset_conf_err(const char *errmsg)
974 {
975 upslogx(LOG_ERR, "Fatal error in parseconf(upsset.conf): %s", errmsg);
976 }
977
978 /* see if the user has confirmed their cgi directory's secure state */
check_conf(void)979 static void check_conf(void)
980 {
981 char fn[SMALLBUF];
982 PCONF_CTX_t ctx;
983
984 snprintf(fn, sizeof(fn), "%s/upsset.conf", confpath());
985
986 pconf_init(&ctx, upsset_conf_err);
987
988 if (!pconf_file_begin(&ctx, fn)) {
989 pconf_finish(&ctx);
990
991 printf("<PRE>\n");
992 printf("Error: Can't open upsset.conf to verify security settings.\n");
993 printf("Refusing to start until this is fixed.\n");
994 printf("</PRE>\n");
995
996 /* leave something in the httpd log for the admin */
997 fprintf(stderr, "upsset.conf does not exist to permit execution\n");
998 exit(EXIT_FAILURE);
999 }
1000
1001 while (pconf_file_next(&ctx)) {
1002 if (pconf_parse_error(&ctx)) {
1003 upslogx(LOG_ERR, "Parse error: %s:%d: %s",
1004 fn, ctx.linenum, ctx.errmsg);
1005 continue;
1006 }
1007
1008 if (ctx.numargs < 1)
1009 continue;
1010
1011 if (!strcmp(ctx.arglist[0], MAGIC_ENABLE_STRING))
1012 magic_string_set = 1;
1013 }
1014
1015 pconf_finish(&ctx);
1016
1017 /* if we've been enabled, jump out of here and go to work */
1018 if (magic_string_set == 1)
1019 return;
1020
1021 printf("<PRE>\n");
1022 printf("Error: Secure mode has not been enabled in upsset.conf.\n");
1023 printf("Refusing to start until this is fixed.\n");
1024 printf("</PRE>\n");
1025
1026 /* leave something in the httpd log for the admin */
1027 fprintf(stderr, "upsset.conf does not permit execution\n");
1028
1029 exit(EXIT_FAILURE);
1030 }
1031
main(int argc,char ** argv)1032 int main(int argc, char **argv)
1033 {
1034 username = password = function = monups = NULL;
1035
1036 printf("Content-type: text/html\n\n");
1037
1038 /* see if the magic string is present in the config file */
1039 check_conf();
1040
1041 /* see if there's anything waiting .. the server my not close STDIN properly */
1042 if (1) {
1043 fd_set fds;
1044 struct timeval tv;
1045
1046 FD_ZERO(&fds);
1047 FD_SET(STDIN_FILENO, &fds);
1048 tv.tv_sec = 0;
1049 tv.tv_usec = 250000; /* wait for up to 250ms for a POST response */
1050 if ((select(STDIN_FILENO+1, &fds, 0, 0, &tv)) > 0)
1051 extractpostargs();
1052 }
1053 if ((!username) || (!password) || (!function))
1054 loginscreen();
1055
1056 if ((!strcmp(function, "pickups")) || (!monups))
1057 initial_pickups();
1058
1059 if (!strcmp(function, "showsettings"))
1060 showsettings();
1061
1062 if (!strcmp(function, "savesettings"))
1063 savesettings();
1064
1065 #if 0 /* FUTURE */
1066 if (!strcmp(function, "showstatus"))
1067 showstatus();
1068 #endif
1069
1070 if (!strcmp(function, "showcmds"))
1071 showcmds();
1072
1073 if (!strcmp(function, "docmd"))
1074 docmd();
1075
1076 printf("Error: Unhandled function name [%s]\n", function);
1077
1078 return 0;
1079 }
1080