]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/options.c
Add set and reset options to control environment variables for scripts.
[ppp.git] / pppd / options.c
index 482eab99e3274086d7c6b13aac4b7c1254045c27..434ab95748fb34497af2d3fe79e43789638b1736 100644 (file)
@@ -119,6 +119,7 @@ bool        dump_options;           /* print out option values */
 bool   dryrun;                 /* print out option values and exit */
 char   *domain;                /* domain name set by domain option */
 int    child_wait = 5;         /* # seconds to wait for children at exit */
+struct userenv *userenv_list;  /* user environment variables */
 
 #ifdef MAXOCTETS
 unsigned int  maxoctets = 0;    /* default - no limit */
@@ -135,6 +136,7 @@ struct      bpf_program pass_filter;/* Filter program for packets to pass */
 struct bpf_program active_filter; /* Filter program for link-active pkts */
 #endif
 
+static option_t *curopt;       /* pointer to option being processed */
 char *current_option;          /* the name of the option being parsed */
 int  privileged_option;                /* set iff the current option came from root */
 char *option_source;           /* string saying where the option came from */
@@ -167,6 +169,11 @@ static int setactivefilter __P((char **));
 static int setmodir __P((char **));
 #endif
 
+static int user_setenv __P((char **));
+static void user_setprint __P((option_t *, printer_func, void *));
+static int user_unsetenv __P((char **));
+static void user_unsetprint __P((option_t *, printer_func, void *));
+
 static option_t *find_option __P((const char *name));
 static int process_option __P((option_t *, char *, char **));
 static int n_arguments __P((option_t *));
@@ -281,6 +288,13 @@ option_t general_options[] = {
       "Number of seconds to wait for child processes at exit",
       OPT_PRIO },
 
+    { "set", o_special, (void *)user_setenv,
+      "Set user environment variable",
+      OPT_A2PRINTER | OPT_NOPRINT, (void *)user_setprint },
+    { "unset", o_special, (void *)user_unsetenv,
+      "Unset user environment variable",
+      OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
+
 #ifdef HAVE_MULTILINK
     { "multilink", o_bool, &multilink,
       "Enable multilink operation", OPT_PRIO | 1 },
@@ -768,6 +782,7 @@ process_option(opt, cmd, argv)
     case o_special_noarg:
     case o_special:
        parser = (int (*) __P((char **))) opt->addr;
+       curopt = opt;
        if (!(*parser)(argv))
            return 0;
        if (opt->flags & OPT_A2LIST) {
@@ -881,7 +896,7 @@ check_options()
 static void
 print_option(opt, mainopt, printer, arg)
     option_t *opt, *mainopt;
-    void (*printer) __P((void *, char *, ...));
+    printer_func printer;
     void *arg;
 {
        int i, v;
@@ -944,11 +959,8 @@ print_option(opt, mainopt, printer, arg)
                        printer(arg, " ");
                }
                if (opt->flags & OPT_A2PRINTER) {
-                       void (*oprt) __P((option_t *,
-                                         void ((*)__P((void *, char *, ...))),
-                                         void *));
-                       oprt = (void (*) __P((option_t *,
-                                        void ((*)__P((void *, char *, ...))),
+                       void (*oprt) __P((option_t *, printer_func, void *));
+                       oprt = (void (*) __P((option_t *, printer_func,
                                         void *)))opt->addr2;
                        (*oprt)(opt, printer, arg);
                } else if (opt->flags & OPT_A2STRVAL) {
@@ -986,7 +998,7 @@ print_option(opt, mainopt, printer, arg)
 static void
 print_option_list(opt, printer, arg)
     option_t *opt;
-    void (*printer) __P((void *, char *, ...));
+    printer_func printer;
     void *arg;
 {
        while (opt->name != NULL) {
@@ -1004,7 +1016,7 @@ print_option_list(opt, printer, arg)
  */
 void
 print_options(printer, arg)
-    void (*printer) __P((void *, char *, ...));
+    printer_func printer;
     void *arg;
 {
        struct option_list *list;
@@ -1623,3 +1635,154 @@ loadplugin(argv)
     return 0;
 }
 #endif /* PLUGIN */
+
+/*
+ * Set an environment variable specified by the user.
+ */
+static int
+user_setenv(argv)
+    char **argv;
+{
+    char *arg = argv[0];
+    char *eqp;
+    struct userenv *uep, **insp;
+
+    if ((eqp = strchr(arg, '=')) == NULL) {
+       option_error("missing = in name=value: %s", arg);
+       return 0;
+    }
+    if (eqp == arg) {
+       option_error("missing variable name: %s", arg);
+       return 0;
+    }
+    for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
+       int nlen = strlen(uep->ue_name);
+       if (nlen == (eqp - arg) &&
+           strncmp(arg, uep->ue_name, nlen) == 0)
+           break;
+    }
+    /* Ignore attempts by unprivileged users to override privileged sources */
+    if (uep != NULL && !privileged_option && uep->ue_priv)
+       return 1;
+    /* The name never changes, so allocate it with the structure */
+    if (uep == NULL) {
+       uep = malloc(sizeof (*uep) + (eqp-arg));
+       strncpy(uep->ue_name, arg, eqp-arg);
+       uep->ue_name[eqp-arg] = '\0';
+       uep->ue_next = NULL;
+       insp = &userenv_list;
+       while (*insp != NULL)
+           insp = &(*insp)->ue_next;
+       *insp = uep;
+    } else {
+       struct userenv *uep2;
+       for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
+           if (uep2 != uep && !uep2->ue_isset)
+               break;
+       }
+       if (uep2 == NULL && !uep->ue_isset)
+           find_option("unset")->flags |= OPT_NOPRINT;
+       free(uep->ue_value);
+    }
+    uep->ue_isset = 1;
+    uep->ue_priv = privileged_option;
+    uep->ue_source = option_source;
+    uep->ue_value = strdup(eqp + 1);
+    curopt->flags &= ~OPT_NOPRINT;
+    return 1;
+}
+
+static void
+user_setprint(opt, printer, arg)
+    option_t *opt;
+    printer_func printer;
+    void *arg;
+{
+    struct userenv *uep, *uepnext;
+
+    uepnext = userenv_list;
+    while (uepnext != NULL && !uepnext->ue_isset)
+       uepnext = uepnext->ue_next;
+    while ((uep = uepnext) != NULL) {
+       uepnext = uep->ue_next;
+       while (uepnext != NULL && !uepnext->ue_isset)
+           uepnext = uepnext->ue_next;
+       (*printer)(arg, "%s=%s", uep->ue_name, uep->ue_value);
+       if (uepnext != NULL)
+           (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
+       else
+           opt->source = uep->ue_source;
+    }
+}
+
+static int
+user_unsetenv(argv)
+    char **argv;
+{
+    struct userenv *uep, **insp;
+    char *arg = argv[0];
+
+    if (strchr(arg, '=') != NULL) {
+       option_error("unexpected = in name: %s", arg);
+       return 0;
+    }
+    if (arg == '\0') {
+       option_error("missing variable name for unset");
+       return 0;
+    }
+    for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
+       if (strcmp(arg, uep->ue_name) == 0)
+           break;
+    }
+    /* Ignore attempts by unprivileged users to override privileged sources */
+    if (uep != NULL && !privileged_option && uep->ue_priv)
+       return 1;
+    /* The name never changes, so allocate it with the structure */
+    if (uep == NULL) {
+       uep = malloc(sizeof (*uep) + strlen(arg));
+       strcpy(uep->ue_name, arg);
+       uep->ue_next = NULL;
+       insp = &userenv_list;
+       while (*insp != NULL)
+           insp = &(*insp)->ue_next;
+       *insp = uep;
+    } else {
+       struct userenv *uep2;
+       for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
+           if (uep2 != uep && uep2->ue_isset)
+               break;
+       }
+       if (uep2 == NULL && uep->ue_isset)
+           find_option("set")->flags |= OPT_NOPRINT;
+       free(uep->ue_value);
+    }
+    uep->ue_isset = 0;
+    uep->ue_priv = privileged_option;
+    uep->ue_source = option_source;
+    uep->ue_value = NULL;
+    curopt->flags &= ~OPT_NOPRINT;
+    return 1;
+}
+
+static void
+user_unsetprint(opt, printer, arg)
+    option_t *opt;
+    printer_func printer;
+    void *arg;
+{
+    struct userenv *uep, *uepnext;
+
+    uepnext = userenv_list;
+    while (uepnext != NULL && uepnext->ue_isset)
+       uepnext = uepnext->ue_next;
+    while ((uep = uepnext) != NULL) {
+       uepnext = uep->ue_next;
+       while (uepnext != NULL && uepnext->ue_isset)
+           uepnext = uepnext->ue_next;
+       (*printer)(arg, "%s", uep->ue_name);
+       if (uepnext != NULL)
+           (*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
+       else
+           opt->source = uep->ue_source;
+    }
+}