drivers/usbhid-ups.c: upsdrv_initups(): update comments about logical progression...
[networkupstools.git] / server / user.c
blob8ebb418ec9e5654d7755e458a4ec298a57bf2f70
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>
23 #ifndef WIN32
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #endif
29 #include "common.h"
30 #include "parseconf.h"
32 #include "user.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;
44 if (!un) {
45 return;
48 for (tmp = users; tmp != NULL; tmp = tmp->next) {
50 last = tmp;
52 if (!strcmp(tmp->username, un)) {
53 fprintf(stderr, "Ignoring duplicate user %s\n", un);
54 return;
58 tmp = xcalloc(1, sizeof(*tmp));
59 tmp->username = xstrdup(un);
61 if (last) {
62 last->next = tmp;
63 } else {
64 users = tmp;
67 /* remember who we're working on */
68 curr_user = tmp;
71 /* set password */
72 static void user_password(const char *pw)
74 if (!curr_user) {
75 upslogx(LOG_WARNING, "Ignoring password definition outside "
76 "user section");
77 return;
80 if (!pw) {
81 return;
84 if (curr_user->password) {
85 fprintf(stderr, "Ignoring duplicate password for %s\n",
86 curr_user->username);
87 return;
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;
98 if (!curr_user) {
99 upslogx(LOG_WARNING, "Ignoring instcmd definition outside "
100 "user section");
101 return;
104 if (!cmd) {
105 return;
108 for (tmp = curr_user->firstcmd; tmp != NULL; tmp = tmp->next) {
110 last = tmp;
112 /* ignore duplicates */
113 if (!strcasecmp(tmp->cmd, cmd)) {
114 return;
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);
125 if (last) {
126 last->next = tmp;
127 } else {
128 curr_user->firstcmd = tmp;
132 static actionlist_t *addaction(actionlist_t *base, const char *action)
134 actionlist_t *tmp, *last = NULL;
136 if (!action) {
137 return base;
140 for (tmp = base; tmp != NULL; tmp = tmp->next) {
142 last = tmp;
145 tmp = xcalloc(1, sizeof(*tmp));
146 tmp->action = xstrdup(action);
148 if (last) {
149 last->next = tmp;
150 return base;
153 return tmp;
156 /* attach allowed actions to user */
157 static void user_add_action(const char *act)
159 if (!curr_user) {
160 upslogx(LOG_WARNING, "Ignoring action definition outside "
161 "user section");
162 return;
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)
173 if (!ptr) {
174 return;
177 flushcmd(ptr->next);
179 free(ptr->cmd);
180 free(ptr);
183 static void flushaction(actionlist_t *ptr)
185 if (!ptr) {
186 return;
189 flushaction(ptr->next);
191 free(ptr->action);
192 free(ptr);
195 static void flushuser(ulist_t *ptr)
197 if (!ptr) {
198 return;
201 flushuser(ptr->next);
202 flushcmd(ptr->firstcmd);
203 flushaction(ptr->firstaction);
205 free(ptr->username);
206 free(ptr->password);
207 free(ptr);
210 /* flush all user attributes - used during reload */
211 void user_flush(void)
213 flushuser(users);
214 users = NULL;
217 static int user_matchinstcmd(ulist_t *user, const char * cmd)
219 instcmdlist_t *tmp;
221 for (tmp = user->firstcmd; tmp != NULL; tmp = tmp->next) {
223 if (!strcasecmp(tmp->cmd, cmd)) {
224 return 1; /* good */
227 if (!strcasecmp(tmp->cmd, "all")) {
228 return 1; /* good */
232 return 0; /* fail */
235 int user_checkinstcmd(const char *un, const char *pw, const char *cmd)
237 ulist_t *tmp;
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)) {
248 continue;
251 if (strcmp(tmp->username, un)) {
252 continue;
256 if (strcmp(tmp->password, pw)) {
257 /* password mismatch */
258 return 0; /* fail */
261 if (!user_matchinstcmd(tmp, cmd)) {
262 return 0; /* fail */
265 /* passed all checks */
266 return 1; /* good */
269 /* username not found */
270 return 0; /* fail */
273 static int user_matchaction(ulist_t *user, const char *action)
275 actionlist_t *tmp;
277 for (tmp = user->firstaction; tmp != NULL; tmp = tmp->next) {
279 if (!strcasecmp(tmp->action, action)) {
280 return 1; /* good */
284 return 0; /* fail */
287 int user_checkaction(const char *un, const char *pw, const char *action)
289 ulist_t *tmp;
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)) {
299 continue;
302 if (strcmp(tmp->username, un)) {
303 continue;
306 if (strcmp(tmp->password, pw)) {
307 upsdebugx(2, "user_checkaction: password mismatch");
308 return 0; /* fail */
311 if (!user_matchaction(tmp, action)) {
312 upsdebugx(2, "user_matchaction: failed");
313 return 0; /* fail */
316 /* passed all checks */
317 return 1; /* good */
320 /* username not found */
321 return 0; /* fail */
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");
333 return;
336 /* secondary: just login */
337 if (!strcasecmp(type, "slave") || !strcasecmp(type, "secondary")) {
338 user_add_action("login");
339 return;
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")) {
349 user_password(val);
350 return;
353 if (!strcasecmp(var, "instcmds")) {
354 user_add_instcmd(val);
355 return;
358 if (!strcasecmp(var, "actions")) {
359 user_add_action(val);
360 return;
363 if (!strcasecmp(var, "allowfrom")) {
364 upslogx(LOG_WARNING, "allowfrom in upsd.users is no longer used");
365 return;
368 /* someone did 'upsmon = type' - allow it anyway */
369 if (!strcasecmp(var, "upsmon")) {
370 set_upsmon_type(val);
371 return;
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)
380 size_t i;
382 /* no globals supported yet, so there's no sense in continuing */
383 if (!curr_user) {
384 return;
387 parse_var(var, fval);
389 if (left == 0) {
390 return;
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)
400 char *ep;
402 if ((numargs == 0) || (!arg)) {
403 return;
406 /* ignore old file format */
407 if (!strcasecmp(arg[0], "user")) {
408 return;
411 /* handle 'foo=bar' (compressed form) */
413 ep = strchr(arg[0], '=');
414 if (ep) {
415 *ep = '\0';
417 /* parse first var/val, plus subsequent values (if any) */
419 /* 0 1 2 ... */
420 /* foo=bar <rest1> <rest2> ... */
422 parse_rest(arg[0], ep+1, arg, 1, (numargs < 2) ? 0 : (numargs - 1));
423 return;
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]);
432 return;
435 if (numargs < 2) {
436 return;
439 if (!strcasecmp(arg[0], "upsmon")) {
440 set_upsmon_type(arg[1]);
443 /* everything after here needs arg[1] and arg[2] */
444 if (numargs < 3) {
445 return;
448 /* handle 'foo = bar' (split form) */
449 if (!strcmp(arg[1], "=")) {
451 /* 0 1 2 3 4 ... */
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));
457 return;
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);
469 void user_load(void)
471 char fn[SMALLBUF];
472 PCONF_CTX_t ctx;
474 curr_user = NULL;
476 snprintf(fn, sizeof(fn), "%s/upsd.users", confpath());
478 check_perms(fn);
480 pconf_init(&ctx, upsd_user_err);
482 if (!pconf_file_begin(&ctx, fn)) {
484 pconf_finish(&ctx);
486 upslogx(LOG_WARNING, "%s", ctx.errmsg);
487 return;
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);
495 continue;
498 user_parse_arg(ctx.numargs, ctx.arglist);
501 pconf_finish(&ctx);