play: New option: --end-of-playlist.
[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 }