server: Combine user_list_init() and populate().
[paraslash.git] / user_list.c
1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file user_list.c User handling for para_server. */
4
5 #include <regex.h>
6 #include <sys/types.h>
7
8 #include "para.h"
9 #include "error.h"
10 #include "crypt.h"
11 #include "fd.h"
12 #include "string.h"
13 #include "list.h"
14 #include "user_list.h"
15
16 INITIALIZED_LIST_HEAD(user_list);
17
18 /*
19  * Wrapper for fgets(3).
20  *
21  * Unlike fgets(3), an integer value is returned. On success, this function
22  * returns 1. On errors, -E_FGETS is returned. A zero return value indicates an
23  * end of file condition.
24  */
25 static int xfgets(char *line, int size, FILE *f)
26 {
27 again:
28         if (fgets(line, size, f))
29                 return 1;
30         if (feof(f))
31                 return 0;
32         if (!ferror(f))
33                 return -E_FGETS;
34         if (errno != EINTR) {
35                 PARA_ERROR_LOG("%s\n", strerror(errno));
36                 return -E_FGETS;
37         }
38         clearerr(f);
39         goto again;
40 }
41
42 /**
43  * Initialize the list of users allowed to connect to para_server.
44  *
45  * \param user_list_file The file containing access information.
46  *
47  * If this function is called for the second time, the contents of the
48  * previous call are discarded, i.e. the user list is reloaded.
49  *
50  * This function either succeeds or calls exit(3).
51  */
52 void user_list_init(char *user_list_file)
53 {
54         int ret = -E_USERLIST;
55         FILE *file_ptr = fopen(user_list_file, "r");
56         struct user *u, *tmpu;
57
58         if (!file_ptr)
59                 goto err;
60
61         list_for_each_entry_safe(u, tmpu, &user_list, node) {
62                 list_del(&u->node);
63                 free(u->name);
64                 free_public_key(u->pubkey);
65                 free(u);
66         }
67         for (;;) {
68                 int num;
69                 char line[255];
70                 /* keyword, name, key, perms */
71                 char w[255], n[255], k[255], p[255], tmp[4][255];
72                 struct asymmetric_key *pubkey;
73
74                 ret = xfgets(line, sizeof(line), file_ptr);
75                 if (ret <= 0)
76                         break;
77                 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
78                         continue;
79                 if (strcmp(w, "user"))
80                         continue;
81                 PARA_DEBUG_LOG("found entry for user %s\n", n);
82                 ret = get_public_key(k, &pubkey);
83                 if (ret < 0) {
84                         PARA_NOTICE_LOG("skipping entry for user %s: %s\n", n,
85                                 para_strerror(-ret));
86                         continue;
87                 }
88                 /*
89                  * In order to encrypt len := CHALLENGE_SIZE + 2 * SESSION_KEY_LEN
90                  * bytes using RSA_public_encrypt() with EME-OAEP padding mode,
91                  * RSA_size(rsa) must be greater than len + 41. So ignore keys
92                  * which are too short. For details see RSA_public_encrypt(3).
93                  */
94                 if (ret <= CHALLENGE_SIZE + 2 * SESSION_KEY_LEN + 41) {
95                         PARA_WARNING_LOG("public key %s too short (%d)\n",
96                                 k, ret);
97                         free_public_key(pubkey);
98                         continue;
99                 }
100                 u = para_malloc(sizeof(*u));
101                 u->name = para_strdup(n);
102                 u->pubkey = pubkey;
103                 u->perms = 0;
104                 num = sscanf(p, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
105                         tmp[0], tmp[1], tmp[2], tmp[3]);
106                 PARA_DEBUG_LOG("found %i perm entries\n", num);
107                 while (num > 0) {
108                         num--;
109                         if (!strcmp(tmp[num], "VSS_READ"))
110                                 u->perms |= VSS_READ;
111                         else if (!strcmp(tmp[num], "VSS_WRITE"))
112                                 u->perms |= VSS_WRITE;
113                         else if (!strcmp(tmp[num], "AFS_READ"))
114                                 u->perms |= AFS_READ;
115                         else if (!strcmp(tmp[num], "AFS_WRITE"))
116                                 u->perms |= AFS_WRITE;
117                         else /* unknown permission */
118                                 PARA_WARNING_LOG("ignoring unknown permission: %s\n",
119                                         tmp[num]);
120                 }
121                 para_list_add(&u->node, &user_list);
122         }
123         fclose(file_ptr);
124         if (ret >= 0)
125                 return;
126 err:
127         PARA_EMERG_LOG("%s\n", para_strerror(-ret));
128         exit(EXIT_FAILURE);
129 }
130
131 /**
132  * Lookup a user in the user list.
133  *
134  * \param name The name of the user.
135  *
136  * \return A pointer to the corresponding user struct if the user was found, \p
137  * NULL otherwise.
138  */
139 const struct user *user_list_lookup(const char *name)
140 {
141         const struct user *u;
142         list_for_each_entry(u, &user_list, node) {
143                 if (strcmp(u->name, name))
144                         continue;
145                 return u;
146         }
147         return NULL;
148 }