Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/   (Postfix Mailserver Version 3.11©)  Datei vom 23.1.2016 mit Größe 7 kB image not shown  

Quelle  postconf_edit.c

  Sprache: C
 

/*++
/* NAME
/* postconf_edit 3
/* SUMMARY
/* edit main.cf or master.cf
/* SYNOPSIS
/* #include <postconf.h>
/*
/* void pcf_edit_main(mode, argc, argv)
/* int mode;
/* int argc;
/* char **argv;
/*
/* void pcf_edit_master(mode, argc, argv)
/* int mode;
/* int argc;
/* char **argv;
/* DESCRIPTION
/* pcf_edit_main() edits the \fBmain.cf\fR configuration file.
/* It replaces or adds parameter settings given as "\fIname=value\fR"
/* pairs given on the command line, or removes parameter
/* settings given as "\fIname\fR" on the command line.  The
/* file is copied to a temporary file then renamed into place.
/*
/* pcf_edit_master() edits the \fBmaster.cf\fR configuration
/* file.  The file is copied to a temporary file then renamed
/* into place. Depending on the flags in \fBmode\fR:
/* .IP PCF_MASTER_ENTRY
/* With PCF_EDIT_CONF, pcf_edit_master() replaces or adds
/* entire master.cf entries, specified on the command line as
/* "\fIname/type = name type private unprivileged chroot wakeup
/* process_limit command...\fR".
/*
/* With PCF_EDIT_EXCL or PCF_COMMENT_OUT, pcf_edit_master()
/* removes or comments out entries specified on the command
/* line as "\fIname/type\fR.
/* .IP PCF_MASTER_FLD
/* With PCF_EDIT_CONF, pcf_edit_master() replaces the value
/* of specific service attributes, specified on the command
/* line as "\fIname/type/attribute = value\fR".
/* .IP PCF_MASTER_PARAM
/* With PCF_EDIT_CONF, pcf_edit_master() replaces or adds the
/* value of service parameters, specified on the command line
/* as "\fIname/type/parameter = value\fR".
/*
/* With PCF_EDIT_EXCL, pcf_edit_master() removes service
/* parameters specified on the command line as "\fIparametername\fR".
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* FILES
/* /etc/postfix/main.cf, Postfix configuration parameters
/* /etc/postfix/main.cf.tmp, temporary name
/* /etc/postfix/master.cf, Postfix configuration parameters
/* /etc/postfix/master.cf.tmp, temporary name
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <htable.h>
#include <vstring.h>
#include <vstring_vstream.h>
#include <edit_file.h>
#include <readlline.h>
#include <stringops.h>
#include <split_at.h>

/* Global library. */

#include <mail_params.h>

/* Application-specific. */

#include <postconf.h>

#define STR(x) vstring_str(x)

/* pcf_find_cf_info - pass-through non-content line, return content or null */

static char *pcf_find_cf_info(VSTRING *buf, VSTREAM *dst)
{
    char   *cp;

    for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
  /* void */ ;
    /* Pass-through comment, all-whitespace, or empty line. */
    if (*cp == '#' || *cp == 0) {
 vstream_fputs(STR(buf), dst);
 return (0);
    } else {
 return (cp);
    }
}

/* pcf_next_cf_line - return next content line, pass non-content */

static char *pcf_next_cf_line(VSTRING *buf, VSTREAM *src, VSTREAM *dst, int *lineno)
{
    char   *cp;
    int     last_char;

    while ((last_char = vstring_get(buf, src)) != VSTREAM_EOF) {
 if (last_char != '\n') {
     VSTRING_ADDCH(buf, '\n');
     VSTRING_TERMINATE(buf);
 }
 if (lineno)
     *lineno += 1;
 if ((cp = pcf_find_cf_info(buf, dst)) != 0)
     return (cp);
    }
    return (0);
}

/* pcf_gobble_cf_line - accumulate multi-line content, pass non-content */

static void pcf_gobble_cf_line(VSTRING *full_entry_buf, VSTRING *line_buf,
               VSTREAM *src, VSTREAM *dst, int *lineno)
{
    int     ch;

    vstring_strcpy(full_entry_buf, STR(line_buf));
    for (;;) {
 if ((ch = VSTREAM_GETC(src)) != VSTREAM_EOF)
     vstream_ungetc(src, ch);
 if ((ch != '#' && !ISSPACE(ch))
     || vstring_get(line_buf, src) == VSTREAM_EOF)
     break;
 lineno += 1;
 if (pcf_find_cf_info(line_buf, dst))
     vstring_strcat(full_entry_buf, STR(line_buf));
    }
}

/* pcf_cmp_ht_key - qsort helper for ht_info pointer array */

static int pcf_cmp_ht_key(const void *a, const void *b)
{
    HTABLE_INFO **ap = (HTABLE_INFO **) a;
    HTABLE_INFO **bp = (HTABLE_INFO **) b;

    return (strcmp(ap[0]->key, bp[0]->key));
}

/* pcf_edit_main - edit main.cf file */

void    pcf_edit_main(int mode, int argc, char **argv)
{
    const char *path;
    EDIT_FILE *ep;
    VSTREAM *src;
    VSTREAM *dst;
    VSTRING *buf = vstring_alloc(100);
    VSTRING *key = vstring_alloc(10);
    char   *cp;
    char   *pattern;
    char   *edit_value;
    HTABLE *table;
    struct cvalue {
 char   *value;
 int     found;
    };
    struct cvalue *cvalue;
    HTABLE_INFO **ht_info;
    HTABLE_INFO **ht;
    int     interesting;
    const char *err;

    /*
     * Store command-line parameters for quick lookup.
     */

    table = htable_create(argc);
    while ((cp = *argv++) != 0) {
 if (strchr(cp, '\n') != 0)
     msg_fatal("-e, -X, or -# accepts no multi-line input");
 while (ISSPACE(*cp))
     cp++;
 if (*cp == '#')
     msg_fatal("-e, -X, or -# accepts no comment input");
 if (mode & PCF_EDIT_CONF) {
     if ((err = split_nameval(cp, &pattern, &edit_value)) != 0)
  msg_fatal("%s: \"%s\"", err, cp);
 } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
     if (*cp == 0)
  msg_fatal("-X or -# requires non-blank parameter names");
     if (strchr(cp, '=') != 0)
  msg_fatal("-X or -# requires parameter names without value");
     pattern = cp;
     trimblanks(pattern, 0);
     edit_value = 0;
 } else {
     msg_panic("pcf_edit_main: unknown mode %d", mode);
 }
 if ((cvalue = htable_find(table, pattern)) != 0) {
     if (edit_value && cvalue->value
  && strcmp(edit_value, cvalue->value) != 0)
  msg_warn("ignoring earlier request: '%s = %s'",
    pattern, cvalue->value);
     htable_delete(table, pattern, myfree);
 }
 cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
 cvalue->value = edit_value;
 cvalue->found = 0;
 htable_enter(table, pattern, (void *) cvalue);
    }

    /*
     * Open a temp file for the result. This uses a deterministic name so we
     * don't leave behind thrash with random names.
     */

    path = pcf_get_main_path();
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
 msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
    dst = ep->tmp_fp;

    /*
     * Open the original file for input.
     */

    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
 /* OK to delete, since we control the temp file name exclusively. */
 (void) unlink(ep->tmp_path);
 msg_fatal("open %s for reading: %m", path);
    }

    /*
     * Copy original file to temp file, while replacing parameters on the
     * fly. Issue warnings for names found multiple times.
     */

#define STR(x) vstring_str(x)

    interesting = 0;
    while ((cp = pcf_next_cf_line(buf, src, dst, (int *) 0)) != 0) {
 /* Copy, skip or replace continued text. */
 if (cp > STR(buf)) {
     if (interesting == 0)
  vstream_fputs(STR(buf), dst);
     else if (mode & PCF_COMMENT_OUT)
  vstream_fprintf(dst, "#%s", STR(buf));
 }
 /* Copy or replace start of logical line. */
 else {
     vstring_strncpy(key, cp, strcspn(cp, CHARS_SPACE "="));
     cvalue = (struct cvalue *) htable_find(table, STR(key));
     if ((interesting = !!cvalue) != 0) {
  if (cvalue->found++ == 1)
      msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
  if (mode & PCF_EDIT_CONF)
      vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
  else if (mode & PCF_COMMENT_OUT)
      vstream_fprintf(dst, "#%s", cp);
     } else {
  vstream_fputs(STR(buf), dst);
     }
 }
    }

    /*
     * Generate new entries for parameters that were not found.
     */

    if (mode & PCF_EDIT_CONF) {
 ht_info = htable_list(table);
 qsort((void *) ht_info, table->used, sizeof(*ht_info), pcf_cmp_ht_key);
 for (ht = ht_info; *ht; ht++) {
     cvalue = (struct cvalue *) ht[0]->value;
     if (cvalue->found == 0)
  vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
 }
 myfree((void *) ht_info);
    }

    /*
     * When all is well, rename the temp file to the original one.
     */

    if (vstream_fclose(src))
 msg_fatal("read %s: %m", path);
    if (edit_file_close(ep) != 0)
 msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);

    /*
     * Cleanup.
     */

    vstring_free(buf);
    vstring_free(key);
    htable_free(table, myfree);
}

 /*
  * Data structure to hold a master.cf edit request.
  */

typedef struct {
    int     match_count;  /* hit count */
    const char *raw_text;  /* unparsed command-line argument */
    char   *parsed_text;  /* destructive parse */
    ARGV   *service_pattern;  /* service name, type, ... */
    int     field_number;  /* attribute field number */
    const char *param_pattern;  /* parameter name */
    char   *edit_value;   /* value substring */
} PCF_MASTER_EDIT_REQ;

/* pcf_edit_master - edit master.cf file */

void    pcf_edit_master(int mode, int argc, char **argv)
{
    const char *myname = "pcf_edit_master";
    const char *path;
    EDIT_FILE *ep;
    VSTREAM *src;
    VSTREAM *dst;
    VSTRING *line_buf = vstring_alloc(100);
    VSTRING *parse_buf = vstring_alloc(100);
    int     lineno;
    PCF_MASTER_ENT *new_entry;
    VSTRING *full_entry_buf = vstring_alloc(100);
    char   *cp;
    char   *pattern;
    int     service_name_type_matched;
    const char *err;
    PCF_MASTER_EDIT_REQ *edit_reqs;
    PCF_MASTER_EDIT_REQ *req;
    int     num_reqs = argc;
    const char *edit_opts = "-Me, -Fe, -Pe, -X, or -#";
    char   *service_name;
    char   *service_type;

    /*
     * Sanity check.
     */

    if (num_reqs <= 0)
 msg_panic("%s: empty argument list", myname);

    /*
     * Preprocessing: split pattern=value, then split the pattern components.
     */

    edit_reqs = (PCF_MASTER_EDIT_REQ *) mymalloc(sizeof(*edit_reqs) * num_reqs);
    for (req = edit_reqs; *argv != 0; req++, argv++) {
 req->match_count = 0;
 req->raw_text = *argv;
 cp = req->parsed_text = mystrdup(req->raw_text);
 if (strchr(cp, '\n') != 0)
     msg_fatal("%s accept no multi-line input", edit_opts);
 while (ISSPACE(*cp))
     cp++;
 if (*cp == '#')
     msg_fatal("%s accept no comment input", edit_opts);
 /* Separate the pattern from the value. */
 if (mode & PCF_EDIT_CONF) {
     if ((err = split_nameval(cp, &pattern, &req->edit_value)) != 0)
  msg_fatal("%s: \"%s\"", err, req->raw_text);
#if 0
     if ((mode & PCF_MASTER_PARAM)
     && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
  msg_fatal("whitespace in parameter value: \"%s\"",
     req->raw_text);
#endif
 } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
     if (strchr(cp, '=') != 0)
  msg_fatal("-X or -# requires names without value");
     pattern = cp;
     trimblanks(pattern, 0);
     req->edit_value = 0;
 } else {
     msg_panic("%s: unknown mode %d", myname, mode);
 }

#define PCF_MASTER_MASK (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)

 /*
  * Split name/type or name/type/whatever pattern into components.
 */

 switch (mode & PCF_MASTER_MASK) {
 case PCF_MASTER_ENTRY:
     if ((req->service_pattern =
   pcf_parse_service_pattern(pattern, 22)) == 0)
  msg_fatal("-Me, -MX or -M# requires service_name/type");
     break;
 case PCF_MASTER_FLD:
     if ((req->service_pattern =
   pcf_parse_service_pattern(pattern, 33)) == 0)
  msg_fatal("-Fe or -FX requires service_name/type/field_name");
     req->field_number =
  pcf_parse_field_pattern(req->service_pattern->argv[2]);
     if (pcf_is_magic_field_pattern(req->field_number))
  msg_fatal("-Fe does not accept wild-card field name");
     if ((mode & PCF_EDIT_CONF)
  && req->field_number < PCF_MASTER_FLD_CMD
     && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
  msg_fatal("-Fe does not accept whitespace in non-command field");
     break;
 case PCF_MASTER_PARAM:
     if ((req->service_pattern =
   pcf_parse_service_pattern(pattern, 33)) == 0)
  msg_fatal("-Pe or -PX requires service_name/type/parameter");
     req->param_pattern = req->service_pattern->argv[2];
     if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern))
  msg_fatal("-Pe does not accept wild-card parameter name");
     if ((mode & PCF_EDIT_CONF)
     && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
  msg_fatal("-Pe does not accept whitespace in parameter value");
     break;
 default:
     msg_panic("%s: unknown edit mode %d", myname, mode);
 }
    }

    /*
     * Open a temp file for the result. This uses a deterministic name so we
     * don't leave behind thrash with random names.
     */

    path = pcf_get_master_path();
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
 msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
    dst = ep->tmp_fp;

    /*
     * Open the original file for input.
     */

    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
 /* OK to delete, since we control the temp file name exclusively. */
 (void) unlink(ep->tmp_path);
 msg_fatal("open %s for reading: %m", path);
    }

    /*
     * Copy original file to temp file, while replacing service entries on
     * the fly.
     */

    service_name_type_matched = 0;
    new_entry = 0;
    lineno = 0;
    while ((cp = pcf_next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
 vstring_strcpy(line_buf, STR(parse_buf));

 /*
  * Copy, skip or replace continued text.
 */

 if (cp > STR(parse_buf)) {
     if (service_name_type_matched == 0)
  vstream_fputs(STR(line_buf), dst);
     else if (mode & PCF_COMMENT_OUT)
  vstream_fprintf(dst, "#%s", STR(line_buf));
 }

 /*
  * Copy or replace (start of) logical line.
 */

 else {
     service_name_type_matched = 0;

     /*
      * Parse out the service name and type.
     */

     if ((service_name = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0
  || (service_type = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0)
  msg_fatal("file %s: line %d: specify service name and type "
     "on the same line", path, lineno);
     if (strchr(service_name, '='))
  msg_fatal("file %s: line %d: service name syntax \"%s\" is "
     "unsupported with %s", path, lineno, service_name,
     edit_opts);
     if (service_type[strcspn(service_type, "=/")] != 0)
  msg_fatal("file %s: line %d: "
   "service type syntax \"%s\" is unsupported with %s",
     path, lineno, service_type, edit_opts);

     /*
      * Match each service pattern.
      * 
      * Additional care is needed when a request adds or replaces an
      * entire service definition, instead of a specific field or
      * parameter. Given a command "postconf -M name1/type1='name2
      * type2 ...'", where name1 and name2 may differ, and likewise
      * for type1 and type2:
      * 
      * - First, if an existing service definition a) matches the service
      * pattern 'name1/type1', or b) matches the name and type in the
      * new service definition 'name2 type2 ...', remove the service
      * definition.
      * 
      * - Then, after an a) or b) type match, add a new service
      * definition for 'name2 type2 ...', but only after the first
      * match.
      * 
      * - Finally, if a request had no a) or b) type match for any
      * master.cf service definition, add a new service definition for
      * 'name2 type2 ...'.
     */

     for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
  PCF_MASTER_ENT *tentative_entry = 0;
  int     use_tentative_entry = 0;

  /* Additional care for whole service definition requests. */
  if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
      tentative_entry = (PCF_MASTER_ENT *)
   mymalloc(sizeof(*tentative_entry));
      if ((err = pcf_parse_master_entry(tentative_entry,
            req->edit_value)) != 0)
   msg_fatal("%s: \"%s\"", err, req->raw_text);
  }
  if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
           service_name,
           service_type)) {
      service_name_type_matched = 1/* Sticky flag */
      req->match_count += 1;

      /*
       * Generate replacement master.cf entries.
     */

      if ((mode & PCF_EDIT_CONF)
   || ((mode & PCF_MASTER_PARAM) && (mode & PCF_EDIT_EXCL))) {
   switch (mode & PCF_MASTER_MASK) {

       /*
        * Replace master.cf entry field or parameter
        * value.
     */

   case PCF_MASTER_FLD:
   case PCF_MASTER_PARAM:
       if (new_entry == 0) {
    /* Gobble up any continuation lines. */
    pcf_gobble_cf_line(full_entry_buf, line_buf,
         src, dst, &lineno);
    new_entry = (PCF_MASTER_ENT *)
        mymalloc(sizeof(*new_entry));
    if ((err = pcf_parse_master_entry(new_entry,
       STR(full_entry_buf))) != 0)
        msg_fatal("file %s: line %d: %s",
           path, lineno, err);
       }
       if (mode & PCF_MASTER_FLD) {
    pcf_edit_master_field(new_entry,
            req->field_number,
            req->edit_value);
       } else {
    pcf_edit_master_param(new_entry, mode,
            req->param_pattern,
            req->edit_value);
       }
       break;

       /*
        * Replace entire master.cf entry.
     */

   case PCF_MASTER_ENTRY:
       if (req->match_count == 1)
    use_tentative_entry = 1;
       break;
   default:
       msg_panic("%s: unknown edit mode %d", myname, mode);
   }
      }
  } else if (tentative_entry != 0
    && PCF_MATCH_SERVICE_PATTERN(tentative_entry->argv,
            service_name,
            service_type)) {
      service_name_type_matched = 1/* Sticky flag */
      req->match_count += 1;
      if (req->match_count == 1)
   use_tentative_entry = 1;
  }
  if (tentative_entry != 0) {
      if (use_tentative_entry) {
   if (new_entry != 0)
       pcf_free_master_entry(new_entry);
   new_entry = tentative_entry;
      } else {
   pcf_free_master_entry(tentative_entry);
      }
  }
     }

     /*
      * Pass through or replace the current input line.
     */

     if (new_entry) {
  pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
  pcf_free_master_entry(new_entry);
  new_entry = 0;
     } else if (service_name_type_matched == 0) {
  vstream_fputs(STR(line_buf), dst);
     } else if (mode & PCF_COMMENT_OUT) {
  vstream_fprintf(dst, "#%s", STR(line_buf));
     }
 }
    }

    /*
     * Postprocessing: when editing entire service entries, generate new
     * entries for services not found. Otherwise (editing fields or
     * parameters), "service not found" is a fatal error.
     */

    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
 if (req->match_count == 0) {
     if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
  new_entry = (PCF_MASTER_ENT *) mymalloc(sizeof(*new_entry));
  if ((err = pcf_parse_master_entry(new_entry, req->edit_value)) != 0)
      msg_fatal("%s: \"%s\"", err, req->raw_text);
  pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
  pcf_free_master_entry(new_entry);
     } else if ((mode & PCF_MASTER_ENTRY) == 0) {
  msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
     }
 }
    }

    /*
     * When all is well, rename the temp file to the original one.
     */

    if (vstream_fclose(src))
 msg_fatal("read %s: %m", path);
    if (edit_file_close(ep) != 0)
 msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);

    /*
     * Cleanup.
     */

    vstring_free(line_buf);
    vstring_free(parse_buf);
    vstring_free(full_entry_buf);
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
 argv_free(req->service_pattern);
 myfree(req->parsed_text);
    }
    myfree((void *) edit_reqs);
}

Messung V0.5 in Prozent
C=74 H=94 G=84

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.31Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.