Add homepage link.
[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 static 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 * Remove all entries from the user list.
44 *
45 * This is called on shutdown and when the user list is reloaded because the
46 * server received SIGHUP.
47 */
48 void user_list_deplete(void)
49 {
50 struct user *u, *tmpu;
51
52 list_for_each_entry_safe(u, tmpu, &user_list, node) {
53 list_del(&u->node);
54 free(u->name);
55 apc_free_pubkey(u->pubkey);
56 free(u);
57 }
58 }
59
60 /**
61 * Initialize the list of users allowed to connect to para_server.
62 *
63 * \param user_list_file The file containing access information.
64 *
65 * If this function is called for the second time, the contents of the
66 * previous call are discarded, i.e. the user list is reloaded.
67 *
68 * This function either succeeds or calls exit(3).
69 */
70 void user_list_init(const char *user_list_file)
71 {
72 int ret = -E_USERLIST;
73 FILE *file_ptr = fopen(user_list_file, "r");
74 struct user *u;
75
76 if (!file_ptr)
77 goto err;
78
79 user_list_deplete();
80 for (;;) {
81 int num;
82 char line[255];
83 /* keyword, name, key, perms */
84 char w[255], n[255], k[255], p[255], tmp[4][255];
85 struct asymmetric_key *pubkey;
86
87 ret = xfgets(line, sizeof(line), file_ptr);
88 if (ret <= 0)
89 break;
90 if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
91 continue;
92 if (strcmp(w, "user"))
93 continue;
94 PARA_DEBUG_LOG("found entry for user %s\n", n);
95 ret = apc_get_pubkey(k, &pubkey);
96 if (ret < 0) {
97 PARA_NOTICE_LOG("skipping entry for user %s: %s\n", n,
98 para_strerror(-ret));
99 continue;
100 }
101 /*
102 * In order to encrypt len := APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN
103 * bytes using RSA_public_encrypt() with EME-OAEP padding mode,
104 * RSA_size(rsa) must be greater than len + 41. So ignore keys
105 * which are too short. For details see RSA_public_encrypt(3).
106 */
107 if (ret <= APC_CHALLENGE_SIZE + 2 * SESSION_KEY_LEN + 41) {
108 PARA_WARNING_LOG("public key %s too short (%d)\n",
109 k, ret);
110 apc_free_pubkey(pubkey);
111 continue;
112 }
113 u = para_malloc(sizeof(*u));
114 u->name = para_strdup(n);
115 u->pubkey = pubkey;
116 u->perms = 0;
117 num = sscanf(p, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
118 tmp[0], tmp[1], tmp[2], tmp[3]);
119 PARA_DEBUG_LOG("found %i perm entries\n", num);
120 while (num > 0) {
121 num--;
122 if (!strcmp(tmp[num], "VSS_READ"))
123 u->perms |= VSS_READ;
124 else if (!strcmp(tmp[num], "VSS_WRITE"))
125 u->perms |= VSS_WRITE;
126 else if (!strcmp(tmp[num], "AFS_READ"))
127 u->perms |= AFS_READ;
128 else if (!strcmp(tmp[num], "AFS_WRITE"))
129 u->perms |= AFS_WRITE;
130 else /* unknown permission */
131 PARA_WARNING_LOG("ignoring unknown permission: %s\n",
132 tmp[num]);
133 }
134 para_list_add(&u->node, &user_list);
135 }
136 fclose(file_ptr);
137 if (ret >= 0)
138 return;
139 err:
140 PARA_EMERG_LOG("%s\n", para_strerror(-ret));
141 exit(EXIT_FAILURE);
142 }
143
144 /**
145 * Lookup a user in the user list.
146 *
147 * \param name The name of the user.
148 *
149 * \return A pointer to the corresponding user struct if the user was found, \p
150 * NULL otherwise.
151 */
152 const struct user *user_list_lookup(const char *name)
153 {
154 const struct user *u;
155 list_for_each_entry(u, &user_list, node) {
156 if (strcmp(u->name, name))
157 continue;
158 return u;
159 }
160 return NULL;
161 }