Make local sockets world-readable.
[paraslash.git] / client_common.c
index 3ff43d1b7bffd2c1c2438078d431122ea9f6942d..cd1ccc619ce06710d9fad42652d6868942fc17d8 100644 (file)
@@ -1,19 +1,23 @@
 /*
- * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
 /** \file client_common.c Common functions of para_client and para_audiod. */
 
+#include <netinet/in.h>
+#include <sys/socket.h>
 #include <regex.h>
 #include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netdb.h>
 
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "sched.h"
-#include "client.cmdline.h"
 #include "crypt.h"
 #include "net.h"
 #include "fd.h"
 #include "client.h"
 #include "buffer_tree.h"
 #include "version.h"
+#include "ggo.h"
 
 /** The size of the receiving buffer. */
 #define CLIENT_BUFSIZE 4000
 
-/**
- * Close the connection to para_server and deallocate per-command ressources.
- *
- * \param ct The client task.
- *
- * This frees all ressources of the current command but keeps the configuration
- * in \p ct->conf.
- *
- * \sa \ref client_close().
- */
-void client_disconnect(struct client_task *ct)
-{
-       if (!ct)
-               return;
-       if (ct->scc.fd >= 0)
-               close(ct->scc.fd);
-       free_argv(ct->features);
-       ct->features = NULL;
-       sc_free(ct->scc.recv);
-       ct->scc.recv = NULL;
-       sc_free(ct->scc.send);
-       ct->scc.send = NULL;
-       btr_remove_node(&ct->btrn[0]);
-       btr_remove_node(&ct->btrn[1]);
-}
-
 /**
  * Close the connection to para_server and free all resources.
  *
  * \param ct Pointer to the client data.
  *
- * \sa \ref client_open(), \ref client_disconnect().
+ * \sa \ref client_open().
  */
 void client_close(struct client_task *ct)
 {
        if (!ct)
                return;
-       client_disconnect(ct);
        free(ct->user);
        free(ct->config_file);
        free(ct->key_file);
@@ -75,24 +53,19 @@ void client_close(struct client_task *ct)
        free(ct);
 }
 
-/**
+/*
  * The preselect hook for server commands.
  *
- * \param s Pointer to the scheduler.
- * \param t Pointer to the task struct for this command.
- *
  * The task pointer must contain a pointer to the initialized client data
  * structure as it is returned by client_open().
  *
  * This function checks the state of the connection and adds the file descriptor
- * of the connection to the read or write fd set of \a s accordingly.
- *
- * \sa register_task() client_open(), struct sched, struct task.
+ * of the connection to the read or write fd set of s accordingly.
  */
-static void client_pre_select(struct sched *s, struct task *t)
+static void client_pre_select(struct sched *s, void *context)
 {
        int ret;
-       struct client_task *ct = container_of(t, struct client_task, task);
+       struct client_task *ct = context;
 
        if (ct->scc.fd < 0)
                return;
@@ -186,7 +159,10 @@ again:
        }
        if (n == 0)
                return 0;
-       if (!sb_received(ct->sbc[0], n, result))
+       ret = sb_received(ct->sbc[0], n, result);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
                goto again;
        ct->sbc[0] = NULL;
        return 1;
@@ -290,31 +266,26 @@ static int send_sb_command(struct client_task *ct)
        return send_sb(ct, 0, command, len, SBD_COMMAND, false);
 }
 
-/**
+/*
  * The post select hook for client commands.
  *
- * \param s Pointer to the scheduler.
- * \param t Pointer to the task struct for this command.
- *
  * Depending on the current state of the connection and the status of the read
- * and write fd sets of \a s, this function performs the necessary steps to
- * authenticate the connection, to send the command given by \a t->private_data
+ * and write fd sets of s, this function performs the necessary steps to
+ * authenticate the connection, to send the command given by t->private_data
  * and to receive para_server's output, if any.
- *
- * \sa struct sched, struct task.
  */
-static void client_post_select(struct sched *s, struct task *t)
+static int client_post_select(struct sched *s, void *context)
 {
-       struct client_task *ct = container_of(t, struct client_task, task);
+       struct client_task *ct = context;
        int ret = 0;
        size_t n;
        char buf[CLIENT_BUFSIZE];
 
-       ret = task_get_notification(t);
+       ret = task_get_notification(ct->task);
        if (ret < 0)
                goto out;
        if (ct->scc.fd < 0)
-               return;
+               return 0;
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
                ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
@@ -327,17 +298,18 @@ static void client_post_select(struct sched *s, struct task *t)
                        goto out;
                }
                ct->status = CL_RECEIVED_WELCOME;
-               return;
+               return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return;
-               sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
+                       return 0;
+               sprintf(buf, AUTH_REQUEST_MSG "%s sideband%s", ct->user,
+                       has_feature("aes_ctr128", ct)? ",aes_ctr128" : "");
                PARA_INFO_LOG("--> %s\n", buf);
                ret = write_buffer(ct->scc.fd, buf);
                if (ret < 0)
                        goto out;
                ct->status = CL_SENT_AUTH;
-               return;
+               return 0;
        case CL_SENT_AUTH:
                /*
                 * Receive challenge and session keys, decrypt the challenge and
@@ -347,6 +319,7 @@ static void client_post_select(struct sched *s, struct task *t)
                /* decrypted challenge/session key buffer */
                unsigned char crypt_buf[1024];
                struct sb_buffer sbb;
+               bool use_aes;
 
                ret = recv_sb(ct, &s->rfds, &sbb);
                if (ret <= 0)
@@ -365,13 +338,14 @@ static void client_post_select(struct sched *s, struct task *t)
                        goto out;
                ct->challenge_hash = para_malloc(HASH_SIZE);
                hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
-               ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
+               use_aes = has_feature("aes_ctr128", ct);
+               ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN, use_aes);
                ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
-                       SESSION_KEY_LEN);
+                       SESSION_KEY_LEN, use_aes);
                hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
-               return;
+               return 0;
                }
        case CL_RECEIVED_CHALLENGE:
                ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
@@ -398,12 +372,12 @@ static void client_post_select(struct sched *s, struct task *t)
        case CL_RECEIVED_PROCEED: /* concat args and send command */
                {
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return;
+                       return 0;
                ret = send_sb_command(ct);
                if (ret <= 0)
                        goto out;
                ct->status = CL_EXECUTING;
-               return;
+               return 0;
                }
        case CL_SENDING:
                if (ct->btrn[1]) {
@@ -429,7 +403,7 @@ static void client_post_select(struct sched *s, struct task *t)
                                        btr_consume(ct->btrn[1], sz);
                        }
                }
-               /* fall though */
+               /* fall through */
        case CL_EXECUTING:
                if (ct->btrn[0]) {
                        ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
@@ -454,21 +428,31 @@ close1:
        PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret));
        btr_remove_node(&ct->btrn[1]);
        if (ct->btrn[0])
-               return;
+               return 0;
        goto out;
 close0:
        PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret));
        btr_remove_node(&ct->btrn[0]);
        if (ct->btrn[1] && ct->status == CL_SENDING)
-               return;
+               return 0;
 out:
        if (ret >= 0)
-               return;
+               return 0;
        btr_remove_node(&ct->btrn[0]);
        btr_remove_node(&ct->btrn[1]);
        if (ret != -E_SERVER_CMD_SUCCESS && ret != -E_SERVER_CMD_FAILURE)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-       t->error = ret;
+       if (ct->scc.fd >= 0) {
+               close(ct->scc.fd);
+               ct->scc.fd = -1;
+       }
+       free_argv(ct->features);
+       ct->features = NULL;
+       sc_free(ct->scc.recv);
+       ct->scc.recv = NULL;
+       sc_free(ct->scc.send);
+       ct->scc.send = NULL;
+       return ret;
 }
 
 /**
@@ -505,11 +489,13 @@ int client_connect(struct client_task *ct, struct sched *s,
                EMBRACE(.name = "client recv", .parent = NULL, .child = child));
        ct->btrn[1] = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "client send", .parent = parent, .child = NULL));
-       ct->task.pre_select = client_pre_select;
-       ct->task.post_select = client_post_select;
-       ct->task.error = 0;
-       sprintf(ct->task.status, "client");
-       register_task(s, &ct->task);
+
+       ct->task = task_register(&(struct task_info) {
+               .name = "client",
+               .pre_select = client_pre_select,
+               .post_select = client_post_select,
+               .context = ct,
+       }, s);
        return 1;
 err_out:
        close(ct->scc.fd);
@@ -517,6 +503,15 @@ err_out:
        return ret;
 }
 
+__noreturn static void print_help_and_die(struct client_task *ct)
+{
+       struct ggo_help h = DEFINE_GGO_HELP(client);
+       bool d = ct->conf.detailed_help_given;
+
+       ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
+       exit(0);
+}
+
 /**
  * Parse a client configuration.
  *
@@ -547,7 +542,9 @@ int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
        ret = -E_CLIENT_SYNTAX;
        if (client_cmdline_parser(argc, argv, &ct->conf))
                goto out;
-       HANDLE_VERSION_FLAG("client", ct->conf);
+       version_handle_flag("client", ct->conf.version_given);
+       if (ct->conf.help_given || ct->conf.detailed_help_given)
+               print_help_and_die(ct);
 
        ct->config_file = ct->conf.config_file_given?
                para_strdup(ct->conf.config_file_arg) :