1 /* user.c - user handling functions for upsd
3 Copyright (C) 2001 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
20 #include "config.h" /* must be the first header */
22 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
30 #include "parseconf.h"
33 #include "user-data.h"
35 static ulist_t
*users
= NULL
;
37 static ulist_t
*curr_user
;
39 /* create a new user entry */
40 static void user_add(const char *un
)
42 ulist_t
*tmp
, *last
= NULL
;
48 for (tmp
= users
; tmp
!= NULL
; tmp
= tmp
->next
) {
52 if (!strcmp(tmp
->username
, un
)) {
53 fprintf(stderr
, "Ignoring duplicate user %s\n", un
);
58 tmp
= xcalloc(1, sizeof(*tmp
));
59 tmp
->username
= xstrdup(un
);
67 /* remember who we're working on */
72 static void user_password(const char *pw
)
75 upslogx(LOG_WARNING
, "Ignoring password definition outside "
84 if (curr_user
->password
) {
85 fprintf(stderr
, "Ignoring duplicate password for %s\n",
90 curr_user
->password
= xstrdup(pw
);
93 /* attach allowed instcmds to user */
94 static void user_add_instcmd(const char *cmd
)
96 instcmdlist_t
*tmp
, *last
= NULL
;
99 upslogx(LOG_WARNING
, "Ignoring instcmd definition outside "
108 for (tmp
= curr_user
->firstcmd
; tmp
!= NULL
; tmp
= tmp
->next
) {
112 /* ignore duplicates */
113 if (!strcasecmp(tmp
->cmd
, cmd
)) {
118 upsdebugx(2, "user_add_instcmd: adding '%s' for %s",
119 cmd
, curr_user
->username
);
121 tmp
= xcalloc(1, sizeof(*tmp
));
123 tmp
->cmd
= xstrdup(cmd
);
128 curr_user
->firstcmd
= tmp
;
132 static actionlist_t
*addaction(actionlist_t
*base
, const char *action
)
134 actionlist_t
*tmp
, *last
= NULL
;
140 for (tmp
= base
; tmp
!= NULL
; tmp
= tmp
->next
) {
145 tmp
= xcalloc(1, sizeof(*tmp
));
146 tmp
->action
= xstrdup(action
);
156 /* attach allowed actions to user */
157 static void user_add_action(const char *act
)
160 upslogx(LOG_WARNING
, "Ignoring action definition outside "
165 upsdebugx(2, "user_add_action: adding '%s' for %s",
166 act
, curr_user
->username
);
168 curr_user
->firstaction
= addaction(curr_user
->firstaction
, act
);
171 static void flushcmd(instcmdlist_t
*ptr
)
183 static void flushaction(actionlist_t
*ptr
)
189 flushaction(ptr
->next
);
195 static void flushuser(ulist_t
*ptr
)
201 flushuser(ptr
->next
);
202 flushcmd(ptr
->firstcmd
);
203 flushaction(ptr
->firstaction
);
210 /* flush all user attributes - used during reload */
211 void user_flush(void)
217 static int user_matchinstcmd(ulist_t
*user
, const char * cmd
)
221 for (tmp
= user
->firstcmd
; tmp
!= NULL
; tmp
= tmp
->next
) {
223 if (!strcasecmp(tmp
->cmd
, cmd
)) {
227 if (!strcasecmp(tmp
->cmd
, "all")) {
235 int user_checkinstcmd(const char *un
, const char *pw
, const char *cmd
)
239 if ((!un
) || (!pw
) || (!cmd
)) {
240 return 0; /* failed */
243 for (tmp
= users
; tmp
!= NULL
; tmp
= tmp
->next
) {
245 /* let's be paranoid before we call strcmp */
247 if ((!tmp
->username
) || (!tmp
->password
)) {
251 if (strcmp(tmp
->username
, un
)) {
256 if (strcmp(tmp
->password
, pw
)) {
257 /* password mismatch */
261 if (!user_matchinstcmd(tmp
, cmd
)) {
265 /* passed all checks */
269 /* username not found */
273 static int user_matchaction(ulist_t
*user
, const char *action
)
277 for (tmp
= user
->firstaction
; tmp
!= NULL
; tmp
= tmp
->next
) {
279 if (!strcasecmp(tmp
->action
, action
)) {
287 int user_checkaction(const char *un
, const char *pw
, const char *action
)
291 if ((!un
) || (!pw
) || (!action
))
292 return 0; /* failed */
294 for (tmp
= users
; tmp
!= NULL
; tmp
= tmp
->next
) {
296 /* let's be paranoid before we call strcmp */
298 if ((!tmp
->username
) || (!tmp
->password
)) {
302 if (strcmp(tmp
->username
, un
)) {
306 if (strcmp(tmp
->password
, pw
)) {
307 upsdebugx(2, "user_checkaction: password mismatch");
311 if (!user_matchaction(tmp
, action
)) {
312 upsdebugx(2, "user_matchaction: failed");
316 /* passed all checks */
320 /* username not found */
324 /* handle "upsmon primary" and "upsmon secondary" for nicer configurations */
325 /* FIXME: Protocol update needed to handle master/primary alias (in action and in protocol) */
326 static void set_upsmon_type(char *type
)
328 /* primary: login, master, fsd */
329 if (!strcasecmp(type
, "master") || !strcasecmp(type
, "primary")) {
330 user_add_action("login");
331 user_add_action("master"); /* Note: this is linked to "MASTER" API command permission */
332 user_add_action("fsd");
336 /* secondary: just login */
337 if (!strcasecmp(type
, "slave") || !strcasecmp(type
, "secondary")) {
338 user_add_action("login");
342 upslogx(LOG_WARNING
, "Unknown upsmon type %s", type
);
345 /* actually do something with the variable + value pairs */
346 static void parse_var(char *var
, char *val
)
348 if (!strcasecmp(var
, "password")) {
353 if (!strcasecmp(var
, "instcmds")) {
354 user_add_instcmd(val
);
358 if (!strcasecmp(var
, "actions")) {
359 user_add_action(val
);
363 if (!strcasecmp(var
, "allowfrom")) {
364 upslogx(LOG_WARNING
, "allowfrom in upsd.users is no longer used");
368 /* someone did 'upsmon = type' - allow it anyway */
369 if (!strcasecmp(var
, "upsmon")) {
370 set_upsmon_type(val
);
374 upslogx(LOG_NOTICE
, "Unrecognized user setting %s", var
);
377 /* parse first var+val pair, then flip through remaining vals */
378 static void parse_rest(char *var
, char *fval
, char **arg
, size_t next
, size_t left
)
382 /* no globals supported yet, so there's no sense in continuing */
387 parse_var(var
, fval
);
393 for (i
= 0; i
< left
; i
++) {
394 parse_var(var
, arg
[next
+ i
]);
398 static void user_parse_arg(size_t numargs
, char **arg
)
402 if ((numargs
== 0) || (!arg
)) {
406 /* ignore old file format */
407 if (!strcasecmp(arg
[0], "user")) {
411 /* handle 'foo=bar' (compressed form) */
413 ep
= strchr(arg
[0], '=');
417 /* parse first var/val, plus subsequent values (if any) */
420 /* foo=bar <rest1> <rest2> ... */
422 parse_rest(arg
[0], ep
+1, arg
, 1, (numargs
< 2) ? 0 : (numargs
- 1));
426 /* look for section headers - [username] */
427 if ((arg
[0][0] == '[') && (arg
[0][strlen(arg
[0])-1] == ']')) {
429 arg
[0][strlen(arg
[0])-1] = '\0';
430 user_add(&arg
[0][1]);
439 if (!strcasecmp(arg
[0], "upsmon")) {
440 set_upsmon_type(arg
[1]);
443 /* everything after here needs arg[1] and arg[2] */
448 /* handle 'foo = bar' (split form) */
449 if (!strcmp(arg
[1], "=")) {
452 /* foo = bar <rest1> <rest2> ... */
454 /* parse first var/val, plus subsequent values (if any) */
456 parse_rest(arg
[0], arg
[2], arg
, 3, (numargs
< 4) ? 0 : (numargs
- 3));
460 /* ... unhandled ... */
463 /* called for fatal errors in parseconf like malloc failures */
464 static void upsd_user_err(const char *errmsg
)
466 upslogx(LOG_ERR
, "Fatal error in parseconf(upsd.users): %s", errmsg
);
476 snprintf(fn
, sizeof(fn
), "%s/upsd.users", confpath());
480 pconf_init(&ctx
, upsd_user_err
);
482 if (!pconf_file_begin(&ctx
, fn
)) {
486 upslogx(LOG_WARNING
, "%s", ctx
.errmsg
);
490 while (pconf_file_next(&ctx
)) {
492 if (pconf_parse_error(&ctx
)) {
493 upslogx(LOG_ERR
, "Parse error: %s:%d: %s",
494 fn
, ctx
.linenum
, ctx
.errmsg
);
498 user_parse_arg(ctx
.numargs
, ctx
.arglist
);