1
/* oldnet.c - old network command handlers for upsd
3
Copyright (C) 2003 Russell Kroll <rkroll@exploits.org>
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.
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.
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
26
#include "shared-tables.h"
27
#include "shared-tables-init.h"
32
#include "var-map-init.h"
34
#include "cmd-map-init.h"
36
/* everything in here is for compatibility with old clients */
38
extern upstype *firstups;
40
/* parse varname[@upsname] into separate variables */
41
upstype *parsearg(const char *arg, char **varname)
43
char *argtmp, *upsname;
46
argtmp = xstrdup(arg);
48
upsname = strchr(argtmp, '@');
51
ups = findups(upsname);
56
/* varname may be a subset of argtmp, so copy it and free argtmp */
57
*varname = xstrdup(argtmp);
63
static const char *oldvar_to_new(const char *old)
66
static char temphex[8];
68
/* first look up the type number in netvars */
69
for (i = 0; netvars[i].name != NULL; i++)
70
if (!strcasecmp(netvars[i].name, old))
71
type = netvars[i].type;
76
for (i = 0; var_map[i].type != 0; i++)
77
if (var_map[i].type == type)
78
return var_map[i].name;
80
/* not there - convert to the hex hack for now */
81
snprintf(temphex, sizeof(temphex), "%04X", type);
85
static const char *oldcmd_to_new(const char *old)
88
static char temphex[8];
90
/* first look up the type number in instcmds[] */
91
for (i = 0; instcmds[i].name != NULL; i++)
92
if (!strcasecmp(instcmds[i].name, old))
93
cmd = instcmds[i].cmd;
98
for (i = 0; cmd_map[i].cmd != 0; i++)
99
if (cmd_map[i].cmd == cmd)
100
return cmd_map[i].name;
102
/* not there - convert to the hex hack for now */
103
snprintf(temphex, sizeof(temphex), "%04X", cmd);
107
/* handler for "REQ" - send a reply */
108
void do_sendans(ctype *client, char *varin, char *rest)
113
const char *tempvar, *tempval;
116
send_err(client, NUT_ERR_MISSING_ARGUMENT);
120
ups = parsearg(varin, &varname);
123
send_err(client, NUT_ERR_UNKNOWN_UPS);
128
/* special case: numlogins is an internal value */
129
if (!strcasecmp(varname, "NUMLOGINS")) {
130
sendback(client, "ANS %s %d\n", varname, ups->numlogins);
135
/* make sure this thing is still with us */
136
if (!ups_available(ups, client)) {
141
tempvar = oldvar_to_new(varname);
144
/* type wasn't resolved in the netvars[] array */
146
send_err(client, NUT_ERR_VAR_UNKNOWN);
150
/* make sure this thing is still with us */
151
if (!ups_available(ups, client))
154
tempval = sstate_getinfo(ups, tempvar, 1);
157
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
161
/* special case - make FSD show up in STATUS */
162
if (!strcasecmp(tempvar, "ups.status") && (ups->fsd == 1))
163
sendback(client, "ANS %s FSD %s\n", varin, tempval);
165
sendback(client, "ANS %s %s\n", varin, tempval);
168
/* handler for "LISTVARS" */
169
void do_listvars(ctype *client, char *arg, char *rest)
177
send_err(client, NUT_ERR_UNKNOWN_UPS);
181
/* make sure this thing is still with us */
182
if (!ups_available(ups, client))
185
memset(ans, '\0', sizeof(ans));
187
/* insert "@upsname" if explicitly specified in request */
188
if ((arg) && (strcmp(arg, "") != 0))
189
snprintf(ans, sizeof(ans), " @%s", arg);
191
sstate_makeinfolist(ups, ans, sizeof(ans));
193
sendback(client, "VARS%s\n", ans);
196
/* handler for "LISTRW" */
197
void do_listrw(ctype *client, char *arg, char *rest)
205
send_err(client, NUT_ERR_UNKNOWN_UPS);
209
/* make sure this thing is still with us */
210
if (!ups_available(ups, client))
215
/* insert "@upsname" if explicitly specified in request */
216
if ((arg) && (strcmp(arg, "") != 0)) {
217
snprintfcat(ans, sizeof(ans), " @%s", arg);
220
sstate_makerwlist(ups, ans, sizeof(ans));
222
sendback(client, "RW%s\n", ans);
225
/* handler for "VARTYPE" */
226
void do_vartype(ctype *client, char *arg, char *rest)
233
const struct enum_t *etmp;
236
send_err(client, NUT_ERR_MISSING_ARGUMENT);
240
ups = parsearg(arg, &varname);
243
send_err(client, NUT_ERR_UNKNOWN_UPS);
248
tempvar = oldvar_to_new(varname);
252
send_err(client, NUT_ERR_VAR_UNKNOWN);
256
flags = sstate_getflags(ups, tempvar);
258
/* see if this variable even exists */
260
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
264
/* maybe it's a string */
265
if (flags & ST_FLAG_STRING) {
266
sendback(client, "TYPE STRING %d\n", sstate_getaux(ups, tempvar));
270
/* maybe it's an enum */
271
etmp = sstate_getenumlist(ups, tempvar);
280
sendback(client, "TYPE ENUM %d\n", ecount);
285
send_err(client, NUT_ERR_UNKNOWN_TYPE);
288
/* handler for "VARDESC" */
289
void do_vardesc(ctype *client, char *arg, char *rest)
293
/* find the variable type for the name */
294
for (i = 0; netvars[i].name != NULL; i++) {
295
if (!strcasecmp(netvars[i].name, arg)) {
296
sendback(client, "DESC \"%s\"\n", netvars[i].desc);
301
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
304
/* handler for "ENUM" */
305
void do_enum(ctype *client, char *arg, char *rest)
311
const char *tempvar, *tempval;
312
const struct enum_t *etmp;
315
send_err(client, NUT_ERR_MISSING_ARGUMENT);
319
ups = parsearg(arg, &varname);
322
send_err(client, NUT_ERR_UNKNOWN_UPS);
329
/* find the variable type for the name */
330
for (i = 0; netvars[i].name != NULL; i++)
331
if (!strcasecmp(netvars[i].name, varname))
332
type = netvars[i].type;
334
if (type == 0) { /* didn't find it */
335
send_err(client, NUT_ERR_UNKNOWN_TYPE);
340
tempvar = oldvar_to_new(varname);
344
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
348
/* see if this variable even exists first */
349
tempval = sstate_getinfo(ups, tempvar, 1);
352
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
356
/* bail out here if the write fails */
357
if (!sendback(client, "ENUM %s\n", varname))
360
etmp = sstate_getenumlist(ups, tempvar);
365
if (!strcmp(etmp->val, tempval))
366
snprintf(resp, sizeof(resp), "OPTION \"%s\" SELECTED",
369
snprintf(resp, sizeof(resp), "OPTION \"%s\"",
372
if (!sendback(client, "%s\n", resp))
378
sendback(client, "END\n");
381
/* handler for "SET" */
382
void do_set(ctype *client, char *arg, char *rest)
384
char *newval, *varname, *ptr;
388
char cmd[SMALLBUF], esc[SMALLBUF];
389
const char *tempvar, *tempval;
390
const struct enum_t *etmp;
392
if ((arg == NULL) || (rest == NULL)) {
393
send_err(client, NUT_ERR_MISSING_ARGUMENT);
397
ups = parsearg(arg, &varname);
400
send_err(client, NUT_ERR_UNKNOWN_UPS);
406
/* make sure 'varname' is part of the protocol as we know it */
407
for (i = 0; netvars[i].name != NULL; i++)
408
if (!strcasecmp(netvars[i].name, varname))
409
type = netvars[i].type;
411
/* type wasn't resolved in the netvars[] array */
413
send_err(client, NUT_ERR_VAR_UNKNOWN);
418
/* make sure this thing is still with us */
419
if (!ups_available(ups, client)) {
424
tempvar = oldvar_to_new(varname);
427
/* not resolved in netvars[] */
429
send_err(client, NUT_ERR_VAR_UNKNOWN);
433
/* see if this UPS supports that variable */
434
tempval = sstate_getinfo(ups, tempvar, 1);
437
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
441
/* make sure this variable is writable (RW) */
442
if ((sstate_getflags(ups, tempvar) & ST_FLAG_RW) == 0) {
443
send_err(client, NUT_ERR_READONLY);
447
/* clean up rest into something usable */
448
newval = xstrdup(rest);
450
ptr = strchr(newval, 13);
452
*ptr = '\0'; /* strip trailing CR */
454
ptr = strchr(newval, 10);
456
*ptr = '\0'; /* strip trailing LF */
458
/* finally, see if the new value is allowed for this variable */
460
/* check the length if this is for a string */
461
if (sstate_getflags(ups, tempvar) & ST_FLAG_STRING) {
462
if (strlen(newval) > sstate_getaux(ups, tempvar)) {
463
send_err(client, NUT_ERR_TOO_LONG);
469
/* see if it's enumerated */
470
etmp = sstate_getenumlist(ups, tempvar);
475
/* make sure this value is supported */
478
if (!strcmp(etmp->val, newval)) {
487
send_err(client, NUT_ERR_INVALID_VALUE);
493
upslogx(LOG_INFO, "Set variable: %s@%s set %s on %s to %s",
494
client->username, client->addr, varname, ups->name,
497
snprintf(cmd, sizeof(cmd), "SET %s \"%s\"\n",
498
tempvar, pconf_encode(newval, esc, sizeof(esc)));
502
if (!sstate_sendline(ups, cmd)) {
503
upslogx(LOG_INFO, "Set command send failed");
504
send_err(client, NUT_ERR_SET_FAILED);
508
sendback(client, "OK\n");
511
/* handler for "INSTCMD" */
512
void do_instcmd(ctype *client, char *arg, char *rest)
518
char sockcmd[SMALLBUF];
520
const struct cmdlist_t *ctmp;
523
send_err(client, NUT_ERR_MISSING_ARGUMENT);
527
ups = parsearg(arg, &cmdname);
530
send_err(client, NUT_ERR_UNKNOWN_UPS);
535
tempcn = oldcmd_to_new(cmdname);
539
send_err(client, NUT_ERR_UNKNOWN_INSTCMD);
543
/* now make sure the UPS can actually DO this command */
545
ctmp = sstate_getcmdlist(ups);
549
if (!strcasecmp(ctmp->name, tempcn)) {
558
send_err(client, NUT_ERR_CMD_NOT_SUPPORTED);
562
/* see if this user is allowed to do this command */
563
if (!user_checkinstcmd(&client->sock, client->username,
564
client->password, tempcn)) {
565
send_err(client, NUT_ERR_ACCESS_DENIED);
569
upslogx(LOG_INFO, "Instant command: %s@%s did %s on %s",
570
client->username, client->addr, cmdname,
573
snprintf(sockcmd, sizeof(sockcmd), "INSTCMD %s\n", tempcn);
575
if (!sstate_sendline(ups, sockcmd)) {
576
upslogx(LOG_INFO, "Set command send failed");
577
send_err(client, NUT_ERR_INSTCMD_FAILED);
581
sendback(client, "OK\n");
584
/* handler for "LISTINSTCMD" */
585
void do_listinstcmd(ctype *client, char *arg, char *rest)
593
send_err(client, NUT_ERR_UNKNOWN_UPS);
597
/* make sure this thing is still with us */
598
if (!ups_available(ups, client))
603
/* insert "@upsname" if explicitly specified in request */
604
if ((arg) && (strcmp(arg, "") != 0))
605
snprintfcat(ans, sizeof(ans), " @%s", arg);
607
sstate_makeinstcmdlist(ups, ans, sizeof(ans));
609
sendback(client, "INSTCMDS%s\n", ans);
612
/* handler for "INSTCMDDESC" */
613
void do_instcmddesc(ctype *client, char *arg, char *rest)
618
send_err(client, NUT_ERR_MISSING_ARGUMENT);
622
/* find the variable type for the name */
623
for (i = 0; instcmds[i].name != NULL; i++) {
624
if (!strcasecmp(instcmds[i].name, arg)) {
625
sendback(client, "DESC \"%s\"\n", instcmds[i].desc);
630
send_err(client, NUT_ERR_CMD_NOT_SUPPORTED);