Imported Debian patch 2.5.1-1
[debian/amanda] / client-src / clientconf.c
diff --git a/client-src/clientconf.c b/client-src/clientconf.c
new file mode 100644 (file)
index 0000000..e2a2246
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-2000 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * $Id: clientconf.c,v 1.17 2006/07/25 19:36:48 martinea Exp $
+ *
+ * read configuration file
+ */
+/*
+ *
+ * XXX - I'm not happy *at all* with this implementation, but I don't
+ * think YACC would be any easier.  A more table based implementation
+ * would be better.  Also clean up memory leaks.
+ */
+#include "amanda.h"
+#include "arglist.h"
+#include "util.h"
+#include "clientconf.h"
+#include "clock.h"
+
+/* configuration parameters */
+static char *cln_config_dir = NULL;
+
+val_t client_conf[CLN_CLN];
+
+command_option_t *client_options      = NULL;
+int               client_options_size = 0;
+
+/* predeclare local functions */
+
+static void init_defaults(void);
+static void read_conffile_recursively(char *filename);
+
+static int read_confline(void);
+
+keytab_t client_keytab[] = {
+    { "CONF", CONF_CONF },
+    { "INDEX_SERVER", CONF_INDEX_SERVER },
+    { "TAPE_SERVER", CONF_TAPE_SERVER },
+    { "TAPEDEV", CONF_TAPEDEV },
+    { "AUTH", CONF_AUTH },
+    { "SSH_KEYS", CONF_SSH_KEYS },
+    { "AMANDAD_PATH", CONF_AMANDAD_PATH },
+    { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
+    { "GNUTAR_LIST_DIR", CONF_GNUTAR_LIST_DIR },
+    { "AMANDATES", CONF_AMANDATES },
+    { "INCLUDEFILE", CONF_INCLUDEFILE },
+    { NULL, CONF_UNKNOWN },
+};
+
+t_conf_var client_var [] = {
+   { CONF_CONF           , CONFTYPE_STRING, read_string, CLN_CONF           , NULL },
+   { CONF_INDEX_SERVER   , CONFTYPE_STRING, read_string, CLN_INDEX_SERVER   , NULL },
+   { CONF_TAPE_SERVER    , CONFTYPE_STRING, read_string, CLN_TAPE_SERVER    , NULL },
+   { CONF_TAPEDEV        , CONFTYPE_STRING, read_string, CLN_TAPEDEV        , NULL },
+   { CONF_AUTH           , CONFTYPE_STRING, read_string, CLN_AUTH           , NULL },
+   { CONF_SSH_KEYS       , CONFTYPE_STRING, read_string, CLN_SSH_KEYS       , NULL },
+   { CONF_AMANDAD_PATH   , CONFTYPE_STRING, read_string, CLN_AMANDAD_PATH   , NULL },
+   { CONF_CLIENT_USERNAME, CONFTYPE_STRING, read_string, CLN_CLIENT_USERNAME, NULL },
+   { CONF_GNUTAR_LIST_DIR, CONFTYPE_STRING, read_string, CLN_GNUTAR_LIST_DIR, NULL },
+   { CONF_AMANDATES      , CONFTYPE_STRING, read_string, CLN_AMANDATES      , NULL },
+   { CONF_UNKNOWN        , CONFTYPE_INT   , NULL       , CLN_CLN            , NULL }
+};
+
+static int first_file = 1;
+
+/*
+** ------------------------
+**  External entry points
+** ------------------------
+*/
+
+/* return  0 on success        */
+/* return  1 on error          */
+/* return -1 if file not found */
+
+int read_clientconf(
+    char *filename)
+{
+    if(first_file == 1) {
+       init_defaults();
+       first_file = 0;
+    } else {
+       allow_overwrites = 1;
+    }
+
+    /* We assume that conf_confname & conf are initialized to NULL above */
+    read_conffile_recursively(filename);
+
+    command_overwrite(client_options, client_var, client_keytab, client_conf,
+                     "");
+
+    return got_parserror;
+}
+
+
+char *
+client_getconf_byname(
+    char *     str)
+{
+    static char *tmpstr;
+    char number[NUM_STR_SIZE];
+    t_conf_var *np;
+    keytab_t *kt;
+    char *s;
+    char ch;
+
+    tmpstr = stralloc(str);
+    s = tmpstr;
+    while((ch = *s++) != '\0') {
+       if(islower((int)ch))
+           s[-1] = (char)toupper(ch);
+    }
+
+    for(kt = client_keytab; kt->token != CONF_UNKNOWN; kt++)
+       if(kt->keyword && strcmp(kt->keyword, tmpstr) == 0) break;
+
+    if(kt->token == CONF_UNKNOWN) return NULL;
+
+    for(np = client_var; np->token != CONF_UNKNOWN; np++)
+       if(np->token == kt->token) break;
+
+    if(np->type == CONFTYPE_INT) {
+       snprintf(number, SIZEOF(number), "%d", client_getconf_int(np->parm));
+       tmpstr = newstralloc(tmpstr, number);
+    } else if(np->type == CONFTYPE_BOOL) {
+       if(client_getconf_boolean(np->parm) == 0) {
+           tmpstr = newstralloc(tmpstr, "off");
+       }
+       else {
+           tmpstr = newstralloc(tmpstr, "on");
+       }
+    } else if(np->type == CONFTYPE_REAL) {
+       snprintf(number, SIZEOF(number), "%lf", client_getconf_real(np->parm));
+       tmpstr = newstralloc(tmpstr, number);
+    } else {
+       tmpstr = newstralloc(tmpstr, client_getconf_str(np->parm));
+    }
+
+    return tmpstr;
+}
+
+int
+client_getconf_seen(
+    cconfparm_t parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    return(client_conf[np->parm].seen);
+}
+
+int
+client_getconf_boolean(
+    cconfparm_t        parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    if (np->type != CONFTYPE_BOOL) {
+       error("client_getconf_boolean: np is not a CONFTYPE_BOOL");
+       /*NOTREACHED*/
+    }
+    return(client_conf[np->parm].v.i != 0);
+}
+
+int
+client_getconf_int(
+    cconfparm_t        parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    if (np->type != CONFTYPE_INT) {
+       error("client_getconf_int: np is not a CONFTYPE_INT");
+       /*NOTREACHED*/
+    }
+
+    return(client_conf[np->parm].v.i);
+}
+
+off_t
+client_getconf_am64(
+    cconfparm_t        parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    if (np->type != CONFTYPE_AM64) {
+       error("client_getconf_am64: np is not a CONFTYPE_AM64");
+       /*NOTREACHED*/
+    }
+    return(client_conf[np->parm].v.am64);
+}
+
+double
+client_getconf_real(
+    cconfparm_t        parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    if (np->type != CONFTYPE_REAL) {
+       error("client_getconf_real: np is not a CONFTYPE_REAL");
+       /*NOTREACHED*/
+    }
+    return(client_conf[np->parm].v.r);
+}
+
+char *
+client_getconf_str(
+    cconfparm_t parm)
+{
+    t_conf_var *np;
+    np = get_np(client_var, parm);
+    if (np->type != CONFTYPE_STRING) {
+       error("client_getconf_string: np is not a CONFTYPE_STRING");
+       /*NOTREACHED*/
+    }
+    return(client_conf[np->parm].v.s);
+}
+
+/*
+** ------------------------
+**  Internal routines
+** ------------------------
+*/
+
+
+static void
+init_defaults(void)
+{
+    char *s;
+
+    /* defaults for exported variables */
+
+#ifdef DEFAULT_CONFIG
+    s = DEFAULT_CONFIG;
+#else
+    s = "";
+#endif
+    conf_init_string(&client_conf[CLN_CONF], s);
+
+#ifdef DEFAULT_SERVER
+    s = DEFAULT_SERVER;
+#else
+    s = "";
+#endif
+    conf_init_string(&client_conf[CLN_INDEX_SERVER], s);
+
+
+#ifdef DEFAULT_TAPE_SERVER
+    s = DEFAULT_TAPE_SERVER;
+#else
+#ifdef DEFAULT_SERVER
+    s = DEFAULT_SERVER;
+#else
+    s = "";
+#endif
+#endif
+    conf_init_string(&client_conf[CLN_TAPE_SERVER], s);
+
+#ifdef DEFAULT_TAPE_DEVICE
+    s = DEFAULT_TAPE_DEVICE;
+#else
+    s = NULL;
+#endif
+    conf_init_string(&client_conf[CLN_TAPEDEV], s);
+
+    conf_init_string(&client_conf[CLN_AUTH], "bsd");
+    conf_init_string(&client_conf[CLN_SSH_KEYS], "");
+    conf_init_string(&client_conf[CLN_AMANDAD_PATH], "");
+    conf_init_string(&client_conf[CLN_CLIENT_USERNAME], "");
+#ifdef GNUTAR_LISTED_INCREMENTAL_DIR
+    conf_init_string(&client_conf[CLN_GNUTAR_LIST_DIR],
+                    GNUTAR_LISTED_INCREMENTAL_DIR);
+#else
+    conf_init_string(&client_conf[CLN_GNUTAR_LIST_DIR], NULL);
+#endif
+    conf_init_string(&client_conf[CLN_AMANDATES], "/etc/amandates");
+    /* defaults for internal variables */
+
+    conf_line_num = got_parserror = 0;
+    allow_overwrites = 0;
+    token_pushed = 0;
+
+}
+
+static void
+read_conffile_recursively(
+    char *     filename)
+{
+    /* Save globals used in read_confline(), elsewhere. */
+    int  save_line_num  = conf_line_num;
+    FILE *save_conf     = conf_conf;
+    char *save_confname = conf_confname;
+    int        rc;
+
+    if (*filename == '/' || cln_config_dir == NULL) {
+       conf_confname = stralloc(filename);
+    } else {
+       conf_confname = stralloc2(cln_config_dir, filename);
+    }
+
+    if((conf_conf = fopen(conf_confname, "r")) == NULL) {
+       dbprintf(("Could not open conf file \"%s\": %s\n", conf_confname,
+                 strerror(errno)));
+       amfree(conf_confname);
+       got_parserror = -1;
+       return;
+    }
+    dbprintf(("Reading conf file \"%s\".\n", conf_confname));
+
+    conf_line_num = 0;
+
+    /* read_confline() can invoke us recursively via "includefile" */
+    do {
+       rc = read_confline();
+    } while (rc != 0);
+    afclose(conf_conf);
+
+    amfree(conf_confname);
+
+    /* Restore globals */
+    conf_line_num = save_line_num;
+    conf_conf     = save_conf;
+    conf_confname = save_confname;
+}
+
+
+/* ------------------------ */
+
+
+static int
+read_confline(void)
+{
+    t_conf_var *np;
+
+    keytable = client_keytab;
+
+    conf_line_num += 1;
+    get_conftoken(CONF_ANY);
+    switch(tok) {
+    case CONF_INCLUDEFILE:
+       {
+           char *fn;
+
+           get_conftoken(CONF_STRING);
+           fn = tokenval.v.s;
+           read_conffile_recursively(fn);
+       }
+       break;
+
+    case CONF_NL:      /* empty line */
+       break;
+
+    case CONF_END:     /* end of file */
+       return 0;
+
+    default:
+       {
+           for(np = client_var; np->token != CONF_UNKNOWN; np++)
+               if(np->token == tok) break;
+
+           if(np->token == CONF_UNKNOWN) {
+               conf_parserror("configuration keyword expected");
+           } else {
+               np->read_function(np, &client_conf[np->parm]);
+               if(np->validate)
+                   np->validate(np, &client_conf[np->parm]);
+           }
+       }
+    }
+    if(tok != CONF_NL)
+       get_conftoken(CONF_NL);
+    return 1;
+}
+
+
+
+/* ------------------------ */
+
+#ifdef TEST
+
+static char *cln_config_name = NULL;
+static char *cln_config_dir = NULL;
+
+void
+dump_client_configuration(
+    char *filename)
+{
+    printf("AMANDA CLIENT CONFIGURATION FROM FILE \"%s\":\n\n", filename);
+
+    printf("cln_conf = \"%s\"\n", client_getconf_str(CLN_CONF));
+    printf("cln_index_server = \"%s\"\n", client_getconf_str(CLN_INDEX_SERVER));
+    printf("cln_tape_server = \"%s\"\n", client_getconf_str(CLN_TAPE_SERVER));
+    printf("cln_tapedev = \"%s\"\n", client_getconf_str(CLN_TAPEDEV));
+    printf("cln_auth = \"%s\"\n", client_getconf_str(CLN_AUTH));
+    printf("cln_ssh_keys = \"%s\"\n", client_getconf_str(CLN_SSH_KEYS));
+}
+
+int
+main(
+    int                argc,
+    char **    argv)
+{
+  char *conffile;
+  char *diskfile;
+  disklist_t lst;
+  int result;
+  unsigned long malloc_hist_1, malloc_size_1;
+  unsigned long malloc_hist_2, malloc_size_2;
+
+  safe_fd(-1, 0);
+
+  set_pname("conffile");
+
+  /* Don't die when child closes pipe */
+  signal(SIGPIPE, SIG_IGN);
+
+  malloc_size_1 = malloc_inuse(&malloc_hist_1);
+
+  startclock();
+
+  if (argc > 1) {
+    if (argv[1][0] == '/') {
+      cln_config_dir = stralloc(argv[1]);
+      cln_config_name = strrchr(cln_config_dir, '/') + 1;
+      cln_config_name[-1] = '\0';
+      cln_config_dir = newstralloc2(cln_config_dir, cln_config_dir, "/");
+    } else {
+      cln_config_name = stralloc(argv[1]);
+      cln_config_dir = vstralloc(CONFIG_DIR, "/", cln_config_name, "/", NULL);
+    }
+  } else {
+    char my_cwd[STR_SIZE];
+
+    if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
+      error("cannot determine current working directory");
+    }
+    cln_config_dir = stralloc2(my_cwd, "/");
+    if ((cln_config_name = strrchr(my_cwd, '/')) != NULL) {
+      cln_config_name = stralloc(cln_config_name + 1);
+    }
+  }
+
+  conffile = stralloc2(cln_config_dir, CONFFILE_NAME);
+  result = read_conffile(conffile);
+  if (result == 0) {
+      diskfile = client_getconf_str(CNF_DISKFILE);
+      if (diskfile != NULL && access(diskfile, R_OK) == 0) {
+         result = read_diskfile(diskfile, &lst);
+      }
+  }
+  dump_client_configuration(CONFFILE_NAME);
+  amfree(conffile);
+
+  malloc_size_2 = malloc_inuse(&malloc_hist_2);
+
+  if(malloc_size_1 != malloc_size_2) {
+    malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
+  }
+
+  return result;
+}
+
+#endif /* TEST */
+
+char *
+generic_client_get_security_conf(
+    char *     string,
+    void *     arg)
+{
+       (void)arg;      /* Quiet unused parameter warning */
+
+       if(!string || !*string)
+               return(NULL);
+
+       if(strcmp(string, "conf")==0) {
+               return(client_getconf_str(CLN_CONF));
+       } else if(strcmp(string, "index_server")==0) {
+               return(client_getconf_str(CLN_INDEX_SERVER));
+       } else if(strcmp(string, "tape_server")==0) {
+               return(client_getconf_str(CLN_TAPE_SERVER));
+       } else if(strcmp(string, "tapedev")==0) {
+               return(client_getconf_str(CLN_TAPEDEV));
+       } else if(strcmp(string, "auth")==0) {
+               return(client_getconf_str(CLN_AUTH));
+       } else if(strcmp(string, "ssh_keys")==0) {
+               return(client_getconf_str(CLN_SSH_KEYS));
+       } else if(strcmp(string, "amandad_path")==0) {
+               return(client_getconf_str(CLN_AMANDAD_PATH));
+       } else if(strcmp(string, "client_username")==0) {
+               return(client_getconf_str(CLN_CLIENT_USERNAME));
+       } else if(strcmp(string, "gnutar_list_dir")==0) {
+               return(client_getconf_str(CLN_GNUTAR_LIST_DIR));
+       } else if(strcmp(string, "amandates")==0) {
+               return(client_getconf_str(CLN_AMANDATES));
+/*
+       } else if(strcmp(string, "krb5principal")==0) {
+               return(client_getconf_str(CNF_KRB5PRINCIPAL));
+       } else if(strcmp(string, "krb5keytab")==0) {
+               return(client_getconf_str(CNF_KRB5KEYTAB));
+*/
+       }
+       return(NULL);
+}
+
+
+void
+parse_client_conf(
+    int parse_argc,
+    char **parse_argv,
+    int *new_argc,
+    char ***new_argv)
+{
+    int i;
+    char **my_argv;
+    char *myarg, *value;
+    command_option_t *client_option;
+
+    client_options = alloc((size_t)(parse_argc+1) * SIZEOF(*client_options));
+    client_options_size = parse_argc+1;
+    client_option = client_options;
+    client_option->name = NULL;
+
+    my_argv = alloc((size_t)parse_argc * SIZEOF(char *));
+    *new_argv = my_argv;
+    *new_argc = 0;
+    i=0;
+    while(i<parse_argc) {
+       if(strncmp(parse_argv[i],"-o",2) == 0) {
+           if(strlen(parse_argv[i]) > 2)
+               myarg = &parse_argv[i][2];
+           else {
+               i++;
+               if(i >= parse_argc)
+                   error("expect something after -o");
+               myarg = parse_argv[i];
+           }
+           value = index(myarg,'=');
+           if (value == NULL) {
+               conf_parserror("Must specify a value for %s.\n", myarg);
+           } else {
+               *value = '\0';
+               value++;
+               client_option->used = 0;
+               client_option->name = stralloc(myarg);
+               client_option->value = stralloc(value);
+               client_option++;
+               client_option->name = NULL;
+           }
+       }
+       else {
+           my_argv[*new_argc] = stralloc(parse_argv[i]);
+           *new_argc += 1;
+       }
+       i++;
+    }
+}
+
+/* return  0 on success             */
+/* return -1 if it is already there */
+/* return -2 if other failure       */
+int
+add_client_conf(
+    cconfparm_t parm,
+    char *value)
+{
+    t_conf_var *np;
+    keytab_t *kt;
+    command_option_t *command_option;
+    int nb_option;
+
+    for(np = client_var; np->token != CONF_UNKNOWN; np++)
+       if(np->parm == (int)parm) break;
+
+    if(np->token == CONF_UNKNOWN) return -2;
+
+    for(kt = client_keytab; kt->token != CONF_UNKNOWN; kt++)
+       if(kt->token == np->token) break;
+
+    if(kt->token == CONF_UNKNOWN) return -2;
+
+    /* Try to find it */
+    nb_option = 0;
+    for(command_option = client_options; command_option->name != NULL;
+                                                       command_option++) {
+       if(strcasecmp(command_option->name, kt->keyword) == 0) {
+           return -1;
+       }
+       nb_option++;
+    }
+
+    /* Increase size of client_options if needed */
+    if(nb_option >= client_options_size-1) {
+       client_options_size *= 2;
+       client_options = realloc(client_options,
+                               client_options_size * SIZEOF(*client_options));
+       if (client_options == NULL) {
+           error("Can't realloc client_options: %s\n", strerror(errno));
+           /*NOTREACHED*/
+       }
+       for(command_option = client_options; command_option->name != NULL;
+                                                       command_option++) {
+       }
+    }
+
+    /* add it */
+    command_option->used = 0;
+    command_option->name = stralloc(kt->keyword);
+    command_option->value = stralloc(value);
+    command_option++;
+    command_option->name = NULL;
+    return 0;
+}
+
+void
+report_bad_client_arg(void)
+{
+    command_option_t *command_option;
+
+    for(command_option = client_options; command_option->name != NULL;
+                                                       command_option++) {
+       if(command_option->used == 0) {
+           fprintf(stderr,"argument -o%s=%s not used\n",
+                   command_option->name, command_option->value);
+       }
+    }
+}