move LOAD_PUBLIC_KEY and LOAD_PRIVATE_KEY to crypt.h
[paraslash.git] / server.c
index bcb43a20e610d275294447b4fc4728f8caaece78..7d7953215b7a8a0c7a52bc1c0c39d3eb432d54ef 100644 (file)
--- a/server.c
+++ b/server.c
@@ -42,6 +42,7 @@
 #include "string.h"
 #include "ipc.h"
 #include "fd.h"
+#include "crypt.h"
 
 /** define the array of error lists needed by para_server */
 INIT_SERVER_ERRLISTS;
@@ -56,13 +57,14 @@ struct misc_meta_data *mmd;
  * It also contains the options for all audio file selectors and all supported
  * senders.
 */
-struct gengetopt_args_info conf;
-char *user_list = NULL;
+struct server_args_info conf;
+char *user_list_file = NULL;
+struct list_head user_list;
 extern void dccp_send_init(struct sender *);
 extern void http_send_init(struct sender *);
 extern void ortp_send_init(struct sender *);
-extern struct audio_format afl[];
 
+/* TODO: This is better handled by autoconf */
 /** the list of supported audio file selectors */
 struct audio_file_selector selectors[] = {
        {
@@ -221,11 +223,11 @@ static void parse_config(int override)
                cf = conf.config_file_arg;
        else
                cf = make_message("%s/.paraslash/server.conf", home);
-       free(user_list);
+       free(user_list_file);
        if (!conf.user_list_given)
-               user_list = make_message("%s/.paraslash/server.users", home);
+               user_list_file = make_message("%s/.paraslash/server.users", home);
        else
-               user_list = para_strdup(conf.user_list_arg);
+               user_list_file = para_strdup(conf.user_list_arg);
        ret = stat(cf, &statbuf);
        if (ret && conf.config_file_given) {
                ret = -1;
@@ -234,7 +236,7 @@ static void parse_config(int override)
        }
        if (!ret) {
                int tmp = conf.daemon_given;
-               cmdline_parser_configfile(cf, &conf, override, 0, 0);
+               server_cmdline_parser_configfile(cf, &conf, override, 0, 0);
                conf.daemon_given = tmp;
        }
        /* logfile */
@@ -251,8 +253,8 @@ out:
        free(home);
        if (ret > 0)
                return;
-       free(user_list);
-       user_list = NULL;
+       free(user_list_file);
+       user_list_file = NULL;
        exit(EXIT_FAILURE);
 }
 
@@ -274,6 +276,110 @@ static void setup_signal_handling(void)
        }
 }
 
+/*
+ * lookup user in user list file. Fills in a user struct containing
+ * filename of the user's public key as well as the permissions of that user.
+ * Returns 1 on success, 0 if user does not exist and < 0 on errors.
+ */
+static void populate_user_list(void) {
+       FILE *file_ptr = NULL;
+       char *char_ptr;
+       char line[MAXLINE];
+       /* keyword, user, key, perms */
+       char w[MAXLINE], n[MAXLINE], k[MAXLINE], p[MAXLINE], tmp[4][MAXLINE];
+       int num, ret;
+
+       file_ptr = fopen(user_list_file, "r");
+       ret = -E_USERLIST;
+       if (!file_ptr)
+               goto out;
+       for (;;) {
+               struct user *u;
+               ret = para_fgets(line, MAXLINE, file_ptr);
+               if (ret < 0)
+                       PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+               if (ret <= 0)
+                       break;
+               if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3)
+                       continue;
+               if (strcmp(w, "user"))
+                       continue;
+               PARA_DEBUG_LOG("found entry for %s\n", n);
+               u = para_malloc(sizeof(struct user));
+               u->name = para_strdup(n);
+               u->rsa = para_malloc(sizeof(RSA));
+               ret = get_rsa_key(k, &u->rsa, LOAD_PUBLIC_KEY);
+               if (ret < 0)
+                       break;
+               u->perms = 0;
+               char_ptr = p;
+               num = sscanf(char_ptr, "%200[A-Z_],%200[A-Z_],%200[A-Z_],%200[A-Z_]",
+                       tmp[0], tmp[1], tmp[2], tmp[3]);
+               PARA_DEBUG_LOG("found %i perm entries\n", num);
+               u->perms = 0;
+               while (num > 0) {
+                       num--;
+                       if (!strcmp(tmp[num], "AFS_READ"))
+                               u->perms |= AFS_READ;
+                       else if (!strcmp(tmp[num], "AFS_WRITE"))
+                               u->perms |= AFS_WRITE;
+                       else if (!strcmp(tmp[num], "DB_READ"))
+                               u->perms |= DB_READ;
+                       else if (!strcmp(tmp[num], "DB_WRITE"))
+                               u->perms |= DB_WRITE;
+                       else /* unknown permission */
+                               PARA_WARNING_LOG("unknown permission: %s\n",
+                                       tmp[num]);
+               }
+               para_list_add(&u->node, &user_list);
+       }
+out:
+       if (file_ptr)
+               fclose(file_ptr);
+       if (ret >= 0)
+               return;
+       PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
+       exit(EXIT_FAILURE);
+}
+
+static void init_user_list(void)
+{
+       struct user *u, *tmp;
+       static int initialized;
+
+       if (initialized) {
+               list_for_each_entry_safe(u, tmp, &user_list, node) {
+                       list_del(&u->node);
+                       free(u->name);
+                       free(u->rsa);
+                       free(u);
+               }
+       } else
+               INIT_LIST_HEAD(&user_list);
+       initialized = 1;
+       populate_user_list();
+}
+
+/**
+ * lookup user in user_list.
+ *
+ * \param user: must initially contain the name of the user and is filled
+ * in by this function on success.
+ *
+ * \return 1 on success and < 0 on errors.
+ */
+int get_user(struct user *user)
+{
+       struct user *u;
+       list_for_each_entry(u, &user_list, node) {
+               if (strcmp(u->name, user->name))
+                       continue;
+               *user = *u;
+               return 1;
+       }
+       return -E_BAD_USER;
+}
+
 static void init_selector(void)
 {
        int i, ret;
@@ -302,11 +408,18 @@ random:
 
 static unsigned init_network(void)
 {
-       int sockfd = init_tcp_socket(conf.port_arg);
+       int fd, ret = init_tcp_socket(conf.port_arg);
 
-       if (sockfd < 0)
-               exit(EXIT_FAILURE);
-       return sockfd;
+       if (ret < 0)
+               goto err;
+       fd = ret;
+       ret = mark_fd_nonblock(fd);
+       if (ret < 0)
+               goto err;
+       return fd;
+err:
+       PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
+       exit(EXIT_FAILURE);
 }
 
 static void init_random_seed(void)
@@ -339,13 +452,14 @@ static unsigned do_inits(int argc, char **argv)
 
        init_random_seed();
        /* parse command line options */
-       cmdline_parser(argc, argv, &conf);
+       server_cmdline_parser(argc, argv, &conf);
        para_drop_privileges(conf.user_arg, conf.group_arg);
        /* parse config file, open log and set defaults */
        parse_config(0);
        log_welcome("para_server", conf.loglevel_arg);
        shm_init(); /* init mmd struct */
        server_uptime(UPTIME_SET); /* reset server uptime */
+       init_user_list();
        /* become daemon */
        if (conf.daemon_given)
                daemon_init();
@@ -359,10 +473,6 @@ static unsigned do_inits(int argc, char **argv)
        /* init network socket */
        PARA_NOTICE_LOG("%s", "initializing tcp command socket\n");
        sockfd = init_network();
-       if (conf.autoplay_given) {
-               mmd->afs_status_flags |= AFS_PLAYING;
-               mmd->new_afs_status_flags |= AFS_PLAYING;
-       }
        PARA_NOTICE_LOG("%s", "init complete\n");
        return sockfd;
 }
@@ -436,14 +546,12 @@ int main(int argc, char *argv[])
        valid_fd_012();
        sockfd = do_inits(argc, argv);
 repeat:
-       /* check socket and signal pipe in any case */
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
-       FD_SET(sockfd, &rfds);
-       max_fileno = sockfd;
-       FD_SET(signal_pipe, &rfds);
-       max_fileno = MAX(max_fileno, signal_pipe);
-
+       max_fileno = -1;
+       /* check socket and signal pipe in any case */
+       para_fd_set(sockfd, &rfds, &max_fileno);
+       para_fd_set(signal_pipe, &rfds, &max_fileno);
        timeout = afs_preselect();
        status_refresh();
        for (i = 0; senders[i].name; i++) {
@@ -451,14 +559,11 @@ repeat:
                        continue;
                if (!senders[i].pre_select)
                        continue;
-               senders[i].pre_select(mmd->audio_format >= 0?
-                       &afl[mmd->audio_format] : NULL,
-                       &max_fileno,
-                       &rfds, &wfds);
+               senders[i].pre_select( &max_fileno, &rfds, &wfds);
        }
        if (selectors[mmd->selector_num].pre_select) {
                ret = selectors[mmd->selector_num].pre_select(&rfds, &wfds);
-               max_fileno = MAX(max_fileno, ret);
+               max_fileno = PARA_MAX(max_fileno, ret);
        }
        mmd_unlock();
        ret = para_select(max_fileno + 1, &rfds, &wfds, timeout);
@@ -474,14 +579,10 @@ repeat:
                        continue;
                if (!senders[i].post_select)
                        continue;
-               senders[i].post_select(mmd->audio_format >= 0?
-                       &afl[mmd->audio_format] : NULL,
-                       &rfds, &wfds);
-       }
-       if (!ret) {
-               afs_send_chunk();
-               status_refresh();
+               senders[i].post_select(&rfds, &wfds);
        }
+       afs_send_chunk();
+       status_refresh();
        if (FD_ISSET(signal_pipe, &rfds)) {
                int sig;
                sig = para_next_signal();