コード例 #1
0
ファイル: fdupes.c プロジェクト: ZiRo-/fdupes
int main(int argc, char **argv) {
  int x;
  int opt;
  FILE *file1;
  FILE *file2;
  file_t *files = NULL;
  file_t *curfile;
  file_t **match = NULL;
  filetree_t *checktree = NULL;
  int filecount = 0;
  int progress = 0;
  char **oldargv;
  int firstrecurse;
  ordertype_t ordertype = ORDER_TIME;
  
#ifndef OMIT_GETOPT_LONG
  static struct option long_options[] = 
  {
    { "omitfirst", 0, 0, 'f' },
    { "recurse", 0, 0, 'r' },
    { "recursive", 0, 0, 'r' },
    { "recurse:", 0, 0, 'R' },
    { "recursive:", 0, 0, 'R' },
    { "quiet", 0, 0, 'q' },
    { "sameline", 0, 0, '1' },
    { "size", 0, 0, 'S' },
    { "symlinks", 0, 0, 's' },
    { "hardlinks", 0, 0, 'H' },
    { "relink", 0, 0, 'l' },
    { "noempty", 0, 0, 'n' },
    { "nohidden", 0, 0, 'A' },
    { "delete", 0, 0, 'd' },
    { "version", 0, 0, 'v' },
    { "help", 0, 0, 'h' },
    { "noprompt", 0, 0, 'N' },
    { "summarize", 0, 0, 'm'},
    { "summary", 0, 0, 'm' },
    { "permissions", 0, 0, 'p' },
    { "order", 1, 0, 'o' },
    { "reverse", 0, 0, 'i' },
    { 0, 0, 0, 0 }
  };
#define GETOPT getopt_long
#else
#define GETOPT getopt
#endif

  program_name = argv[0];

  oldargv = cloneargs(argc, argv);

  while ((opt = GETOPT(argc, argv, "frRq1SsHlnAdvhNmpo:i"
#ifndef OMIT_GETOPT_LONG
          , long_options, NULL
#endif
          )) != EOF) {
    switch (opt) {
    case 'f':
      SETFLAG(flags, F_OMITFIRST);
      break;
    case 'r':
      SETFLAG(flags, F_RECURSE);
      break;
    case 'R':
      SETFLAG(flags, F_RECURSEAFTER);
      break;
    case 'q':
      SETFLAG(flags, F_HIDEPROGRESS);
      break;
    case '1':
      SETFLAG(flags, F_DSAMELINE);
      break;
    case 'S':
      SETFLAG(flags, F_SHOWSIZE);
      break;
    case 's':
      SETFLAG(flags, F_FOLLOWLINKS);
      break;
    case 'H':
      SETFLAG(flags, F_CONSIDERHARDLINKS);
      break;
    case 'n':
      SETFLAG(flags, F_EXCLUDEEMPTY);
      break;
    case 'A':
      SETFLAG(flags, F_EXCLUDEHIDDEN);
      break;
    case 'd':
      SETFLAG(flags, F_DELETEFILES);
      break;
    case 'v':
      printf("fdupes %s\n", VERSION);
      exit(0);
    case 'h':
      help_text();
      exit(1);
    case 'N':
      SETFLAG(flags, F_NOPROMPT);
      break;
    case 'm':
      SETFLAG(flags, F_SUMMARIZEMATCHES);
      break;
    case 'p':
      SETFLAG(flags, F_PERMISSIONS);
      break;
    case 'o':
      if (!strcasecmp("name", optarg)) {
        ordertype = ORDER_NAME;
      } else if (!strcasecmp("time", optarg)) {
        ordertype = ORDER_TIME;
      } else {
        errormsg("invalid value for --order: '%s'\n", optarg);
        exit(1);
      }
      break;
    case 'i':
      SETFLAG(flags, F_REVERSE);
      break;

    default:
      fprintf(stderr, "Try `fdupes --help' for more information.\n");
      exit(1);
    }
  }

  if (optind >= argc) {
    errormsg("no directories specified\n");
    exit(1);
  }

  if (ISFLAG(flags, F_RECURSE) && ISFLAG(flags, F_RECURSEAFTER)) {
    errormsg("options --recurse and --recurse: are not compatible\n");
    exit(1);
  }

  if (ISFLAG(flags, F_SUMMARIZEMATCHES) && ISFLAG(flags, F_DELETEFILES)) {
    errormsg("options --summarize and --delete are not compatible\n");
    exit(1);
  }

  if (ISFLAG(flags, F_RECURSEAFTER)) {
    firstrecurse = nonoptafter("--recurse:", argc, oldargv, argv, optind);
    
    if (firstrecurse == argc)
      firstrecurse = nonoptafter("-R", argc, oldargv, argv, optind);

    if (firstrecurse == argc) {
      errormsg("-R option must be isolated from other options\n");
      exit(1);
    }

    /* F_RECURSE is not set for directories before --recurse: */
    for (x = optind; x < firstrecurse; x++)
      filecount += grokdir(argv[x], &files);

    /* Set F_RECURSE for directories after --recurse: */
    SETFLAG(flags, F_RECURSE);

    for (x = firstrecurse; x < argc; x++)
      filecount += grokdir(argv[x], &files);
  } else {
    for (x = optind; x < argc; x++)
      filecount += grokdir(argv[x], &files);
  }

  if (!files) {
    if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");
    exit(0);
  }
  
  curfile = files;

  while (curfile) {
    if (!checktree) 
      registerfile(&checktree, curfile);
    else 
      match = checkmatch(&checktree, checktree, curfile);

    if (match != NULL) {
      file1 = fopen(curfile->d_name, "rb");
      if (!file1) {
	curfile = curfile->next;
	continue;
      }
      
      file2 = fopen((*match)->d_name, "rb");
      if (!file2) {
	fclose(file1);
	curfile = curfile->next;
	continue;
      }

      if (confirmmatch(file1, file2)) {
        registerpair(match, curfile,
            (ordertype == ORDER_TIME) ? sort_pairs_by_mtime : sort_pairs_by_filename );
	
	/*match->hasdupes = 1;
        curfile->duplicates = match->duplicates;
        match->duplicates = curfile;*/
      }
      
      fclose(file1);
      fclose(file2);
    }

    curfile = curfile->next;

    if (!ISFLAG(flags, F_HIDEPROGRESS)) {
      fprintf(stderr, "\rProgress [%d/%d] %d%% ", progress, filecount,
       (int)((float) progress / (float) filecount * 100.0));
      progress++;
    }
  }

  if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");

  if (ISFLAG(flags, F_DELETEFILES))
  {
    if (ISFLAG(flags, F_NOPROMPT))
    {
      deletefiles(files, 0, 0);
    }
    else
    {
      if (freopen("/dev/tty", "r", stdin) == 0)
      {
        errormsg("could not open terminal for input\n");
        exit(1);
      }

      deletefiles(files, 1, stdin);
    }
  }

  else 

    if (ISFLAG(flags, F_SUMMARIZEMATCHES))
      summarizematches(files);
      
    else

      printmatches(files);

  while (files) {
    curfile = files->next;
    free(files->d_name);
    free(files->crcsignature);
    free(files->crcpartial);
    free(files);
    files = curfile;
  }

  for (x = 0; x < argc; x++)
    free(oldargv[x]);

  free(oldargv);

  purgetree(checktree);

  return 0;
}
コード例 #2
0
ファイル: diod.c プロジェクト: alepharchives/diod-ether
int
main(int argc, char **argv)
{
    int c;
    char *copt = NULL;
    srvmode_t mode = SRV_NORMAL;
    int rfdno = -1, wfdno = -1;
   
    diod_log_init (argv[0]); 
    diod_conf_init ();

    /* config file overrides defaults */
    opterr = 0;
    while ((c = GETOPT (argc, argv, OPTIONS, longopts)) != -1) {
        switch (c) {
            case 'c':   /* --config-file PATH */
                copt = optarg;
                break;
            default:
                break;
        }
    }
    diod_conf_init_config_file (copt);

    /* Command line overrides config file.
     */
    optind = 0;
    opterr = 0;
    while ((c = GETOPT (argc, argv, OPTIONS, longopts)) != -1) {
        switch (c) {
            case 'f':   /* --foreground */
                diod_conf_set_foreground (1);
                break;
            case 'r':   /* --rfdno */
                mode = SRV_FILEDES;
                rfdno = strtoul (optarg, NULL, 10);
                break;
            case 'w':   /* --wfdno */
                mode = SRV_FILEDES;
                wfdno = strtoul (optarg, NULL, 10);
                break;
            case 'd':   /* --debug MASK */
                diod_conf_set_debuglevel (strtoul (optarg, NULL, 0));
                break;
            case 'l':   /* --listen HOST:PORT */
                if (!diod_conf_opt_listen ())
                    diod_conf_clr_listen ();
                if (!strchr (optarg, ':'))
                    usage ();
                diod_conf_add_listen (optarg);
                break;
            case 't':   /* --nwthreads INT */
                diod_conf_set_nwthreads (strtoul (optarg, NULL, 10));
                break;
            case 'm':   /* --maxmmap INT */
                diod_conf_set_maxmmap (strtoul (optarg, NULL, 10));
                break;
            case 'c':   /* --config-file PATH */
                break;
            case 'e':   /* --export PATH */
                if (!diod_conf_opt_exports ())
                    diod_conf_clr_exports ();
                diod_conf_add_exports (optarg);
                break;
            case 'E':   /* --export-all */
                diod_conf_set_exportall (1);
                break;
            case 'o':   /* --export-ops opt,[opt,...] */
                diod_conf_set_exportopts (optarg);
                break;
            case 'n':   /* --no-auth */
                diod_conf_set_auth_required (0);
                break;
            case 'p':   /* --statfs-passthru */
                diod_conf_set_statfs_passthru (0);
                break;
            case 'N':   /* --no-userdb */
                diod_conf_set_userdb (0);
                break;
            case 'S':   /* --allsquash */
                diod_conf_set_allsquash (1);
                break;
            case 'U':   /* --squashuser USER */
                diod_conf_set_squashuser (optarg);
                break;
            case 'u': { /* --runas-uid UID */
                uid_t uid;
                char *end;

                errno = 0;
                uid = strtoul (optarg, &end, 10);
                if (errno != 0)
                    err_exit ("error parsing --runas-uid argument");
                if (*end != '\0')
                    msg_exit ("error parsing --runas-uid argument");
                diod_conf_set_runasuid (uid);
                break;
            }
            case 'L':   /* --logdest DEST */
                diod_conf_set_logdest (optarg);
                diod_log_set_dest (optarg);
                break;
            default:
                usage();
        }
    }
    if (optind < argc)
        usage();
    if (diod_conf_opt_runasuid () && diod_conf_get_allsquash ())
        msg_exit ("--runas-uid and allsquash cannot be used together");
    if (mode == SRV_FILEDES && (rfdno == -1 || wfdno == -1))
        msg_exit ("--rfdno,wfdno must be used together");

    diod_conf_validate_exports ();

    if (geteuid () == 0)
        _setrlimit ();

    _service_run (mode, rfdno, wfdno);

    diod_conf_fini ();
    diod_log_fini ();

    exit (0);
}
コード例 #3
0
int     main(int argc, char **argv)
{
    SESSION *session;
    char   *host;
    char   *port;
    char   *path;
    int     path_len;
    int     sessions = 1;
    int     ch;
    ssize_t len;
    int     n;
    int     i;
    char   *buf;
    const char *parse_err;
    struct addrinfo *res;
    int     aierr;
    const char *protocols = INET_PROTO_NAME_ALL;
    INET_PROTO_INFO *proto_info;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    signal(SIGPIPE, SIG_IGN);
    msg_vstream_init(argv[0], VSTREAM_ERR);

    /*
     * Parse JCL.
     */
    while ((ch = GETOPT(argc, argv, "46cC:f:l:m:M:r:R:s:t:vw:")) > 0) {
	switch (ch) {
	case '4':
	    protocols = INET_PROTO_NAME_IPV4;
	    break;
	case '6':
	    protocols = INET_PROTO_NAME_IPV6;
	    break;
	case 'c':
	    count++;
	    break;
	case 'C':
	    if ((connect_count = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 'f':
	    sender = optarg;
	    break;
	case 'l':
	    if ((message_length = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 'm':
	    if ((message_count = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 'M':
	    if (*optarg == '[') {
		if (!valid_mailhost_literal(optarg, DO_GRIPE))
		    msg_fatal("bad address literal: %s", optarg);
	    } else {
		if (!valid_hostname(optarg, DO_GRIPE))
		    msg_fatal("bad hostname: %s", optarg);
	    }
	    var_myhostname = optarg;
	    break;
	case 'r':
	    if ((recipients = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 'R':
	    if (fixed_delay > 0 || (random_delay = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 's':
	    if ((sessions = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	case 't':
	    recipient = optarg;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'w':
	    if (random_delay > 0 || (fixed_delay = atoi(optarg)) <= 0)
		usage(argv[0]);
	    break;
	default:
	    usage(argv[0]);
	}
    }
    if (argc - optind != 1)
	usage(argv[0]);

    if (random_delay > 0)
	srand(getpid());

    /*
     * Translate endpoint address to internal form.
     */
    proto_info = inet_proto_init("protocols", protocols);
    if (strncmp(argv[optind], "unix:", 5) == 0) {
	path = argv[optind] + 5;
	path_len = strlen(path);
	if (path_len >= (int) sizeof(sun.sun_path))
	    msg_fatal("unix-domain name too long: %s", path);
	memset((char *) &sun, 0, sizeof(sun));
	sun.sun_family = AF_UNIX;
#ifdef HAS_SUN_LEN
	sun.sun_len = path_len + 1;
#endif
	memcpy(sun.sun_path, path, path_len);
	sa = (struct sockaddr *) & sun;
	sa_length = sizeof(sun);
    } else {
	if (strncmp(argv[optind], "inet:", 5) == 0)
	    argv[optind] += 5;
	buf = mystrdup(argv[optind]);
	if ((parse_err = host_port(buf, &host, (char *) 0, &port, "628")) != 0)
	    msg_fatal("%s: %s", argv[optind], parse_err);
	if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
	    msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr));
	myfree(buf);
	sa = (struct sockaddr *) & ss;
	if (res->ai_addrlen > sizeof(ss))
	    msg_fatal("address length %d > buffer length %d",
		      (int) res->ai_addrlen, (int) sizeof(ss));
	memcpy((char *) sa, res->ai_addr, res->ai_addrlen);
	sa_length = res->ai_addrlen;
#ifdef HAS_SA_LEN
	sa->sa_len = sa_length;
#endif
	freeaddrinfo(res);
    }

    /*
     * Allocate space for temporary buffer.
     */
    buffer = vstring_alloc(100);

    /*
     * Make sure we have sender and recipient addresses.
     */
    if (var_myhostname == 0)
	var_myhostname = get_hostname();
    if (sender == 0 || recipient == 0) {
	vstring_sprintf(buffer, "foo@%s", var_myhostname);
	defaddr = mystrdup(vstring_str(buffer));
	if (sender == 0)
	    sender = defaddr;
	if (recipient == 0)
	    recipient = defaddr;
    }

    /*
     * Prepare some results that may be used multiple times: the message
     * content netstring, the sender netstring, and the recipient netstrings.
     */
    mydate = mail_date(time((time_t *) 0));
    mypid = getpid();

    message_buffer = vstring_alloc(message_length + 200);
    vstring_sprintf(buffer,
		  "From: <%s>\nTo: <%s>\nDate: %s\nMessage-Id: <%d@%s>\n\n",
		    sender, recipient, mydate, mypid, var_myhostname);
    for (n = 1; LEN(buffer) < message_length; n++) {
	for (i = 0; i < n && i < 79; i++)
	    VSTRING_ADDCH(buffer, 'X');
	VSTRING_ADDCH(buffer, '\n');
    }
    STR(buffer)[message_length - 1] = '\n';
    netstring_memcpy(message_buffer, STR(buffer), message_length);

    len = strlen(sender);
    sender_buffer = vstring_alloc(len);
    netstring_memcpy(sender_buffer, sender, len);

    if (recipients == 1) {
	len = strlen(recipient);
	recipient_buffer = vstring_alloc(len);
	netstring_memcpy(recipient_buffer, recipient, len);
    } else {
	recipient_buffer = vstring_alloc(100);
	for (n = 0; n < recipients; n++) {
	    vstring_sprintf(buffer, "%d%s", n, recipient);
	    netstring_memcat(recipient_buffer, STR(buffer), LEN(buffer));
	}
    }

    /*
     * Start sessions.
     */
    while (sessions-- > 0) {
	session = (SESSION *) mymalloc(sizeof(*session));
	session->stream = 0;
	session->xfer_count = 0;
	session->connect_count = connect_count;
	session->next = 0;
	session_count++;
	startup(session);
    }
    for (;;) {
	event_loop(-1);
	if (session_count <= 0 && message_count <= 0) {
	    if (count) {
		VSTREAM_PUTC('\n', VSTREAM_OUT);
		vstream_fflush(VSTREAM_OUT);
	    }
	    exit(0);
	}
    }
}
コード例 #4
0
ファイル: postdrop.c プロジェクト: ii0/postfix
int     main(int argc, char **argv)
{
    struct stat st;
    int     fd;
    int     c;
    VSTRING *buf;
    int     status;
    MAIL_STREAM *dst;
    int     rec_type;
    static char *segment_info[] = {
	REC_TYPE_POST_ENVELOPE, REC_TYPE_POST_CONTENT, REC_TYPE_POST_EXTRACT, ""
    };
    char  **expected;
    uid_t   uid = getuid();
    ARGV   *import_env;
    const char *error_text;
    char   *attr_name;
    char   *attr_value;
    const char *errstr;
    char   *junk;
    struct timeval start;
    int     saved_errno;
    int     from_count = 0;
    int     rcpt_count = 0;
    int     validate_input = 1;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Set up logging. Censor the process name: it is provided by the user.
     */
    argv[0] = "postdrop";
    msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
    set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * Parse JCL. This program is set-gid and must sanitize all command-line
     * arguments. The configuration directory argument is validated by the
     * mail configuration read routine. Don't do complex things until we have
     * completed initializations.
     */
    while ((c = GETOPT(argc, argv, "c:rv")) > 0) {
	switch (c) {
	case 'c':
	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
		msg_fatal("out of memory");
	    break;
	case 'r':				/* forward compatibility */
	    break;
	case 'v':
	    if (geteuid() == 0)
		msg_verbose++;
	    break;
	default:
	    msg_fatal("usage: %s [-c config_dir] [-v]", argv[0]);
	}
    }

    /*
     * Read the global configuration file and extract configuration
     * information. Some claim that the user should supply the working
     * directory instead. That might be OK, given that this command needs
     * write permission in a subdirectory called "maildrop". However we still
     * need to reliably detect incomplete input, and so we must perform
     * record-level I/O. With that, we should also take the opportunity to
     * perform some sanity checks on the input.
     */
    mail_conf_read();
    /* Re-evaluate mail_task() after reading main.cf. */
    msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
    get_mail_conf_str_table(str_table);

    /*
     * Mail submission access control. Should this be in the user-land gate,
     * or in the daemon process?
     */
    mail_dict_init();
    if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl,
				       uid)) != 0)
	msg_fatal("User %s(%ld) is not allowed to submit mail",
		  errstr, (long) uid);

    /*
     * Stop run-away process accidents by limiting the queue file size. This
     * is not a defense against DOS attack.
     */
    if (var_message_limit > 0 && get_file_limit() > var_message_limit)
	set_file_limit((off_t) var_message_limit);

    /*
     * This program is installed with setgid privileges. Strip the process
     * environment so that we don't have to trust the C library.
     */
    import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
    clean_env(import_env->argv);
    argv_free(import_env);

    if (chdir(var_queue_dir))
	msg_fatal("chdir %s: %m", var_queue_dir);
    if (msg_verbose)
	msg_info("chdir %s", var_queue_dir);

    /*
     * Set up signal handlers and a runtime error handler so that we can
     * clean up incomplete output.
     * 
     * postdrop_sig() uses the in-kernel SIGINT handler address as an atomic
     * variable to prevent nested postdrop_sig() calls. For this reason, the
     * SIGINT handler must be configured before other signal handlers are
     * allowed to invoke postdrop_sig().
     */
    signal(SIGPIPE, SIG_IGN);
    signal(SIGXFSZ, SIG_IGN);

    signal(SIGINT, postdrop_sig);
    signal(SIGQUIT, postdrop_sig);
    if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
	signal(SIGTERM, postdrop_sig);
    if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
	signal(SIGHUP, postdrop_sig);
    msg_cleanup(postdrop_cleanup);

    /* End of initializations. */

    /*
     * Don't trust the caller's time information.
     */
    GETTIMEOFDAY(&start);

    /*
     * Create queue file. mail_stream_file() never fails. Send the queue ID
     * to the caller. Stash away a copy of the queue file name so we can
     * clean up in case of a fatal error or an interrupt.
     */
    dst = mail_stream_file(MAIL_QUEUE_MAILDROP, MAIL_CLASS_PUBLIC,
			   var_pickup_service, 0444);
    attr_print(VSTREAM_OUT, ATTR_FLAG_NONE,
	       SEND_ATTR_STR(MAIL_ATTR_QUEUEID, dst->id),
	       ATTR_TYPE_END);
    vstream_fflush(VSTREAM_OUT);
    postdrop_path = mystrdup(VSTREAM_PATH(dst->stream));

    /*
     * Copy stdin to file. The format is checked so that we can recognize
     * incomplete input and cancel the operation. With the sanity checks
     * applied here, the pickup daemon could skip format checks and pass a
     * file descriptor to the cleanup daemon. These are by no means all
     * sanity checks - the cleanup service and queue manager services will
     * reject messages that lack required information.
     * 
     * If something goes wrong, slurp up the input before responding to the
     * client, otherwise the client will give up after detecting SIGPIPE.
     * 
     * Allow attribute records if the attribute specifies the MIME body type
     * (sendmail -B).
     */
    vstream_control(VSTREAM_IN, CA_VSTREAM_CTL_PATH("stdin"), CA_VSTREAM_CTL_END);
    buf = vstring_alloc(100);
    expected = segment_info;
    /* Override time information from the untrusted caller. */
    rec_fprintf(dst->stream, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT,
		REC_TYPE_TIME_ARG(start));
    for (;;) {
	/* Don't allow PTR records. */
	rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, REC_FLAG_NONE);
	if (rec_type == REC_TYPE_EOF) {		/* request cancelled */
	    mail_stream_cleanup(dst);
	    if (remove(postdrop_path))
		msg_warn("uid=%ld: remove %s: %m", (long) uid, postdrop_path);
	    else if (msg_verbose)
		msg_info("remove %s", postdrop_path);
	    myfree(postdrop_path);
	    postdrop_path = 0;
	    exit(0);
	}
	if (rec_type == REC_TYPE_ERROR)
	    msg_fatal("uid=%ld: malformed input", (long) uid);
	if (strchr(*expected, rec_type) == 0)
	    msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type);
	if (rec_type == **expected)
	    expected++;
	/* Override time information from the untrusted caller. */
	if (rec_type == REC_TYPE_TIME)
	    continue;
	/* Check these at submission time instead of pickup time. */
	if (rec_type == REC_TYPE_FROM)
	    from_count++;
	if (rec_type == REC_TYPE_RCPT)
	    rcpt_count++;
	/* Limit the attribute types that users may specify. */
	if (rec_type == REC_TYPE_ATTR) {
	    if ((error_text = split_nameval(vstring_str(buf), &attr_name,
					    &attr_value)) != 0) {
		msg_warn("uid=%ld: ignoring malformed record: %s: %.200s",
			 (long) uid, error_text, vstring_str(buf));
		continue;
	    }
#define STREQ(x,y) (strcmp(x,y) == 0)

	    if ((STREQ(attr_name, MAIL_ATTR_ENCODING)
		 && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
		     || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
		     || STREQ(attr_value, MAIL_ATTR_ENC_NONE)))
		|| STREQ(attr_name, MAIL_ATTR_DSN_ENVID)
		|| STREQ(attr_name, MAIL_ATTR_DSN_NOTIFY)
		|| rec_attr_map(attr_name)
		|| (STREQ(attr_name, MAIL_ATTR_RWR_CONTEXT)
		    && (STREQ(attr_value, MAIL_ATTR_RWR_LOCAL)
			|| STREQ(attr_value, MAIL_ATTR_RWR_REMOTE)))
		|| STREQ(attr_name, MAIL_ATTR_TRACE_FLAGS)) {	/* XXX */
		rec_fprintf(dst->stream, REC_TYPE_ATTR, "%s=%s",
			    attr_name, attr_value);
	    } else {
		msg_warn("uid=%ld: ignoring attribute record: %.200s=%.200s",
			 (long) uid, attr_name, attr_value);
	    }
	    continue;
	}
	if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) {
	    /* rec_get() errors must not clobber errno. */
	    saved_errno = errno;
	    while ((rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit,
					   REC_FLAG_NONE)) != REC_TYPE_END
		   && rec_type != REC_TYPE_EOF)
		if (rec_type == REC_TYPE_ERROR)
		    msg_fatal("uid=%ld: malformed input", (long) uid);
	    validate_input = 0;
	    errno = saved_errno;
	    break;
	}
	if (rec_type == REC_TYPE_END)
	    break;
    }
    vstring_free(buf);

    /*
     * As of Postfix 2.7 the pickup daemon discards mail without recipients.
     * Such mail may enter the maildrop queue when "postsuper -r" is invoked
     * before the queue manager deletes an already delivered message. Looking
     * at file ownership is not a good way to make decisions on what mail to
     * discard. Instead, the pickup server now requires that new submissions
     * always have at least one recipient record.
     * 
     * The Postfix sendmail command already rejects mail without recipients.
     * However, in the future postdrop may receive mail via other programs,
     * so we add a redundant recipient check here for future proofing.
     * 
     * The test for the sender address is just for consistency of error
     * reporting (report at submission time instead of pickup time). Besides
     * the segment terminator records, there aren't any other mandatory
     * records in a Postfix submission queue file.
     */
    if (validate_input && (from_count == 0 || rcpt_count == 0)) {
	status = CLEANUP_STAT_BAD;
	mail_stream_cleanup(dst);
    }

    /*
     * Finish the file.
     */
    else if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) {
	msg_warn("uid=%ld: %m", (long) uid);
	postdrop_cleanup();
    }

    /*
     * Disable deletion on fatal error before reporting success, so the file
     * will not be deleted after we have taken responsibility for delivery.
     */
    if (postdrop_path) {
	junk = postdrop_path;
	postdrop_path = 0;
	myfree(junk);
    }

    /*
     * Send the completion status to the caller and terminate.
     */
    attr_print(VSTREAM_OUT, ATTR_FLAG_NONE,
	       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
	       SEND_ATTR_STR(MAIL_ATTR_WHY, ""),
	       ATTR_TYPE_END);
    vstream_fflush(VSTREAM_OUT);
    exit(status);
}
コード例 #5
0
ファイル: hfind.cpp プロジェクト: sleuthkit/sleuthkit
int
main(int argc, char ** argv1)
{
    int ch;
    TSK_TCHAR *idx_type = NULL;
    TSK_TCHAR *db_file = NULL;
    TSK_TCHAR *lookup_file = NULL;
    unsigned int flags = 0;
    TSK_HDB_INFO *hdb_info;
    TSK_TCHAR **argv;
    bool create = false;
    bool addHash = false;

#ifdef TSK_WIN32
    // On Windows, get the wide arguments (mingw doesn't support wmain)
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if( argv == NULL) {    
        tsk_fprintf(stderr, "Error getting wide arguments\n");
        exit(1);
    }
#else
    argv = (TSK_TCHAR **)argv1;
#endif
    
    progname = argv[0];
    setlocale(LC_ALL, "");

    while ((ch = GETOPT(argc, argv, _TSK_T("cef:i:aqV"))) > 0) {
        switch (ch) {
        case _TSK_T('e'):
            flags |= TSK_HDB_FLAG_EXT;
            break;

        case _TSK_T('f'):
            lookup_file = OPTARG;
            break;

        case _TSK_T('i'):
            idx_type = OPTARG;
            break;

        case _TSK_T('c'):
            create = true;
            break;

        case _TSK_T('a'):
            addHash = true;
            break;

        case _TSK_T('q'):
            flags |= TSK_HDB_FLAG_QUICK;
            break;

        case _TSK_T('V'):
            tsk_version_print(stdout);
            exit(0);

        default:
            usage();
        }
    }
    
    if ((addHash) && ((idx_type != NULL) || (create))) {
        tsk_fprintf(stderr, "-a cannot be specified with -c or -i\n");
        usage();
    }

    if (OPTIND + 1 > argc) {
        tsk_fprintf(stderr,
                    "Error: You must provide the source hash database location\n");
        usage();
    }

    db_file = argv[OPTIND++];

    // Running in create mode (-c option). Make a new hash database and exit.
    if (create) {
        if (idx_type != NULL) {
            tsk_fprintf(stderr, "-c and -i cannot be specified at same time\n");
            usage();
        }
        
        TSK_TCHAR *ext = TSTRRCHR(db_file, _TSK_T('.'));    
        if ((NULL != ext) && (TSTRLEN(ext) >= 4) && (TSTRCMP(ext, _TSK_T(".kdb")) == 0)) {
            if (0 == tsk_hdb_create(db_file)) {
                tsk_fprintf(stdout, "New database %" PRIttocTSK" created\n", db_file);
                return 0;
            }
            else {
                tsk_fprintf(stderr, "Failed to create new database %" PRIttocTSK"\n", db_file);
                return 1;
            }        
        }
        else {
            tsk_fprintf(stderr, "New database path must end in .kdb extension\n");
            return 1;
        }
    }
        
    // Opening an existing database.    
    if ((hdb_info = tsk_hdb_open(db_file, TSK_HDB_OPEN_NONE)) == NULL) {
        tsk_error_print(stderr);
        return 1;
    }
    
    // Now that the database is open and its type is known, if running in add hashes mode (-a option)
    // see if it takes updates.
    if (addHash && !tsk_hdb_accepts_updates(hdb_info)) {
        tsk_fprintf(stderr, "-a option specified, but the specified database does not allow hashes to be added\n");
        usage();
    }

    // Running in indexing mode (-i option). Create an index file and exit.
    if (idx_type != NULL) {
        if (lookup_file != NULL) {
            tsk_fprintf(stderr, "'-f' flag can't be used with '-i'\n");
            usage();
        }

        if (flags & TSK_HDB_FLAG_QUICK) {
            tsk_fprintf(stderr, "'-q' flag can't be used with '-i'\n");
            usage();
        }

        if (flags & TSK_HDB_FLAG_EXT) {
            tsk_fprintf(stderr, "'-e' flag can't be used with '-i'\n");
            usage();
        }

        if (!tsk_hdb_uses_external_indexes(hdb_info)) {
            tsk_fprintf(stderr, "Database does not use external indexes, can't be used with '-i'\n");
        }

        if (tsk_hdb_is_idx_only(hdb_info)) {
            tsk_fprintf(stderr, "Database is index only, can be used for look ups, but can't be used with '-i'\n");
        }

        if (tsk_hdb_make_index(hdb_info, idx_type)) {
            tsk_error_print(stderr);
            tsk_hdb_close(hdb_info);
            return 1;
        }
        
        tsk_fprintf(stdout, "Index created\n");
        tsk_hdb_close(hdb_info);
        return 0;
    }

    /* Either lookup hash values or add them to DB.
     * Check if the values were passed on the command line or via a file 
     */
    if (OPTIND < argc) {

        if ((OPTIND + 1 < argc) && (flags & TSK_HDB_FLAG_QUICK)) {
            fprintf(stderr,
                    "Error: Only one hash can be given with quick option\n");
            usage();
        }

        if ((flags & TSK_HDB_FLAG_EXT) && (flags & TSK_HDB_FLAG_QUICK)) {
            fprintf(stderr, "'-e' flag can't be used with '-q'\n");
            usage();
        }

        if (lookup_file != NULL) {
            fprintf(stderr,
                    "Error: -f can't be used when hashes are also given\n");
            usage();
        }

        /* Loop through all provided hash values
         */
        while (OPTIND < argc) {
            char htmp[128];
            int i;
            int retval;

            // convert to char -- lazy way to deal with WCHARs..
            for (i = 0; i < 127 && argv[OPTIND][i] != '\0'; i++) {
                htmp[i] = (char) argv[OPTIND][i];
            }
            htmp[i] = '\0';

            if (addHash) {
                // Write a new hash to the database/index, if it's updateable
                //@todo support sha1 and sha2-256
                retval = tsk_hdb_add_entry(hdb_info, NULL, (const char *)htmp, NULL, NULL, NULL);
                if (retval == 1) {
                    printf("There was an error adding the hash.\n");
                    tsk_error_print(stderr);
                    return 1;
                }
                else if (retval == 0) {
                    printf("Hash %s added.\n", htmp);
                }
            }
            else {
                /* Perform lookup */
                retval = tsk_hdb_lookup_str(hdb_info, (const char *)htmp, 
                         (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL);
                if (retval == -1) {
                    tsk_error_print(stderr);
                    return 1;
                }
                if (flags & TSK_HDB_FLAG_QUICK) {
                    printf("%d\n", retval);
                }
                else if (retval == 0) {
                    print_notfound(htmp);
                }
            }
            OPTIND++;
        }
    }
    /* Hash were given from stdin or a file */
    else {
        char buf[100];

        /* If the file was specified, use that - otherwise stdin */
#ifdef TSK_WIN32
        HANDLE handle = NULL;
        if (lookup_file != NULL) {
            if ((handle = CreateFile(lookup_file, GENERIC_READ,
                                     FILE_SHARE_READ, 0, OPEN_EXISTING, 0,
                                     0)) == INVALID_HANDLE_VALUE) {
                TFPRINTF(stderr, _TSK_T("Error opening hash file: %s\n"),
                         lookup_file);
                exit(1);
            }
        }
        else {
            handle = GetStdHandle(STD_INPUT_HANDLE);
        }
#else
        FILE *handle = NULL;
        if (lookup_file != NULL) {
            handle = fopen(lookup_file, "r");
            if (!handle) {
                fprintf(stderr, "Error opening hash file: %s\n",
                        lookup_file);
                exit(1);
            }
        }
        else {
            handle = stdin;
        }
#endif

        while (1) {
            int retval;
            memset(buf, 0, 100);
#ifdef TSK_WIN32
            int done = 0;
            // win32 doesn't have a fgets equivalent, so we make an equivalent one
            for (int i = 0; i < 100; i++) {
                DWORD nread;

                if (FALSE == ReadFile(handle, &buf[i], (DWORD) 1, &nread, NULL)) {
                    done = 1;
                    break;
                }
                // skip the windows CR
                else if (buf[i] == '\r') {
                    buf[i] = '\0';
                    i--;
                    continue;
                }
                else if (buf[i] == '\n') {
                    break;
                }
            }
            
            if (done)
                break;
#else
            if (NULL == fgets(buf, 100, handle)) {
                break;
            }
#endif

            /* Remove the newline */
            buf[strlen(buf) - 1] = '\0';

            retval =
                tsk_hdb_lookup_str(hdb_info, (const char *)buf, 
                        (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL);
            if (retval == -1) {
                tsk_error_print(stderr);
                return 1;
            }
            if (flags & TSK_HDB_FLAG_QUICK) {
                printf("%d\n", retval);
                break;
            }
            else if (retval == 0) {
                print_notfound(buf);
            }
        }
        
#ifdef TSK_WIN32
        if (lookup_file != NULL)
            CloseHandle(handle);
#else
        if (lookup_file != NULL)
            fclose(handle);
#endif
        
    }

    tsk_hdb_close(hdb_info);
    return 0;
}
コード例 #6
0
ファイル: postconf.c プロジェクト: ystk/debian-postfix
int     main(int argc, char **argv)
{
    int     ch;
    int     fd;
    struct stat st;
    int     junk;
    ARGV   *ext_argv = 0;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Set up logging.
     */
    msg_vstream_init(argv[0], VSTREAM_ERR);

    /*
     * Parse JCL.
     */
    while ((ch = GETOPT(argc, argv, "aAbc:deE#hmlntv")) > 0) {
	switch (ch) {
	case 'a':
	    cmd_mode |= SHOW_SASL_SERV;
	    break;
	case 'A':
	    cmd_mode |= SHOW_SASL_CLNT;
	    break;
	case 'b':
	    if (ext_argv)
		msg_fatal("specify one of -b and -t");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0);
	    break;
	case 'c':
	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
		msg_fatal("out of memory");
	    break;
	case 'd':
	    cmd_mode |= SHOW_DEFS;
	    break;
	case 'e':
	    cmd_mode |= EDIT_MAIN;
	    break;

	    /*
	     * People, this does not work unless you properly handle default
	     * settings. For example, fast_flush_domains = $relay_domains
	     * must not evaluate to the empty string when relay_domains is
	     * left at its default setting of $mydestination.
	     */
#if 0
	case 'E':
	    cmd_mode |= SHOW_EVAL;
	    break;
#endif
	case '#':
	    cmd_mode = COMMENT_OUT;
	    break;

	case 'h':
	    cmd_mode &= ~SHOW_NAME;
	    break;
	case 'l':
	    cmd_mode |= SHOW_LOCKS;
	    break;
	case 'm':
	    cmd_mode |= SHOW_MAPS;
	    break;
	case 'n':
	    cmd_mode |= SHOW_NONDEF;
	    break;
	case 't':
	    if (ext_argv)
		msg_fatal("specify one of -b and -t");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0);
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	default:
	    msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-d (defaults)] [-e (edit)] [-# (comment-out)] [-h (no names)] [-l (lock types)] [-m (map types)] [-n (non-defaults)] [-v] [name...]", argv[0]);
	}
    }

    /*
     * Sanity check.
     */
    junk = (cmd_mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT));
    if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF
	     && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN
		       && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT
		       && junk != COMMENT_OUT)
		      || ext_argv != 0))
	msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -m, -l and -n");

    /*
     * Display bounce template information and exit.
     */
    if (ext_argv) {
	if (argv[optind]) {
	    if (argv[optind + 1])
		msg_fatal("options -b and -t require at most one template file");
	    argv_add(ext_argv, "-o",
		     concatenate(VAR_BOUNCE_TMPL, "=",
				 argv[optind], (char *) 0),
		     (char *) 0);
	}
	/* Grr... */
	argv_add(ext_argv, "-o",
		 concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0),
		 (char *) 0);
	mail_conf_read();
	mail_run_replace(var_daemon_dir, ext_argv->argv);
	/* NOTREACHED */
    }

    /*
     * If showing map types, show them and exit
     */
    if (cmd_mode & SHOW_MAPS) {
	mail_dict_init();
	show_maps();
    }

    /*
     * If showing locking methods, show them and exit
     */
    else if (cmd_mode & SHOW_LOCKS) {
	show_locks();
    }

    /*
     * If showing SASL plug-in types, show them and exit
     */
    else if (cmd_mode & SHOW_SASL_SERV) {
	show_sasl(SHOW_SASL_SERV);
    } else if (cmd_mode & SHOW_SASL_CLNT) {
	show_sasl(SHOW_SASL_CLNT);
    }

    /*
     * Edit main.cf.
     */
    else if (cmd_mode & (EDIT_MAIN | COMMENT_OUT)) {
	edit_parameters(cmd_mode, argc - optind, argv + optind);
    }

    /*
     * If showing non-default values, read main.cf.
     */
    else {
	if ((cmd_mode & SHOW_DEFS) == 0) {
	    read_parameters();
	    set_parameters();
	}

	/*
	 * Throw together all parameters and show the asked values.
	 */
	hash_parameters();
	show_parameters(cmd_mode, argv + optind);
    }
    vstream_fflush(VSTREAM_OUT);
    exit(0);
}
コード例 #7
0
ファイル: postalias.c プロジェクト: ii0/postfix
int     main(int argc, char **argv)
{
    char   *path_name;
    int     ch;
    int     fd;
    char   *slash;
    struct stat st;
    int     postalias_flags = POSTALIAS_FLAG_AS_OWNER | POSTALIAS_FLAG_SAVE_PERM;
    int     open_flags = O_RDWR | O_CREAT | O_TRUNC;
    int     dict_flags = (DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX
			  | DICT_FLAG_UTF8_REQUEST);
    char   *query = 0;
    char   *delkey = 0;
    int     sequence = 0;
    int     found;
    ARGV   *import_env;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Process environment options as early as we can. We are not set-uid,
     * and we are supposed to be running in a controlled environment.
     */
    if (getenv(CONF_ENV_VERB))
	msg_verbose = 1;

    /*
     * Initialize. Set up logging, read the global configuration file and
     * extract configuration information.
     */
    if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
	argv[0] = slash + 1;
    msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * Parse JCL.
     */
    while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rsuvw")) > 0) {
	switch (ch) {
	default:
	    usage(argv[0]);
	    break;
	case 'N':
	    dict_flags |= DICT_FLAG_TRY1NULL;
	    dict_flags &= ~DICT_FLAG_TRY0NULL;
	    break;
	case 'c':
	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
		msg_fatal("out of memory");
	    break;
	case 'd':
	    if (sequence || query || delkey)
		msg_fatal("specify only one of -s -q or -d");
	    delkey = optarg;
	    break;
	case 'f':
	    dict_flags &= ~DICT_FLAG_FOLD_FIX;
	    break;
	case 'i':
	    open_flags &= ~O_TRUNC;
	    break;
	case 'n':
	    dict_flags |= DICT_FLAG_TRY0NULL;
	    dict_flags &= ~DICT_FLAG_TRY1NULL;
	    break;
	case 'o':
	    postalias_flags &= ~POSTALIAS_FLAG_AS_OWNER;
	    break;
	case 'p':
	    postalias_flags &= ~POSTALIAS_FLAG_SAVE_PERM;
	    break;
	case 'q':
	    if (sequence || query || delkey)
		msg_fatal("specify only one of -s -q or -d");
	    query = optarg;
	    break;
	case 'r':
	    dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
	    dict_flags |= DICT_FLAG_DUP_REPLACE;
	    break;
	case 's':
	    if (query || delkey)
		msg_fatal("specify only one of -s or -q or -d");
	    sequence = 1;
	    break;
	case 'u':
	    dict_flags &= ~DICT_FLAG_UTF8_REQUEST;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'w':
	    dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_REPLACE);
	    dict_flags |= DICT_FLAG_DUP_IGNORE;
	    break;
	}
    }
    mail_conf_read();
    /* Enforce consistent operation of different Postfix parts. */
    import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
    update_env(import_env->argv);
    argv_free(import_env);
    /* Re-evaluate mail_task() after reading main.cf. */
    msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
    mail_dict_init();

    /*
     * Use the map type specified by the user, or fall back to a default
     * database type.
     */
    if (delkey) {				/* remove entry */
	if (optind + 1 > argc)
	    usage(argv[0]);
	if (strcmp(delkey, "-") == 0)
	    exit(postalias_deletes(VSTREAM_IN, argv + optind, argc - optind,
				   dict_flags | DICT_FLAG_LOCK) == 0);
	found = 0;
	while (optind < argc) {
	    if ((path_name = split_at(argv[optind], ':')) != 0) {
		found |= postalias_delete(argv[optind], path_name, delkey,
					  dict_flags | DICT_FLAG_LOCK);
	    } else {
		found |= postalias_delete(var_db_type, argv[optind], delkey,
					  dict_flags | DICT_FLAG_LOCK);
	    }
	    optind++;
	}
	exit(found ? 0 : 1);
    } else if (query) {				/* query map(s) */
	if (optind + 1 > argc)
	    usage(argv[0]);
	if (strcmp(query, "-") == 0)
	    exit(postalias_queries(VSTREAM_IN, argv + optind, argc - optind,
				   dict_flags | DICT_FLAG_LOCK) == 0);
	while (optind < argc) {
	    if ((path_name = split_at(argv[optind], ':')) != 0) {
		found = postalias_query(argv[optind], path_name, query,
					dict_flags | DICT_FLAG_LOCK);
	    } else {
		found = postalias_query(var_db_type, argv[optind], query,
					dict_flags | DICT_FLAG_LOCK);
	    }
	    if (found)
		exit(0);
	    optind++;
	}
	exit(1);
    } else if (sequence) {
	while (optind < argc) {
	    if ((path_name = split_at(argv[optind], ':')) != 0) {
		postalias_seq(argv[optind], path_name,
			      dict_flags | DICT_FLAG_LOCK);
	    } else {
		postalias_seq(var_db_type, argv[optind],
			      dict_flags | DICT_FLAG_LOCK);
	    }
	    exit(0);
	}
	exit(1);
    } else {					/* create/update map(s) */
	if (optind + 1 > argc)
	    usage(argv[0]);
	while (optind < argc) {
	    if ((path_name = split_at(argv[optind], ':')) != 0) {
		postalias(argv[optind], path_name, postalias_flags,
			  open_flags, dict_flags);
	    } else {
		postalias(var_db_type, argv[optind], postalias_flags,
			  open_flags, dict_flags);
	    }
	    optind++;
	}
	exit(0);
    }
}
コード例 #8
0
ファイル: istat.cpp プロジェクト: julezcuad/sleuthkit
int
main(int argc, char **argv1)
{
    TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT;
    TSK_IMG_INFO *img;

    TSK_OFF_T imgaddr = 0;
    TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT;
    TSK_FS_INFO *fs;

    TSK_INUM_T inum;
    int ch;
    TSK_TCHAR *cp;
    int32_t sec_skew = 0;

    /* When > 0 this is the number of blocks to print, used for -B arg */
    TSK_DADDR_T numblock = 0;
    TSK_TCHAR **argv;
    unsigned int ssize = 0;

#ifdef TSK_WIN32
    // On Windows, get the wide arguments (mingw doesn't support wmain)
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (argv == NULL) {
        fprintf(stderr, "Error getting wide arguments\n");
        exit(1);
    }
#else
    argv = (TSK_TCHAR **) argv1;
#endif

    progname = argv[0];
    setlocale(LC_ALL, "");

    while ((ch = GETOPT(argc, argv, _TSK_T("b:B:f:i:o:s:vVz:"))) > 0) {
        switch (ch) {
        case _TSK_T('?'):
        default:
            TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"),
                     argv[OPTIND]);
            usage();
        case _TSK_T('B'):
            numblock = TSTRTOULL(OPTARG, &cp, 0);
            if (*cp || *cp == *OPTARG || numblock < 1) {
                TFPRINTF(stderr,
                         _TSK_T
                         ("invalid argument: block count must be positive: %s\n"),
                         OPTARG);
                usage();
            }
            break;
        case _TSK_T('b'):
            ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0);
            if (*cp || *cp == *OPTARG || ssize < 1) {
                TFPRINTF(stderr,
                         _TSK_T
                         ("invalid argument: sector size must be positive: %s\n"),
                         OPTARG);
                usage();
            }
            break;
        case _TSK_T('f'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_fs_type_print(stderr);
                exit(1);
            }
            fstype = tsk_fs_type_toid(OPTARG);
            if (fstype == TSK_FS_TYPE_UNSUPP) {
                TFPRINTF(stderr,
                         _TSK_T("Unsupported file system type: %s\n"), OPTARG);
                usage();
            }
            break;
        case _TSK_T('i'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_img_type_print(stderr);
                exit(1);
            }
            imgtype = tsk_img_type_toid(OPTARG);
            if (imgtype == TSK_IMG_TYPE_UNSUPP) {
                TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"),
                         OPTARG);
                usage();
            }
            break;
        case _TSK_T('o'):
            if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) {
                tsk_error_print(stderr);
                exit(1);
            }
            break;
        case _TSK_T('s'):
            sec_skew = TATOI(OPTARG);
            break;
        case _TSK_T('v'):
            tsk_verbose++;
            break;
        case _TSK_T('V'):
            tsk_version_print(stdout);
            exit(0);
        case _TSK_T('z'):
        {
            TSK_TCHAR envstr[32];
            TSNPRINTF(envstr, 32, _TSK_T("TZ=%s"), OPTARG);
            if (0 != TPUTENV(envstr)) {
                tsk_fprintf(stderr, "error setting environment");
                exit(1);
            }
            TZSET();
        }
        break;
        }
    }

    /* We need at least two more argument */
    if (OPTIND + 1 >= argc) {
        tsk_fprintf(stderr, "Missing image name and/or address\n");
        usage();
    }

    /* if we are given the inode in the inode-type-id form, then ignore
     * the other stuff w/out giving an error
     *
     * This will make scripting easier
     */
    if (tsk_fs_parse_inum(argv[argc - 1], &inum, NULL, NULL, NULL, NULL)) {
        TFPRINTF(stderr, _TSK_T("Invalid inode number: %s"),
                 argv[argc - 1]);
        usage();
    }

    /*
     * Open the file system.
     */
    if ((img =
                tsk_img_open(argc - OPTIND - 1, &argv[OPTIND],
                             imgtype, ssize)) == NULL) {
        tsk_error_print(stderr);
        exit(1);
    }
    if ((imgaddr * img->sector_size) >= img->size) {
        tsk_fprintf(stderr,
                    "Sector offset supplied is larger than disk image (maximum: %"
                    PRIu64 ")\n", img->size / img->sector_size);
        exit(1);
    }

    if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) {
        tsk_error_print(stderr);
        if (tsk_error_get_errno() == TSK_ERR_FS_UNSUPTYPE)
            tsk_fs_type_print(stderr);
        img->close(img);
        exit(1);
    }

    if (inum > fs->last_inum) {
        tsk_fprintf(stderr,
                    "Metadata address is too large for image (%" PRIuINUM ")\n",
                    fs->last_inum);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    if (inum < fs->first_inum) {
        tsk_fprintf(stderr,
                    "Metadata address is too small for image (%" PRIuINUM ")\n",
                    fs->first_inum);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    if (fs->istat(fs, stdout, inum, numblock, sec_skew)) {
        tsk_error_print(stderr);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    fs->close(fs);
    img->close(img);
    exit(0);
}
コード例 #9
0
ファイル: diodmount.c プロジェクト: doughdemon/diod
int
main (int argc, char *argv[])
{
    char *dir = NULL;
    char *spec, *host;
    char *nspec = NULL;
    int c, i;
    int nopt = 0;
    int vopt = 0;
    int fopt = 0;
    int aopt = 0;
    int dopt = 0;
    int rfd = -1, wfd = -1;
    Opt o; 

    diod_log_init (argv[0]);

    o = opt_create ();

    opterr = 0;
    while ((c = GETOPT (argc, argv, OPTIONS, longopts)) != -1) {
        switch (c) {
            case 'f':   /* --fake-mount */
                fopt = 1;
                break;
            case 'n':   /* --no-mtab */
                nopt = 1;
                break;
            case 'v':   /* --verbose */
                vopt++;
                break;
            case 'o':   /* --options OPT[,OPT]... */
                opt_addf (o, "%s", optarg);
                break;
            case 'a':   /* --9nbd-attach */
                aopt++;
                break;
            case 'd':   /* --9nbd-detach */
                dopt++;
                break;
            default:
                usage ();
        }
    }

    /* Take care of 9nbd operations and exit.
     */
    if (aopt) {
        _nbd_attach (o, argc - optind, argv + optind, nopt, vopt);
        exit (0);
    }
    if (dopt) {
        _nbd_detach (o, argc - optind, argv + optind, nopt, vopt);
        exit (0);
    }

    if (optind != argc - 2)
        usage ();

    if (geteuid () != 0)
        msg_exit ("you must be root");

    spec = argv[optind++];
    dir = argv[optind++];
    host = _parse_spec (spec, o);

    _verify_mountpoint (dir);

    /* Remount - only pass mount flags into the VFS for an existing mount.
     * Take care of it here and exit.
     */
    if (opt_find (o, "remount")) {
        if (opt_check_allowed_csv (o, "ro,rw,aname,remount"))
            msg_exit ("-oremount can only be used with ro,rw");
        _diod_remount (o, spec, dir, vopt, fopt);
        goto done;
    }

    /* Ensure uname and access are set, and to diod-compatible values.
     * The uname user becomes the euid which will be used by munge auth.
     */
    _parse_uname_access (o);
     if (seteuid (_uname2uid (opt_find (o, "uname"))) < 0)
        err_exit ("seteuid");

    /* We require -otrans=fd because auth occurs in user space, then live fd
     * is passed to the kernel via -orfdno,wfdno.
     */
    if (!opt_find (o, "trans"))
        opt_addf (o, "trans=%s", "fd");
    else if (!opt_find (o, "trans=fd"))
        msg_exit ("only -otrans=fd transport is supported");

    /* Set msize if not already set.  Validate it later.
     */
    if (!opt_find (o, "msize"))
        opt_addf (o, "msize=%d", DIOD_DEFAULT_MSIZE);

    /* Only .L version is supported.
     */
    if (!opt_find (o, "version"))
        opt_addf (o, "version=%s", "9p2000.L");
    else if (!opt_find (o, "version=9p2000.L"))
        msg_exit ("only -oversion=9p2000.L is supported (little p, big L)");

    /* Set debug level.
     */
    if (!opt_find (o, "debug"))
        opt_addf (o, "debug=%d", 0x1); /* send errors to dmesg */

    /* Set rwdepth (number of concurrent reads with buffer > msize).
     * N.B. this option is not upstream yet but unknown options are ignored.
     */
    if (!opt_find (o, "rwdepth"))
        opt_addf (o, "rwdepth=%d", 1);

    /* Server is on an inherited file descriptor.
     * For testing, we start server on a socketpair duped to fd 0.
     */
    if (opt_find (o, "rfdno") || opt_find (o, "wfdno")) {
        if (!opt_scanf (o, "rfdno=%d", &rfd) || !opt_scanf (o, "wfdno=%d",&wfd))
            msg_exit ("-orfdno,wfdno must be used together");
        nopt = 1; /* force no mtab */

    /* Connect to server on UNIX domain socket
     */
    } else if (host[0] == '/') {
        if (opt_find (o, "port"))
            msg_exit ("-oport won't work with UNIX domain socket");
        if ((rfd = diod_sock_connect_unix (host, 0)) < 0)
            exit (1);
        wfd = rfd;

        opt_addf (o, "rfdno=%d", rfd);
        opt_addf (o, "wfdno=%d", wfd);

    /* Connect to server on IANA port (or user-specified) and host.
     */
    } else {
        char *port = opt_find (o, "port");
        hostlist_iterator_t hi;
        hostlist_t hl; 
        char *h;

        if (!port)
            port = "564";
        if (!(hl = hostlist_create (host)))
            msg_exit ("error parsing host string: %s", host);
        if (!(hi = hostlist_iterator_create (hl)))
            msg_exit ("out of memory");
        while ((h = hostlist_next (hi))) {
            if (vopt)
                msg ("trying to connect to %s:%s", h, port);
            if ((rfd = diod_sock_connect_inet (h, port, DIOD_SOCK_QUIET)) >= 0)
                break;
        }
        if (h) { /* create new 'spec' string identifying successful host */
            char *p = strchr (spec , ':');
            int len = strlen (h) + (p ? strlen (p) : 0) + 1;

            if (!(nspec = malloc (len)))
                msg_exit ("out of memory");
            snprintf (nspec, len, "%s%s", h, p ? p : "");
        }
        hostlist_destroy (hl);
        if (rfd < 0)
            msg_exit ("could not connect to server(s), giving up");
        wfd = rfd;
        
        opt_delete (o, "port");
        opt_addf (o, "rfdno=%d", rfd);
        opt_addf (o, "wfdno=%d", wfd);
    }

    NP_ASSERT (opt_find (o, "trans=fd"));
    NP_ASSERT (opt_scanf (o, "msize=%d", &i));
    NP_ASSERT (opt_find (o, "version=9p2000.L"));
    NP_ASSERT (opt_scanf (o, "debug=%d", &i) || opt_scanf (o, "debug=%x", &i));
    NP_ASSERT (opt_scanf (o, "wfdno=%d", &i) && opt_scanf (o, "rfdno=%d", &i));
    NP_ASSERT ((opt_find (o, "access=user") && opt_find(o, "uname=root"))
         || (opt_scanf (o, "access=%d", &i) && opt_find(o, "uname")));

    NP_ASSERT (!opt_find (o, "port"));

    _diod_mount (o, rfd, wfd, nspec ? nspec : spec, dir, vopt, fopt, nopt);

done:
    opt_destroy (o);
    exit (0);
}
コード例 #10
0
ファイル: ils.cpp プロジェクト: TheLoneRanger14/vmxray
/* main - open file system, list inode info */
int
main(int argc, char **argv1)
{
    TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT;
    TSK_IMG_INFO *img;

    TSK_OFF_T imgaddr = 0;
    TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT;
    TSK_FS_INFO *fs;

    TSK_TCHAR *cp, *dash;
    TSK_INUM_T istart = 0, ilast = 0;
    int ch;
    int flags = TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED;
    int ils_flags = 0;
    int set_range = 1;
    TSK_TCHAR *image = NULL;
    int32_t sec_skew = 0;
    TSK_TCHAR **argv;
    unsigned int ssize = 0;

#ifdef TSK_WIN32
    // On Windows, get the wide arguments (mingw doesn't support wmain)
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (argv == NULL) {
        fprintf(stderr, "Error getting wide arguments\n");
        exit(1);
    }
#else
    argv = (TSK_TCHAR **) argv1;
#endif

    progname = argv[0];
    setlocale(LC_ALL, "");

    /*
     * Provide convenience options for the most commonly selected feature
     * combinations.
     */
    while ((ch =
            GETOPT(argc, argv, _TSK_T("aAb:ef:i:lLmo:Oprs:vVzZ"))) > 0) {
        switch (ch) {
        case _TSK_T('?'):
        default:
            TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"),
                argv[OPTIND]);
            usage();
        case _TSK_T('b'):
            ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0);
            if (*cp || *cp == *OPTARG || ssize < 1) {
                TFPRINTF(stderr,
                    _TSK_T
                    ("invalid argument: sector size must be positive: %s\n"),
                    OPTARG);
                usage();
            }
            break;
        case _TSK_T('f'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_fs_type_print(stderr);
                exit(1);
            }
            fstype = tsk_fs_type_toid(OPTARG);
            if (fstype == TSK_FS_TYPE_UNSUPP) {
                TFPRINTF(stderr,
                    _TSK_T("Unsupported file system type: %s\n"), OPTARG);
                usage();
            }
            break;
        case _TSK_T('i'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_img_type_print(stderr);
                exit(1);
            }
            imgtype = tsk_img_type_toid(OPTARG);
            if (imgtype == TSK_IMG_TYPE_UNSUPP) {
                TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"),
                    OPTARG);
                usage();
            }
            break;
        case _TSK_T('e'):
            flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC);
            flags &= ~TSK_FS_META_FLAG_USED;
            break;
        case _TSK_T('m'):
            ils_flags |= TSK_FS_ILS_MAC;
            break;
        case _TSK_T('o'):
            if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) {
                tsk_error_print(stderr);
                exit(1);
            }
            break;
        case _TSK_T('O'):
            flags |= TSK_FS_META_FLAG_UNALLOC;
            flags &= ~TSK_FS_META_FLAG_ALLOC;
            ils_flags |= TSK_FS_ILS_OPEN;
            break;
        case _TSK_T('p'):
            flags |= (TSK_FS_META_FLAG_ORPHAN | TSK_FS_META_FLAG_UNALLOC);
            flags &= ~TSK_FS_META_FLAG_ALLOC;
            break;
        case _TSK_T('r'):
            flags |= (TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED);
            flags &= ~TSK_FS_META_FLAG_ALLOC;
            break;
        case _TSK_T('s'):
            sec_skew = TATOI(OPTARG);
            break;
        case _TSK_T('v'):
            tsk_verbose++;
            break;
        case _TSK_T('V'):
            tsk_version_print(stdout);
            exit(0);

            /*
             * Provide fine controls to tweak one feature at a time.
             */
        case _TSK_T('a'):
            flags |= TSK_FS_META_FLAG_ALLOC;
            break;
        case _TSK_T('A'):
            flags |= TSK_FS_META_FLAG_UNALLOC;
            break;
        case _TSK_T('l'):
            ils_flags |= TSK_FS_ILS_LINK;
            break;
        case _TSK_T('L'):
            ils_flags |= TSK_FS_ILS_UNLINK;
            break;
        case _TSK_T('z'):
            flags |= TSK_FS_META_FLAG_UNUSED;
            break;
        case _TSK_T('Z'):
            flags |= TSK_FS_META_FLAG_USED;
            break;
        }
    }

    if (OPTIND >= argc) {
        tsk_fprintf(stderr, "Missing image name\n");
        usage();
    }

    if ((ils_flags & TSK_FS_ILS_LINK) && (ils_flags & TSK_FS_ILS_UNLINK)) {
        tsk_fprintf(stderr,
            "ERROR: Only linked or unlinked should be used\n");
        usage();
    }

    /* We need to determine if an inode or inode range was given */
    if ((dash = TSTRCHR(argv[argc - 1], _TSK_T('-'))) == NULL) {
        /* Check if is a single number */
        istart = TSTRTOULL(argv[argc - 1], &cp, 0);
        if (*cp || *cp == *argv[argc - 1]) {
            /* Not a number - consider it a file name */
            image = argv[OPTIND];
            if ((img =
                    tsk_img_open(argc - OPTIND, &argv[OPTIND],
                        imgtype, ssize)) == NULL) {
                tsk_error_print(stderr);
                exit(1);
            }
            if ((imgaddr * img->sector_size) >= img->size) {
                tsk_fprintf(stderr,
                    "Sector offset supplied is larger than disk image (maximum: %"
                    PRIu64 ")\n", img->size / img->sector_size);
                exit(1);
            }
        }
        else {
            /* Single address set end addr to start */
            ilast = istart;
            set_range = 0;
            image = argv[OPTIND];
            if ((img =
                    tsk_img_open(argc - OPTIND - 1, &argv[OPTIND],
                        imgtype, ssize)) == NULL) {
                tsk_error_print(stderr);
                exit(1);
            }
            if ((imgaddr * img->sector_size) >= img->size) {
                tsk_fprintf(stderr,
                    "Sector offset supplied is larger than disk image (maximum: %"
                    PRIu64 ")\n", img->size / img->sector_size);
                exit(1);
            }
        }
    }
    else {
        /* We have a dash, but it could be part of the file name */
        *dash = '\0';

        istart = TSTRTOULL(argv[argc - 1], &cp, 0);
        if (*cp || *cp == *argv[argc - 1]) {
            /* Not a number - consider it a file name */
            *dash = _TSK_T('-');
            image = argv[OPTIND];
            if ((img =
                    tsk_img_open(argc - OPTIND, &argv[OPTIND],
                        imgtype, ssize)) == NULL) {
                tsk_error_print(stderr);
                exit(1);
            }
            if ((imgaddr * img->sector_size) >= img->size) {
                tsk_fprintf(stderr,
                    "Sector offset supplied is larger than disk image (maximum: %"
                    PRIu64 ")\n", img->size / img->sector_size);
                exit(1);
            }
        }
        else {
            dash++;
            ilast = TSTRTOULL(dash, &cp, 0);
            if (*cp || *cp == *dash) {
                /* Not a number - consider it a file name */
                dash--;
                *dash = '-';
                image = argv[OPTIND];
                if ((img =
                        tsk_img_open(argc - OPTIND, &argv[OPTIND],
                            imgtype, ssize)) == NULL) {
                    tsk_error_print(stderr);
                    exit(1);
                }
                if ((imgaddr * img->sector_size) >= img->size) {
                    tsk_fprintf(stderr,
                        "Sector offset supplied is larger than disk image (maximum: %"
                        PRIu64 ")\n", img->size / img->sector_size);
                    exit(1);
                }
            }
            else {
                set_range = 0;
                /* It was a block range, so do not include it in the open */
                image = argv[OPTIND];
                if ((img =
                        tsk_img_open(argc - OPTIND - 1, &argv[OPTIND],
                            imgtype, ssize)) == NULL) {
                    tsk_error_print(stderr);
                    exit(1);
                }
                if ((imgaddr * img->sector_size) >= img->size) {
                    tsk_fprintf(stderr,
                        "Sector offset supplied is larger than disk image (maximum: %"
                        PRIu64 ")\n", img->size / img->sector_size);
                    exit(1);
                }
            }
        }
    }

    if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) {
        tsk_error_print(stderr);
        if (tsk_errno == TSK_ERR_FS_UNSUPTYPE)
            tsk_fs_type_print(stderr);
        img->close(img);
        exit(1);
    }

    /* do we need to set the range or just check them? */
    if (set_range) {
        istart = fs->first_inum;
        ilast = fs->last_inum;
    }
    else {
        if (istart < fs->first_inum)
            istart = fs->first_inum;

        if (ilast > fs->last_inum)
            ilast = fs->last_inum;
    }

    /* NTFS uses alloc and link different than UNIX so change
     * the default behavior
     *
     * The link value can be > 0 on deleted files (even when closed)
     */

    /* NTFS and FAT have no notion of deleted but still open */
    if ((ils_flags & TSK_FS_ILS_OPEN) && (TSK_FS_TYPE_ISNTFS(fs->ftype)
            || TSK_FS_TYPE_ISFAT(fs->ftype))) {
        fprintf(stderr,
            "Error: '-O' argument does not work with NTFS and FAT images\n");
        exit(1);
    }

    if (tsk_fs_ils(fs, (TSK_FS_ILS_FLAG_ENUM) ils_flags, istart, ilast,
            (TSK_FS_META_FLAG_ENUM) flags, sec_skew, image)) {
        tsk_error_print(stderr);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    fs->close(fs);
    img->close(img);
    exit(0);
}
コード例 #11
0
ファイル: jcat.cpp プロジェクト: TheLoneRanger14/vmxray
int
main(int argc, char **argv1)
{
    TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT;
    TSK_IMG_INFO *img;

    TSK_OFF_T imgaddr = 0;
    TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT;
    TSK_FS_INFO *fs;

    TSK_INUM_T inum;
    int ch;
    TSK_DADDR_T blk;
    TSK_TCHAR *cp;
    TSK_TCHAR **argv;
    unsigned int ssize = 0;

#ifdef TSK_WIN32
    // On Windows, get the wide arguments (mingw doesn't support wmain)
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (argv == NULL) {
        fprintf(stderr, "Error getting wide arguments\n");
        exit(1);
    }
#else
    argv = (TSK_TCHAR **) argv1;
#endif

    progname = argv[0];
    setlocale(LC_ALL, "");

    while ((ch = GETOPT(argc, argv, _TSK_T("b:f:i:o:vV"))) > 0) {
        switch (ch) {
        case _TSK_T('?'):
        default:
            TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"),
                argv[OPTIND]);
            usage();
        case _TSK_T('b'):
            ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0);
            if (*cp || *cp == *OPTARG || ssize < 1) {
                TFPRINTF(stderr,
                    _TSK_T
                    ("invalid argument: sector size must be positive: %s\n"),
                    OPTARG);
                usage();
            }
            break;
        case _TSK_T('f'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_fs_type_print(stderr);
                exit(1);
            }
            fstype = tsk_fs_type_toid(OPTARG);
            if (fstype == TSK_FS_TYPE_UNSUPP) {
                TFPRINTF(stderr,
                    _TSK_T("Unsupported file system type: %s\n"), OPTARG);
                usage();
            }
            break;
        case _TSK_T('i'):
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_img_type_print(stderr);
                exit(1);
            }
            imgtype = tsk_img_type_toid(OPTARG);
            if (imgtype == TSK_IMG_TYPE_UNSUPP) {
                TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"),
                    OPTARG);
                usage();
            }
            break;
        case _TSK_T('o'):
            if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) {
                tsk_error_print(stderr);
                exit(1);
            }
            break;
        case _TSK_T('v'):
            tsk_verbose++;
            break;
        case _TSK_T('V'):
            tsk_version_print(stdout);
            exit(0);
        }
    }

    /* We need at least two more arguments */
    if (OPTIND + 1 >= argc) {
        tsk_fprintf(stderr, "Missing image name and/or block address\n");
        usage();
    }

    blk = TSTRTOULL(argv[argc - 1], &cp, 0);
    if (*cp || *cp == *argv[argc - 1]) {
        TFPRINTF(stderr, _TSK_T("bad block number: %s"), argv[argc - 1]);
        exit(1);
    }

    /* Do we have an inode as well? */
    if (tsk_fs_parse_inum(argv[argc - 2], &inum, NULL, NULL, NULL, NULL)) {
        /* Not a number therefore an image */
        if ((img =
                tsk_img_open(argc - OPTIND - 1, &argv[OPTIND],
                    imgtype, ssize)) == NULL) {
            tsk_error_print(stderr);
            exit(1);
        }
        if ((imgaddr * img->sector_size) >= img->size) {
            tsk_fprintf(stderr,
                "Sector offset supplied is larger than disk image (maximum: %"
                PRIu64 ")\n", img->size / img->sector_size);
            exit(1);
        }

        if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) {
            tsk_error_print(stderr);
            if (tsk_errno == TSK_ERR_FS_UNSUPTYPE)
                tsk_fs_type_print(stderr);
            img->close(img);
            exit(1);
        }
        inum = fs->journ_inum;
    }
    else {
        if ((img =
                tsk_img_open(argc - OPTIND - 2, &argv[OPTIND],
                    imgtype, ssize)) == NULL) {
            tsk_error_print(stderr);
            exit(1);
        }

        if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) {
            tsk_error_print(stderr);
            if (tsk_errno == TSK_ERR_FS_UNSUPTYPE)
                tsk_fs_type_print(stderr);
            img->close(img);
            exit(1);
        }
    }

    if (inum > fs->last_inum) {
        tsk_fprintf(stderr,
            "Inode value is too large for image (%" PRIuINUM ")\n",
            fs->last_inum);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    if (inum < fs->first_inum) {
        tsk_fprintf(stderr,
            "Inode value is too small for image (%" PRIuINUM ")\n",
            fs->first_inum);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    if (fs->jopen == NULL) {
        tsk_fprintf(stderr,
            "Journal support does not exist for this file system\n");
        fs->close(fs);
        img->close(img);
        exit(1);
    }

#ifdef TSK_WIN32
    if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
        fprintf(stderr,
            "jcat: error setting stdout to binary: %s", strerror(errno));
        fs->close(fs);
        img->close(img);
        exit(1);
    }
#endif

    if (fs->jopen(fs, inum)) {
        tsk_error_print(stderr);
        fs->close(fs);
        img->close(img);
        exit(1);
    }
    if (fs->jblk_walk(fs, blk, blk, 0, 0, NULL)) {
        tsk_error_print(stderr);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    fs->close(fs);
    img->close(img);
    exit(0);
}
コード例 #12
0
ファイル: fscheck.cpp プロジェクト: TheLoneRanger14/vmxray
int
main(int argc, char **argv)
{
    TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT;
    TSK_IMG_INFO *img;

    TSK_OFF_T imgaddr = 0;
    TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT;
    TSK_FS_INFO *fs;

    int ch;
    TSK_TCHAR **argv;
    unsigned int ssize = 0;
    TSK_TCHAR *cp;

#ifdef TSK_WIN32
    // On Windows, get the wide arguments (mingw doesn't support wmain)
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (argv == NULL) {
        fprintf(stderr, "Error getting wide arguments\n");
        exit(1);
    }
#else
    argv = (TSK_TCHAR **) argv1;
#endif


    progname = argv[0];

    while ((ch = GETOPT(argc, argv, "b:f:i:o:vV")) > 0) {
        switch (ch) {
        case '?':
        default:
            fprintf(stderr, "Invalid argument: %s\n", argv[OPTIND]);
            usage();
        case _TSK_T('b'):
            ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0);
            if (*cp || *cp == *OPTARG || ssize < 1) {
                TFPRINTF(stderr,
                    _TSK_T
                    ("invalid argument: sector size must be positive: %s\n"),
                    OPTARG);
                usage();
            }
            break;
        case 'f':
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_fs_type_print(stderr);
                exit(1);
            }
            fstype = tsk_fs_type_toid(OPTARG);
            if (fstype == TSK_FS_TYPE_UNSUPP) {
                TFPRINTF(stderr,
                    _TSK_T("Unsupported file system type: %s\n"), OPTARG);
                usage();
            }
            break;

        case 'i':
            if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) {
                tsk_img_type_print(stderr);
                exit(1);
            }
            imgtype = tsk_img_type_toid(OPTARG);
            if (imgtype == TSK_IMG_TYPE_UNSUPP) {
                TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"),
                    OPTARG);
                usage();
            }
            break;

        case 'o':
            if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) {
                tsk_error_print(stderr);
                exit(1);
            }
            break;

        case 'v':
            verbose++;
            break;

        case 'V':
            print_version(stdout);
            exit(0);
        }
    }

    /* We need at least one more argument */
    if (OPTIND >= argc) {
        fprintf(stderr, "Missing image name\n");
        usage();
    }

    img =
        img_open(imgoff, argc - OPTIND,
        (const char **) &argv[OPTIND], imgtype, ssize);
    if (img == NULL) {
        tsk_error_print(stderr);
        exit(1);
    }

    if (fs = fs_open(img, fstype)) {
        if (tsk_errno == TSK_ERR_FS_UNSUPTYPE)
            tsk_print_types(stderr);

        tsk_error_print(stderr);
        img->close(img);
        exit(1);

    }

    if (fs->fscheck(fs, stdout)) {
        tsk_error_print(stderr);
        fs->close(fs);
        img->close(img);
        exit(1);
    }

    fs->close(fs);
    img->close(img);

    exit(0);
}
コード例 #13
0
ファイル: postkick.c プロジェクト: TonyChengTW/Rmail
int     main(int argc, char **argv)
{
    char   *class;
    char   *service;
    char   *request;
    int     fd;
    struct stat st;
    char   *slash;
    int     c;

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Process environment options as early as we can.
     */
    if (safe_getenv(CONF_ENV_VERB))
	msg_verbose = 1;

    /*
     * Initialize. Set up logging, read the global configuration file and
     * extract configuration information.
     */
    if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
	argv[0] = slash + 1;
    msg_vstream_init(argv[0], VSTREAM_ERR);
    set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));

    /*
     * Parse JCL.
     */
    while ((c = GETOPT(argc, argv, "c:v")) > 0) {
	switch (c) {
	default:
	    usage(argv[0]);
	case 'c':
	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
		msg_fatal("out of memory");
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	}
    }
    if (argc != optind + 3)
	usage(argv[0]);
    class = argv[optind];
    service = argv[optind + 1];
    request = argv[optind + 2];

    /*
     * Finish initializations.
     */
    mail_conf_read();
    if (chdir(var_queue_dir))
	msg_fatal("chdir %s: %m", var_queue_dir);

    /*
     * Kick the service.
     */
    if (mail_trigger(class, service, request, strlen(request)) < 0) {
	msg_warn("Cannot contact class %s service %s - perhaps the mail system is down",
		 class, service);
	exit(1);
    } else {
コード例 #14
0
ファイル: sendmail.c プロジェクト: VargMon/netbsd-cvs-mirror
int     main(int argc, char **argv)
{
    static char *full_name = 0;		/* sendmail -F */
    struct stat st;
    char   *slash;
    char   *sender = 0;			/* sendmail -f */
    int     c;
    int     fd;
    int     mode;
    ARGV   *ext_argv;
    int     debug_me = 0;
    int     err;
    int     n;
    int     flags = SM_FLAG_DEFAULT;
    char   *site_to_flush = 0;
    char   *id_to_flush = 0;
    char   *encoding = 0;
    char   *qtime = 0;
    const char *errstr;
    uid_t   uid;
    const char *rewrite_context = MAIL_ATTR_RWR_LOCAL;
    int     dsn_notify = 0;
    const char *dsn_envid = 0;
    int     saved_optind;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal_status(EX_OSERR, "open /dev/null: %m");

    /*
     * The CDE desktop calendar manager leaks a parent file descriptor into
     * the child process. For the sake of sendmail compatibility we have to
     * close the file descriptor otherwise mail notification will hang.
     */
    for ( /* void */ ; fd < 100; fd++)
	(void) close(fd);

    /*
     * Process environment options as early as we can. We might be called
     * from a set-uid (set-gid) program, so be careful with importing
     * environment variables.
     */
    if (safe_getenv(CONF_ENV_VERB))
	msg_verbose = 1;
    if (safe_getenv(CONF_ENV_DEBUG))
	debug_me = 1;

    /*
     * Initialize. Set up logging, read the global configuration file and
     * extract configuration information. Set up signal handlers so that we
     * can clean up incomplete output.
     */
    if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
	argv[0] = slash + 1;
    msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_cleanup(tempfail);
    msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
    set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));

    /*
     * Some sites mistakenly install Postfix sendmail as set-uid root. Drop
     * set-uid privileges only when root, otherwise some systems will not
     * reset the saved set-userid, which would be a security vulnerability.
     */
    if (geteuid() == 0 && getuid() != 0) {
	msg_warn("the Postfix sendmail command has set-uid root file permissions");
	msg_warn("or the command is run from a set-uid root process");
	msg_warn("the Postfix sendmail command must be installed without set-uid root file permissions");
	set_ugid(getuid(), getgid());
    }

    /*
     * Further initialization. Load main.cf first, so that command-line
     * options can override main.cf settings. Pre-scan the argument list so
     * that we load the right main.cf file.
     */
#define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"

    saved_optind = optind;
    while (argv[OPTIND] != 0) {
	if (strcmp(argv[OPTIND], "-q") == 0) {	/* not getopt compatible */
	    optind++;
	    continue;
	}
	if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
	    break;
	if (c == 'C') {
	    VSTRING *buf = vstring_alloc(1);

	    if (setenv(CONF_ENV_PATH,
		   strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
		       sane_dirname(buf, optarg) : optarg, 1) < 0)
		msg_fatal_status(EX_UNAVAILABLE, "out of memory");
	    vstring_free(buf);
	}
    }
    optind = saved_optind;
    mail_conf_read();
    if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
	msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
    get_mail_conf_str_table(str_table);

    if (chdir(var_queue_dir))
	msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir);

    signal(SIGPIPE, SIG_IGN);

    /*
     * Optionally start the debugger on ourself. This must be done after
     * reading the global configuration file, because that file specifies
     * what debugger command to execute.
     */
    if (debug_me)
	debug_process();

    /*
     * The default mode of operation is determined by the process name. It
     * can, however, be changed via command-line options (for example,
     * "newaliases -bp" will show the mail queue).
     */
    if (strcmp(argv[0], "mailq") == 0) {
	mode = SM_MODE_MAILQ;
    } else if (strcmp(argv[0], "newaliases") == 0) {
	mode = SM_MODE_NEWALIAS;
    } else if (strcmp(argv[0], "smtpd") == 0) {
	mode = SM_MODE_DAEMON;
    } else {
	mode = SM_MODE_ENQUEUE;
    }

    /*
     * Parse JCL. Sendmail has been around for a long time, and has acquired
     * a large number of options in the course of time. Some options such as
     * -q are not parsable with GETOPT() and get special treatment.
     */
#define OPTIND  (optind > 0 ? optind : 1)

    while (argv[OPTIND] != 0) {
	if (strcmp(argv[OPTIND], "-q") == 0) {
	    if (mode == SM_MODE_DAEMON)
		msg_warn("ignoring -q option in daemon mode");
	    else
		mode = SM_MODE_FLUSHQ;
	    optind++;
	    continue;
	}
	if (strcmp(argv[OPTIND], "-V") == 0) {
	    msg_warn("option -V is deprecated with Postfix 2.3; "
		     "specify -XV instead");
	    argv[OPTIND] = "-XV";
	}
	if (strncmp(argv[OPTIND], "-V", 2) == 0 && strlen(argv[OPTIND]) == 4) {
	    msg_warn("option %s is deprecated with Postfix 2.3; "
		     "specify -X%s instead",
		     argv[OPTIND], argv[OPTIND] + 1);
	    argv[OPTIND] = concatenate("-X", argv[OPTIND] + 1, (char *) 0);
	}
	if (strcmp(argv[OPTIND], "-XV") == 0) {
	    verp_delims = var_verp_delims;
	    optind++;
	    continue;
	}
	if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
	    break;
	switch (c) {
	default:
	    if (msg_verbose)
		msg_info("-%c option ignored", c);
	    break;
	case 'n':
	    msg_fatal_status(EX_USAGE, "-%c option not supported", c);
	case 'B':
	    if (strcmp(optarg, "8BITMIME") == 0)/* RFC 1652 */
		encoding = MAIL_ATTR_ENC_8BIT;
	    else if (strcmp(optarg, "7BIT") == 0)	/* RFC 1652 */
		encoding = MAIL_ATTR_ENC_7BIT;
	    else
		msg_fatal_status(EX_USAGE, "-B option needs 8BITMIME or 7BIT");
	    break;
	case 'F':				/* full name */
	    full_name = optarg;
	    break;
	case 'G':				/* gateway submission */
	    rewrite_context = MAIL_ATTR_RWR_REMOTE;
	    break;
	case 'I':				/* newaliases */
	    mode = SM_MODE_NEWALIAS;
	    break;
	case 'N':
	    if ((dsn_notify = dsn_notify_mask(optarg)) == 0)
		msg_warn("bad -N option value -- ignored");
	    break;
	case 'V':				/* DSN, was: VERP */
	    if (strlen(optarg) > 100)
		msg_warn("too long -V option value -- ignored");
	    else if (!allprint(optarg))
		msg_warn("bad syntax in -V option value -- ignored");
	    else
		dsn_envid = optarg;
	    break;
	case 'X':
	    switch (*optarg) {
	    default:
		msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg);
	    case 'V':				/* VERP */
		if (verp_delims_verify(optarg + 1) != 0)
		    msg_fatal_status(EX_USAGE, "-V requires two characters from %s",
				     var_verp_filter);
		verp_delims = optarg + 1;
		break;
	    }
	    break;
	case 'b':
	    switch (*optarg) {
	    default:
		msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg);
	    case 'd':				/* daemon mode */
		if (mode == SM_MODE_FLUSHQ)
		    msg_warn("ignoring -q option in daemon mode");
		mode = SM_MODE_DAEMON;
		break;
	    case 'h':				/* print host status */
	    case 'H':				/* flush host status */
		mode = SM_MODE_IGNORE;
		break;
	    case 'i':				/* newaliases */
		mode = SM_MODE_NEWALIAS;
		break;
	    case 'm':				/* deliver mail */
		mode = SM_MODE_ENQUEUE;
		break;
	    case 'p':				/* mailq */
		mode = SM_MODE_MAILQ;
		break;
	    case 's':				/* stand-alone mode */
		mode = SM_MODE_USER;
		break;
	    case 'v':				/* expand recipients */
		flags |= DEL_REQ_FLAG_USR_VRFY;
		break;
	    }
	    break;
	case 'f':
	    sender = optarg;
	    break;
	case 'i':
	    flags &= ~SM_FLAG_AEOF;
	    break;
	case 'o':
	    switch (*optarg) {
	    default:
		if (msg_verbose)
		    msg_info("-%c%c option ignored", c, *optarg);
		break;
	    case 'A':
		if (optarg[1] == 0)
		    msg_fatal_status(EX_USAGE, "-oA requires pathname");
		myfree(var_alias_db_map);
		var_alias_db_map = mystrdup(optarg + 1);
		set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map);
		break;
	    case '7':
	    case '8':
		break;
	    case 'i':
		flags &= ~SM_FLAG_AEOF;
		break;
	    case 'm':
		break;
	    }
	    break;
	case 'r':				/* obsoleted by -f */
	    sender = optarg;
	    break;
	case 'q':
	    if (ISDIGIT(optarg[0])) {
		qtime = optarg;
	    } else if (optarg[0] == 'R') {
		site_to_flush = optarg + 1;
		if (*site_to_flush == 0)
		    msg_fatal_status(EX_USAGE, "specify: -qRsitename");
	    } else if (optarg[0] == 'I') {
		id_to_flush = optarg + 1;
		if (*id_to_flush == 0)
		    msg_fatal_status(EX_USAGE, "specify: -qIqueueid");
	    } else {
		msg_fatal_status(EX_USAGE, "-q%c is not implemented",
				 optarg[0]);
	    }
	    break;
	case 't':
	    flags |= SM_FLAG_XRCPT;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case '?':
	    msg_fatal_status(EX_USAGE, "usage: %s [options]", argv[0]);
	}
    }

    /*
     * Look for conflicting options and arguments.
     */
    if ((flags & SM_FLAG_XRCPT) && mode != SM_MODE_ENQUEUE)
	msg_fatal_status(EX_USAGE, "-t can be used only in delivery mode");

    if (site_to_flush && mode != SM_MODE_ENQUEUE)
	msg_fatal_status(EX_USAGE, "-qR can be used only in delivery mode");

    if (id_to_flush && mode != SM_MODE_ENQUEUE)
	msg_fatal_status(EX_USAGE, "-qI can be used only in delivery mode");

    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	if (flags & SM_FLAG_XRCPT)
	    msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv");
	if (dsn_notify)
	    msg_fatal_status(EX_USAGE, "-N option cannot be used with -bv");
	if (msg_verbose == 1)
	    msg_fatal_status(EX_USAGE, "-v option cannot be used with -bv");
    }

    /*
     * The -v option plays double duty. One requests verbose delivery, more
     * than one requests verbose logging.
     */
    if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) {
	msg_verbose = 0;
	flags |= DEL_REQ_FLAG_RECORD;
    }

    /*
     * Start processing. Everything is delegated to external commands.
     */
    if (qtime && mode != SM_MODE_DAEMON)
	exit(0);
    switch (mode) {
    default:
	msg_panic("unknown operation mode: %d", mode);
	/* NOTREACHED */
    case SM_MODE_ENQUEUE:
	if (site_to_flush) {
	    if (argv[OPTIND])
		msg_fatal_status(EX_USAGE, "flush site requires no recipient");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0);
	    for (n = 0; n < msg_verbose; n++)
		argv_add(ext_argv, "-v", (char *) 0);
	    argv_terminate(ext_argv);
	    mail_run_replace(var_command_dir, ext_argv->argv);
	    /* NOTREACHED */
	} else if (id_to_flush) {
	    if (argv[OPTIND])
		msg_fatal_status(EX_USAGE, "flush queue_id requires no recipient");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "postqueue", "-i", id_to_flush, (char *) 0);
	    for (n = 0; n < msg_verbose; n++)
		argv_add(ext_argv, "-v", (char *) 0);
	    argv_terminate(ext_argv);
	    mail_run_replace(var_command_dir, ext_argv->argv);
	    /* NOTREACHED */
	} else {
	    enqueue(flags, encoding, dsn_envid, dsn_notify,
		    rewrite_context, sender, full_name, argv + OPTIND);
	    exit(0);
	    /* NOTREACHED */
	}
	break;
    case SM_MODE_MAILQ:
	if (argv[OPTIND])
	    msg_fatal_status(EX_USAGE,
			     "display queue mode requires no recipient");
	ext_argv = argv_alloc(2);
	argv_add(ext_argv, "postqueue", "-p", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(ext_argv, "-v", (char *) 0);
	argv_terminate(ext_argv);
	mail_run_replace(var_command_dir, ext_argv->argv);
	/* NOTREACHED */
    case SM_MODE_FLUSHQ:
	if (argv[OPTIND])
	    msg_fatal_status(EX_USAGE,
			     "flush queue mode requires no recipient");
	ext_argv = argv_alloc(2);
	argv_add(ext_argv, "postqueue", "-f", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(ext_argv, "-v", (char *) 0);
	argv_terminate(ext_argv);
	mail_run_replace(var_command_dir, ext_argv->argv);
	/* NOTREACHED */
    case SM_MODE_DAEMON:
	if (argv[OPTIND])
	    msg_fatal_status(EX_USAGE, "daemon mode requires no recipient");
	ext_argv = argv_alloc(2);
	argv_add(ext_argv, "postfix", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(ext_argv, "-v", (char *) 0);
	argv_add(ext_argv, "start", (char *) 0);
	argv_terminate(ext_argv);
	err = (mail_run_background(var_command_dir, ext_argv->argv) < 0);
	argv_free(ext_argv);
	exit(err);
	break;
    case SM_MODE_NEWALIAS:
	if (argv[OPTIND])
	    msg_fatal_status(EX_USAGE,
			 "alias initialization mode requires no recipient");
	if (*var_alias_db_map == 0)
	    return (0);
	ext_argv = argv_alloc(2);
	argv_add(ext_argv, "postalias", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(ext_argv, "-v", (char *) 0);
	argv_split_append(ext_argv, var_alias_db_map, ", \t\r\n");
	argv_terminate(ext_argv);
	mail_run_replace(var_command_dir, ext_argv->argv);
	/* NOTREACHED */
    case SM_MODE_USER:
	if (argv[OPTIND])
	    msg_fatal_status(EX_USAGE,
			     "stand-alone mode requires no recipient");
	/* The actual enforcement happens in the postdrop command. */
	if ((errstr = check_user_acl_byuid(var_submit_acl, uid = getuid())) != 0)
	    msg_fatal_status(EX_NOPERM,
			     "User %s(%ld) is not allowed to submit mail",
			     errstr, (long) uid);
	ext_argv = argv_alloc(2);
	argv_add(ext_argv, "smtpd", "-S", (char *) 0);
	for (n = 0; n < msg_verbose; n++)
	    argv_add(ext_argv, "-v", (char *) 0);
	argv_terminate(ext_argv);
	mail_run_replace(var_daemon_dir, ext_argv->argv);
	/* NOTREACHED */
    case SM_MODE_IGNORE:
	exit(0);
	/* NOTREACHED */
    }
}
コード例 #15
0
ファイル: postfix.c プロジェクト: pombredanne/NetBSD
int     main(int argc, char **argv)
{
    char   *script;
    struct stat st;
    char   *slash;
    int     fd;
    int     ch;
    ARGV   *import_env;
    static const CONFIG_STR_TABLE str_table[] = {
	VAR_SENDMAIL_PATH, DEF_SENDMAIL_PATH, &var_sendmail_path, 1, 0,
	VAR_MAILQ_PATH, DEF_MAILQ_PATH, &var_mailq_path, 1, 0,
	VAR_NEWALIAS_PATH, DEF_NEWALIAS_PATH, &var_newalias_path, 1, 0,
	VAR_MANPAGE_DIR, DEF_MANPAGE_DIR, &var_manpage_dir, 1, 0,
	VAR_SAMPLE_DIR, DEF_SAMPLE_DIR, &var_sample_dir, 1, 0,
	VAR_README_DIR, DEF_README_DIR, &var_readme_dir, 1, 0,
	VAR_HTML_DIR, DEF_HTML_DIR, &var_html_dir, 1, 0,
	0,
    };
    int     force_single_instance;
    ARGV   *my_argv;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Set up diagnostics. XXX What if stdin is the system console during
     * boot time? It seems a bad idea to log startup errors to the console.
     * This is UNIX, a system that can run without hand holding.
     */
    if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
	argv[0] = slash + 1;
    if (isatty(STDERR_FILENO))
	msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_syslog_init(argv[0], LOG_PID, LOG_FACILITY);

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * The mail system must be run by the superuser so it can revoke
     * privileges for selected operations. That's right - it takes privileges
     * to toss privileges.
     */
    if (getuid() != 0) {
	msg_error("to submit mail, use the Postfix sendmail command");
	msg_fatal("the postfix command is reserved for the superuser");
    }
    if (unsafe() != 0)
	msg_fatal("the postfix command must not run as a set-uid process");

    /*
     * Parse switches.
     */
    while ((ch = GETOPT(argc, argv, "c:Dv")) > 0) {
	switch (ch) {
	default:
	    msg_fatal("usage: %s [-c config_dir] [-Dv] command", argv[0]);
	case 'c':
	    if (*optarg != '/')
		msg_fatal("-c requires absolute pathname");
	    check_setenv(CONF_ENV_PATH, optarg);
	    break;
	case 'D':
	    check_setenv(CONF_ENV_DEBUG, "");
	    break;
	case 'v':
	    msg_verbose++;
	    check_setenv(CONF_ENV_VERB, "");
	    break;
	}
    }
    force_single_instance = (getenv(CONF_ENV_PATH) != 0);

    /*
     * Copy a bunch of configuration parameters into the environment for easy
     * access by the maintenance shell script.
     */
    mail_conf_read();
    get_mail_conf_str_table(str_table);

    /*
     * Environment import filter, to enforce consistent behavior whether this
     * command is started by hand, or at system boot time. This is necessary
     * because some shell scripts use environment settings to override
     * main.cf settings.
     */
    import_env = argv_split(var_import_environ, ", \t\r\n");
    clean_env(import_env->argv);
    argv_free(import_env);

    check_setenv("PATH", ROOT_PATH);		/* sys_defs.h */
    check_setenv(CONF_ENV_PATH, var_config_dir);/* mail_conf.h */

    check_setenv(VAR_COMMAND_DIR, var_command_dir);	/* main.cf */
    check_setenv(VAR_DAEMON_DIR, var_daemon_dir);	/* main.cf */
    check_setenv(VAR_DATA_DIR, var_data_dir);	/* main.cf */
    check_setenv(VAR_QUEUE_DIR, var_queue_dir);	/* main.cf */
    check_setenv(VAR_CONFIG_DIR, var_config_dir);	/* main.cf */

    /*
     * Do we want to keep adding things here as shell scripts evolve?
     */
    check_setenv(VAR_MAIL_OWNER, var_mail_owner);	/* main.cf */
    check_setenv(VAR_SGID_GROUP, var_sgid_group);	/* main.cf */
    check_setenv(VAR_SENDMAIL_PATH, var_sendmail_path);	/* main.cf */
    check_setenv(VAR_MAILQ_PATH, var_mailq_path);	/* main.cf */
    check_setenv(VAR_NEWALIAS_PATH, var_newalias_path);	/* main.cf */
    check_setenv(VAR_MANPAGE_DIR, var_manpage_dir);	/* main.cf */
    check_setenv(VAR_SAMPLE_DIR, var_sample_dir);	/* main.cf */
    check_setenv(VAR_README_DIR, var_readme_dir);	/* main.cf */
    check_setenv(VAR_HTML_DIR, var_html_dir);	/* main.cf */

    /*
     * Make sure these directories exist. Run the maintenance scripts with as
     * current directory the mail database.
     */
    if (chdir(var_command_dir))
	msg_fatal("chdir(%s): %m", var_command_dir);
    if (chdir(var_daemon_dir))
	msg_fatal("chdir(%s): %m", var_daemon_dir);
    if (chdir(var_queue_dir))
	msg_fatal("chdir(%s): %m", var_queue_dir);

    /*
     * Run the management script.
     */
    if (force_single_instance
	|| argv_split(var_multi_conf_dirs, "\t\r\n, ")->argc == 0) {
	script = concatenate(var_daemon_dir, "/postfix-script", (char *) 0);
	if (optind < 1)
	    msg_panic("bad optind value");
	argv[optind - 1] = script;
	execvp(script, argv + optind - 1);
	msg_fatal("%s: %m", script);
    }

    /*
     * Hand off control to a multi-instance manager.
     */
    else {
	if (*var_multi_wrapper == 0)
	    msg_fatal("multi-instance support is requested, but %s is empty",
		      VAR_MULTI_WRAPPER);
	my_argv = argv_split(var_multi_wrapper, " \t\r\n");
	do {
	    argv_add(my_argv, argv[optind], (char *) 0);
	} while (argv[optind++] != 0);
	execvp(my_argv->argv[0], my_argv->argv);
	msg_fatal("%s: %m", my_argv->argv[0]);
    }
}
コード例 #16
0
ファイル: trigger_server.c プロジェクト: ureyni/postfix.3.1
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
{
    const char *myname = "trigger_server_main";
    char   *root_dir = 0;
    char   *user_name = 0;
    int     debug_me = 0;
    int     daemon_mode = 1;
    char   *service_name = basename(argv[0]);
    VSTREAM *stream = 0;
    int     delay;
    int     c;
    int     socket_count = 1;
    int     fd;
    va_list ap;
    MAIL_SERVER_INIT_FN pre_init = 0;
    MAIL_SERVER_INIT_FN post_init = 0;
    MAIL_SERVER_LOOP_FN loop = 0;
    int     key;
    char    buf[TRIGGER_BUF_SIZE];
    ssize_t len;
    char   *transport = 0;
    char   *lock_path;
    VSTRING *why;
    int     alone = 0;
    int     zerolimit = 0;
    WATCHDOG *watchdog;
    char   *oname_val;
    char   *oname;
    char   *oval;
    const char *err;
    char   *generation;
    int     msg_vstream_needed = 0;
    int     redo_syslog_init = 0;
    const char *dsn_filter_title;
    const char **dsn_filter_maps;

    /*
     * Process environment options as early as we can.
     */
    if (getenv(CONF_ENV_VERB))
        msg_verbose = 1;
    if (getenv(CONF_ENV_DEBUG))
        debug_me = 1;

    /*
     * Don't die when a process goes away unexpectedly.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * Don't die for frivolous reasons.
     */
#ifdef SIGXFSZ
    signal(SIGXFSZ, SIG_IGN);
#endif

    /*
     * May need this every now and then.
     */
    var_procname = mystrdup(basename(argv[0]));
    set_mail_conf_str(VAR_PROCNAME, var_procname);

    /*
     * Initialize logging and exit handler. Do the syslog first, so that its
     * initialization completes before we enter the optional chroot jail.
     */
    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
    if (msg_verbose)
        msg_info("daemon started");

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * Initialize from the configuration file. Allow command-line options to
     * override compiled-in defaults or configured parameter values.
     */
    mail_conf_suck();

    /*
     * After database open error, continue execution with reduced
     * functionality.
     */
    dict_allow_surrogate = 1;

    /*
     * Pick up policy settings from master process. Shut up error messages to
     * stderr, because no-one is going to see them.
     */
    opterr = 0;
    while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
        switch (c) {
        case 'c':
            root_dir = "setme";
            break;
        case 'd':
            daemon_mode = 0;
            break;
        case 'D':
            debug_me = 1;
            break;
        case 'i':
            mail_conf_update(VAR_MAX_IDLE, optarg);
            break;
        case 'l':
            alone = 1;
            break;
        case 'm':
            mail_conf_update(VAR_MAX_USE, optarg);
            break;
        case 'n':
            service_name = optarg;
            break;
        case 'o':
            oname_val = mystrdup(optarg);
            if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
                msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
            mail_conf_update(oname, oval);
            if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
                redo_syslog_init = 1;
            myfree(oname_val);
            break;
        case 's':
            if ((socket_count = atoi(optarg)) <= 0)
                msg_fatal("invalid socket_count: %s", optarg);
            break;
        case 'S':
            stream = VSTREAM_IN;
            break;
        case 't':
            transport = optarg;
            break;
        case 'u':
            user_name = "setme";
            break;
        case 'v':
            msg_verbose++;
            break;
        case 'V':
            if (++msg_vstream_needed == 1)
                msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
            break;
        case 'z':
            zerolimit = 1;
            break;
        default:
            msg_fatal("invalid option: %c", c);
            break;
        }
    }

    /*
     * Initialize generic parameters.
     */
    mail_params_init();
    if (redo_syslog_init)
        msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);

    /*
     * Register higher-level dictionaries and initialize the support for
     * dynamically-loaded dictionarles.
     */
    mail_dict_init();

    /*
     * If not connected to stdin, stdin must not be a terminal.
     */
    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
        msg_vstream_init(var_procname, VSTREAM_ERR);
        msg_fatal("do not run this command by hand-4");
    }

    /*
     * Application-specific initialization.
     */
    va_start(ap, service);
    while ((key = va_arg(ap, int)) != 0) {
        switch (key) {
        case MAIL_SERVER_INT_TABLE:
            get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
            break;
        case MAIL_SERVER_LONG_TABLE:
            get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
            break;
        case MAIL_SERVER_STR_TABLE:
            get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
            break;
        case MAIL_SERVER_BOOL_TABLE:
            get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
            break;
        case MAIL_SERVER_TIME_TABLE:
            get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
            break;
        case MAIL_SERVER_RAW_TABLE:
            get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
            break;
        case MAIL_SERVER_NINT_TABLE:
            get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
            break;
        case MAIL_SERVER_NBOOL_TABLE:
            get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
            break;
        case MAIL_SERVER_PRE_INIT:
            pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
            break;
        case MAIL_SERVER_POST_INIT:
            post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
            break;
        case MAIL_SERVER_LOOP:
            loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
            break;
        case MAIL_SERVER_EXIT:
            trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
            break;
        case MAIL_SERVER_PRE_ACCEPT:
            trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
            break;
        case MAIL_SERVER_IN_FLOW_DELAY:
            trigger_server_in_flow_delay = 1;
            break;
        case MAIL_SERVER_SOLITARY:
            if (stream == 0 && !alone)
                msg_fatal("service %s requires a process limit of 1",
                          service_name);
            break;
        case MAIL_SERVER_UNLIMITED:
            if (stream == 0 && !zerolimit)
                msg_fatal("service %s requires a process limit of 0",
                          service_name);
            break;
        case MAIL_SERVER_PRIVILEGED:
            if (user_name)
                msg_fatal("service %s requires privileged operation",
                          service_name);
            break;
        case MAIL_SERVER_WATCHDOG:
            trigger_server_watchdog = *va_arg(ap, int *);
            break;
        case MAIL_SERVER_BOUNCE_INIT:
            dsn_filter_title = va_arg(ap, const char *);
            dsn_filter_maps = va_arg(ap, const char **);
            bounce_client_init(dsn_filter_title, *dsn_filter_maps);
            break;
        default:
            msg_panic("%s: unknown argument type: %d", myname, key);
        }
    }
    va_end(ap);

    if (root_dir)
        root_dir = var_queue_dir;
    if (user_name)
        user_name = var_mail_owner;

    /*
     * Can options be required?
     *
     * XXX Initially this code was implemented with UNIX-domain sockets, but
     * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
     * client disconnects before the server has accepted the connection.
     * Symptom: the server accept() fails with EPIPE or EPROTO, but the
     * socket stays readable, so that the program goes into a wasteful loop.
     *
     * The initial fix was to use FIFOs, but those turn out to have their own
     * problems, witness the workarounds in the fifo_listen() routine.
     * Therefore we support both FIFOs and UNIX-domain sockets, so that the
     * user can choose whatever works best.
     *
     * Well, I give up. Solaris UNIX-domain sockets still don't work properly,
     * so it will have to limp along with a streams-specific alternative.
     */
    if (stream == 0) {
        if (transport == 0)
            msg_fatal("no transport type specified");
        if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
            trigger_server_accept = trigger_server_accept_local;
        else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
            trigger_server_accept = trigger_server_accept_fifo;
#ifdef MASTER_XPORT_NAME_PASS
        else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
            trigger_server_accept = trigger_server_accept_pass;
#endif
        else
            msg_fatal("unsupported transport type: %s", transport);
    }

    /*
     * Retrieve process generation from environment.
     */
    if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
        if (!alldig(generation))
            msg_fatal("bad generation: %s", generation);
        OCTAL_TO_UNSIGNED(trigger_server_generation, generation);
        if (msg_verbose)
            msg_info("process generation: %s (%o)",
                     generation, trigger_server_generation);
    }

    /*
     * Optionally start the debugger on ourself.
     */
    if (debug_me)
        debug_process();

    /*
     * Traditionally, BSD select() can't handle multiple processes selecting
     * on the same socket, and wakes up every process in select(). See TCP/IP
     * Illustrated volume 2 page 532. We avoid select() collisions with an
     * external lock file.
     */
    if (stream == 0 && !alone) {
        lock_path = concatenate(DEF_PID_DIR, "/", transport,
                                ".", service_name, (char *) 0);
        why = vstring_alloc(1);
        if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
                                             (struct stat *) 0, -1, -1, why)) == 0)
            msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
        close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
        myfree(lock_path);
        vstring_free(why);
    }

    /*
     * Set up call-back info.
     */
    trigger_server_service = service;
    trigger_server_name = service_name;
    trigger_server_argv = argv + optind;

    /*
     * Run pre-jail initialization.
     */
    if (chdir(var_queue_dir) < 0)
        msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    if (pre_init)
        pre_init(trigger_server_name, trigger_server_argv);

    /*
     * Optionally, restrict the damage that this process can do.
     */
    resolve_local_init();
    tzset();
    chroot_uid(root_dir, user_name);

    /*
     * Run post-jail initialization.
     */
    if (post_init)
        post_init(trigger_server_name, trigger_server_argv);

    /*
     * Are we running as a one-shot server with the client connection on
     * standard input?
     */
    if (stream != 0) {
        if ((len = read(vstream_fileno(stream), buf, sizeof(buf))) <= 0)
            msg_fatal("read: %m");
        service(buf, len, trigger_server_name, trigger_server_argv);
        vstream_fflush(stream);
        trigger_server_exit();
    }

    /*
     * Running as a semi-resident server. Service connection requests.
     * Terminate when we have serviced a sufficient number of clients, when
     * no-one has been talking to us for a configurable amount of time, or
     * when the master process terminated abnormally.
     */
    if (var_idle_limit > 0)
        event_request_timer(trigger_server_timeout, (void *) 0, var_idle_limit);
    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
        event_enable_read(fd, trigger_server_accept, CAST_INT_TO_VOID_PTR(fd));
        close_on_exec(fd, CLOSE_ON_EXEC);
    }
    event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (void *) 0);
    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    watchdog = watchdog_create(trigger_server_watchdog,
                               (WATCHDOG_FN) 0, (void *) 0);

    /*
     * The event loop, at last.
     */
    while (var_use_limit == 0 || use_count < var_use_limit) {
        if (trigger_server_lock != 0) {
            watchdog_stop(watchdog);
            if (myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
                        MYFLOCK_OP_EXCLUSIVE) < 0)
                msg_fatal("select lock: %m");
        }
        watchdog_start(watchdog);
        delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
        event_loop(delay);
    }
    trigger_server_exit();
}
コード例 #17
0
ファイル: postconf.c プロジェクト: j-weiss-consulting/postfix
int     main(int argc, char **argv)
{
    int     ch;
    int     fd;
    struct stat st;
    ARGV   *ext_argv = 0;
    int     param_class = PCF_PARAM_MASK_CLASS;
    static const NAME_MASK param_class_table[] = {
	"builtin", PCF_PARAM_FLAG_BUILTIN,
	"service", PCF_PARAM_FLAG_SERVICE,
	"user", PCF_PARAM_FLAG_USER,
	"all", PCF_PARAM_MASK_CLASS,
	0,
    };
    ARGV   *override_params = 0;

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * Be consistent with file permissions.
     */
    umask(022);

    /*
     * To minimize confusion, make sure that the standard file descriptors
     * are open before opening anything else. XXX Work around for 44BSD where
     * fstat can return EBADF on an open file descriptor.
     */
    for (fd = 0; fd < 3; fd++)
	if (fstat(fd, &st) == -1
	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
	    msg_fatal("open /dev/null: %m");

    /*
     * Set up logging.
     */
    msg_vstream_init(argv[0], VSTREAM_ERR);

    /*
     * Parse JCL.
     */
    while ((ch = GETOPT(argc, argv, "aAbc:C:deEfFhlmMno:pPtvxX#")) > 0) {
	switch (ch) {
	case 'a':
	    pcf_cmd_mode |= PCF_SHOW_SASL_SERV;
	    break;
	case 'A':
	    pcf_cmd_mode |= PCF_SHOW_SASL_CLNT;
	    break;
	case 'b':
	    pcf_cmd_mode |= PCF_EXP_DSN_TEMPL;
	    if (ext_argv)
		msg_fatal("specify one of -b and -t");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0);
	    break;
	case 'c':
	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
		msg_fatal("out of memory");
	    break;
	case 'C':
	    param_class = name_mask_opt("-C option", param_class_table,
			      optarg, NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
	    break;
	case 'd':
	    pcf_cmd_mode |= PCF_SHOW_DEFS;
	    break;
	case 'e':
	    pcf_cmd_mode |= PCF_EDIT_CONF;
	    break;
	case 'f':
	    pcf_cmd_mode |= PCF_FOLD_LINE;
	    break;
	case 'F':
	    pcf_cmd_mode |= PCF_MASTER_FLD;
	    break;
	case '#':
	    pcf_cmd_mode |= PCF_COMMENT_OUT;
	    break;
	case 'h':
	    pcf_cmd_mode |= PCF_HIDE_NAME;
	    break;
	case 'l':
	    pcf_cmd_mode |= PCF_SHOW_LOCKS;
	    break;
	case 'm':
	    pcf_cmd_mode |= PCF_SHOW_MAPS;
	    break;
	case 'M':
	    pcf_cmd_mode |= PCF_MASTER_ENTRY;
	    break;
	case 'n':
	    pcf_cmd_mode |= PCF_SHOW_NONDEF;
	    break;
	case 'o':
	    pcf_cmd_mode |= PCF_MAIN_OVER;
	    if (override_params == 0)
		override_params = argv_alloc(2);
	    argv_add(override_params, optarg, (char *) 0);
	    break;
	case 'p':
	    pcf_cmd_mode |= PCF_MAIN_PARAM;
	    break;
	case 'P':
	    pcf_cmd_mode |= PCF_MASTER_PARAM;
	    break;
	case 't':
	    pcf_cmd_mode |= PCF_DUMP_DSN_TEMPL;
	    if (ext_argv)
		msg_fatal("specify one of -b and -t");
	    ext_argv = argv_alloc(2);
	    argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0);
	    break;
	case 'x':
	    pcf_cmd_mode |= PCF_SHOW_EVAL;
	    break;
	case 'X':
	    /* This is irreversible, therefore require two-finger action. */
	    pcf_cmd_mode |= PCF_EDIT_EXCL;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	default:
	    usage(argv[0]);
	}
    }

    /*
     * Make all options explicit, before checking their compatibility.
     */
#define PCF_MAIN_OR_MASTER \
	(PCF_MAIN_PARAM | PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)

    if ((pcf_cmd_mode & pcf_incompat_options[0]) == 0)
	pcf_cmd_mode |= PCF_MAIN_PARAM;
    if ((pcf_cmd_mode & PCF_MAIN_OR_MASTER)
	&& argv[optind] && strchr(argv[optind], '='))
	pcf_cmd_mode |= PCF_EDIT_CONF;

    /*
     * Sanity check.
     */
    pcf_check_exclusive_options(pcf_cmd_mode);
    pcf_check_compat_options(pcf_cmd_mode);

    if ((pcf_cmd_mode & PCF_EDIT_CONF) && argc == optind)
	msg_fatal("-e requires name=value argument");

    /*
     * Display bounce template information and exit.
     */
    if (ext_argv) {
	if (argv[optind]) {
	    if (argv[optind + 1])
		msg_fatal("options -b and -t require at most one template file");
	    argv_add(ext_argv, "-o",
		     concatenate(VAR_BOUNCE_TMPL, "=",
				 argv[optind], (char *) 0),
		     (char *) 0);
	}
	/* Grr... */
	argv_add(ext_argv, "-o",
		 concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0),
		 (char *) 0);
	mail_conf_read();
	mail_run_replace(var_daemon_dir, ext_argv->argv);
	/* NOTREACHED */
    }

    /*
     * If showing map types, show them and exit
     */
    if (pcf_cmd_mode & PCF_SHOW_MAPS) {
	mail_dict_init();
	pcf_show_maps();
    }

    /*
     * If showing locking methods, show them and exit
     */
    else if (pcf_cmd_mode & PCF_SHOW_LOCKS) {
	pcf_show_locks();
    }

    /*
     * If showing master.cf entries, show them and exit
     */
    else if ((pcf_cmd_mode & (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM))
    && !(pcf_cmd_mode & (PCF_EDIT_CONF | PCF_EDIT_EXCL | PCF_COMMENT_OUT))) {
	pcf_read_master(PCF_FAIL_ON_OPEN_ERROR);
	pcf_read_parameters();
	if (override_params)
	    pcf_set_parameters(override_params->argv);
	pcf_register_builtin_parameters(basename(argv[0]), getpid());
	pcf_register_service_parameters();
	pcf_register_user_parameters();
	if (pcf_cmd_mode & PCF_MASTER_FLD)
	    pcf_show_master_fields(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
				   argv + optind);
	else if (pcf_cmd_mode & PCF_MASTER_PARAM)
	    pcf_show_master_params(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
				   argv + optind);
	else
	    pcf_show_master_entries(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
				    argv + optind);
    }

    /*
     * If showing SASL plug-in types, show them and exit
     */
    else if (pcf_cmd_mode & PCF_SHOW_SASL_SERV) {
	pcf_show_sasl(PCF_SHOW_SASL_SERV);
    } else if (pcf_cmd_mode & PCF_SHOW_SASL_CLNT) {
	pcf_show_sasl(PCF_SHOW_SASL_CLNT);
    }

    /*
     * Edit main.cf or master.cf.
     */
    else if (pcf_cmd_mode & (PCF_EDIT_CONF | PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
	if (optind == argc)
	    msg_fatal("missing service argument");
	if (pcf_cmd_mode & (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)) {
	    pcf_edit_master(pcf_cmd_mode, argc - optind, argv + optind);
	} else {
	    pcf_edit_main(pcf_cmd_mode, argc - optind, argv + optind);
	}
    }

    /*
     * If showing non-default values, read main.cf.
     */
    else {
	if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0) {
	    pcf_read_parameters();
	    if (override_params)
		pcf_set_parameters(override_params->argv);
	}
	pcf_register_builtin_parameters(basename(argv[0]), getpid());

	/*
	 * Add service-dependent parameters (service names from master.cf)
	 * and user-defined parameters ($name macros in parameter values in
	 * main.cf and master.cf, but only if those names have a name=value
	 * in main.cf or master.cf).
	 */
	pcf_read_master(PCF_WARN_ON_OPEN_ERROR);
	pcf_register_service_parameters();
	if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0)
	    pcf_register_user_parameters();

	/*
	 * Show the requested values.
	 */
	pcf_show_parameters(VSTREAM_OUT, pcf_cmd_mode, param_class,
			    argv + optind);

	/*
	 * Flag unused parameters. This makes no sense with "postconf -d",
	 * because that ignores all the user-specified parameters and
	 * user-specified macro expansions in main.cf.
	 */
	if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0) {
	    pcf_flag_unused_main_parameters();
	    pcf_flag_unused_master_parameters();
	}
    }
    vstream_fflush(VSTREAM_OUT);
    exit(0);
}