1N/A/*
1N/A * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A * Copyright (c) 1983 Eric P. Allman. All rights reserved.
1N/A * Copyright (c) 1988, 1993
1N/A * The Regents of the University of California. All rights reserved.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A *
1N/A */
1N/A
1N/A#include <sm/gen.h>
1N/A
1N/ASM_IDSTR(copyright,
1N/A"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
1N/A All rights reserved.\n\
1N/A Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\
1N/A Copyright (c) 1988, 1993\n\
1N/A The Regents of the University of California. All rights reserved.\n")
1N/A
1N/ASM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $")
1N/A
1N/A#include <sys/types.h>
1N/A#include <ctype.h>
1N/A#include <stdlib.h>
1N/A#include <unistd.h>
1N/A#ifdef EX_OK
1N/A# undef EX_OK /* unistd.h may have another use for this */
1N/A#endif /* EX_OK */
1N/A#include <sysexits.h>
1N/A
1N/A
1N/A#ifndef NOT_SENDMAIL
1N/A# define NOT_SENDMAIL
1N/A#endif /* ! NOT_SENDMAIL */
1N/A#include <sendmail/sendmail.h>
1N/A#include <sendmail/pathnames.h>
1N/A#include <libsmdb/smdb.h>
1N/A
1N/Astatic void praliases __P((char *, int, char **));
1N/A
1N/Auid_t RealUid;
1N/Agid_t RealGid;
1N/Achar *RealUserName;
1N/Auid_t RunAsUid;
1N/Agid_t RunAsGid;
1N/Achar *RunAsUserName;
1N/Aint Verbose = 2;
1N/Abool DontInitGroups = false;
1N/Auid_t TrustedUid = 0;
1N/ABITMAP256 DontBlameSendmail;
1N/A
1N/A# define DELIMITERS " ,/"
1N/A# define PATH_SEPARATOR ':'
1N/A
1N/Aint
1N/Amain(argc, argv)
1N/A int argc;
1N/A char **argv;
1N/A{
1N/A char *cfile;
1N/A char *filename = NULL;
1N/A SM_FILE_T *cfp;
1N/A int ch;
1N/A char afilebuf[MAXLINE];
1N/A char buf[MAXLINE];
1N/A struct passwd *pw;
1N/A static char rnamebuf[MAXNAME];
1N/A extern char *optarg;
1N/A extern int optind;
1N/A
1N/A clrbitmap(DontBlameSendmail);
1N/A RunAsUid = RealUid = getuid();
1N/A RunAsGid = RealGid = getgid();
1N/A pw = getpwuid(RealUid);
1N/A if (pw != NULL)
1N/A {
1N/A if (strlen(pw->pw_name) > MAXNAME - 1)
1N/A pw->pw_name[MAXNAME] = 0;
1N/A sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
1N/A }
1N/A else
1N/A (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
1N/A "Unknown UID %d", (int) RealUid);
1N/A RunAsUserName = RealUserName = rnamebuf;
1N/A
1N/A cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
1N/A while ((ch = getopt(argc, argv, "C:f:")) != -1)
1N/A {
1N/A switch ((char)ch) {
1N/A case 'C':
1N/A cfile = optarg;
1N/A break;
1N/A case 'f':
1N/A filename = optarg;
1N/A break;
1N/A case '?':
1N/A default:
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "usage: praliases [-C cffile] [-f aliasfile]"
1N/A " [key ...]\n");
1N/A exit(EX_USAGE);
1N/A }
1N/A }
1N/A argc -= optind;
1N/A argv += optind;
1N/A
1N/A if (filename != NULL)
1N/A {
1N/A praliases(filename, argc, argv);
1N/A exit(EX_OK);
1N/A }
1N/A
1N/A if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
1N/A NULL)) == NULL)
1N/A {
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: %s: %s\n", cfile,
1N/A sm_errstring(errno));
1N/A exit(EX_NOINPUT);
1N/A }
1N/A
1N/A while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
1N/A {
1N/A register char *b, *p;
1N/A
1N/A b = strchr(buf, '\n');
1N/A if (b != NULL)
1N/A *b = '\0';
1N/A
1N/A b = buf;
1N/A switch (*b++)
1N/A {
1N/A case 'O': /* option -- see if alias file */
1N/A if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
1N/A !(isascii(b[10]) && isalnum(b[10])))
1N/A {
1N/A /* new form -- find value */
1N/A b = strchr(b, '=');
1N/A if (b == NULL)
1N/A continue;
1N/A while (isascii(*++b) && isspace(*b))
1N/A continue;
1N/A }
1N/A else if (*b++ != 'A')
1N/A {
1N/A /* something else boring */
1N/A continue;
1N/A }
1N/A
1N/A /* this is the A or AliasFile option -- save it */
1N/A if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
1N/A sizeof afilebuf)
1N/A {
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: AliasFile filename too long: %.30s\n",
1N/A b);
1N/A (void) sm_io_close(cfp, SM_TIME_DEFAULT);
1N/A exit(EX_CONFIG);
1N/A }
1N/A b = afilebuf;
1N/A
1N/A for (p = b; p != NULL; )
1N/A {
1N/A while (isascii(*p) && isspace(*p))
1N/A p++;
1N/A if (*p == '\0')
1N/A break;
1N/A b = p;
1N/A
1N/A p = strpbrk(p, DELIMITERS);
1N/A
1N/A /* find end of spec */
1N/A if (p != NULL)
1N/A {
1N/A bool quoted = false;
1N/A
1N/A for (; *p != '\0'; p++)
1N/A {
1N/A /*
1N/A ** Don't break into a quoted
1N/A ** string.
1N/A */
1N/A
1N/A if (*p == '"')
1N/A quoted = !quoted;
1N/A else if (*p == ',' && !quoted)
1N/A break;
1N/A }
1N/A
1N/A /* No more alias specs follow */
1N/A if (*p == '\0')
1N/A {
1N/A /* chop trailing whitespace */
1N/A while (isascii(*p) &&
1N/A isspace(*p) &&
1N/A p > b)
1N/A p--;
1N/A *p = '\0';
1N/A p = NULL;
1N/A }
1N/A }
1N/A
1N/A if (p != NULL)
1N/A {
1N/A char *e = p - 1;
1N/A
1N/A /* chop trailing whitespace */
1N/A while (isascii(*e) &&
1N/A isspace(*e) &&
1N/A e > b)
1N/A e--;
1N/A *++e = '\0';
1N/A *p++ = '\0';
1N/A }
1N/A praliases(b, argc, argv);
1N/A }
1N/A
1N/A default:
1N/A continue;
1N/A }
1N/A }
1N/A (void) sm_io_close(cfp, SM_TIME_DEFAULT);
1N/A exit(EX_OK);
1N/A /* NOTREACHED */
1N/A return EX_OK;
1N/A}
1N/A
1N/Astatic void
1N/Apraliases(filename, argc, argv)
1N/A char *filename;
1N/A int argc;
1N/A char **argv;
1N/A{
1N/A int result;
1N/A char *colon;
1N/A char *db_name;
1N/A char *db_type;
1N/A SMDB_DATABASE *database = NULL;
1N/A SMDB_CURSOR *cursor = NULL;
1N/A SMDB_DBENT db_key, db_value;
1N/A SMDB_DBPARAMS params;
1N/A SMDB_USER_INFO user_info;
1N/A
1N/A colon = strchr(filename, PATH_SEPARATOR);
1N/A if (colon == NULL)
1N/A {
1N/A db_name = filename;
1N/A db_type = SMDB_TYPE_DEFAULT;
1N/A }
1N/A else
1N/A {
1N/A *colon = '\0';
1N/A db_name = colon + 1;
1N/A db_type = filename;
1N/A }
1N/A
1N/A /* clean off arguments */
1N/A for (;;)
1N/A {
1N/A while (isascii(*db_name) && isspace(*db_name))
1N/A db_name++;
1N/A
1N/A if (*db_name != '-')
1N/A break;
1N/A while (*db_name != '\0' &&
1N/A !(isascii(*db_name) && isspace(*db_name)))
1N/A db_name++;
1N/A }
1N/A
1N/A /* Skip non-file based DB types */
1N/A if (db_type != NULL && *db_type != '\0')
1N/A {
1N/A if (db_type != SMDB_TYPE_DEFAULT &&
1N/A strcmp(db_type, "hash") != 0 &&
1N/A strcmp(db_type, "btree") != 0 &&
1N/A strcmp(db_type, "dbm") != 0)
1N/A {
1N/A sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: Skipping non-file based alias type %s\n",
1N/A db_type);
1N/A return;
1N/A }
1N/A }
1N/A
1N/A if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
1N/A {
1N/A if (colon != NULL)
1N/A *colon = ':';
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: illegal alias specification: %s\n", filename);
1N/A goto fatal;
1N/A }
1N/A
1N/A memset(&params, '\0', sizeof params);
1N/A params.smdbp_cache_size = 1024 * 1024;
1N/A
1N/A user_info.smdbu_id = RunAsUid;
1N/A user_info.smdbu_group_id = RunAsGid;
1N/A (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
1N/A SMDB_MAX_USER_NAME_LEN);
1N/A
1N/A result = smdb_open_database(&database, db_name, O_RDONLY, 0,
1N/A SFF_ROOTOK, db_type, &user_info, &params);
1N/A if (result != SMDBE_OK)
1N/A {
1N/A sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: %s: open: %s\n",
1N/A db_name, sm_errstring(result));
1N/A goto fatal;
1N/A }
1N/A
1N/A if (argc == 0)
1N/A {
1N/A memset(&db_key, '\0', sizeof db_key);
1N/A memset(&db_value, '\0', sizeof db_value);
1N/A
1N/A result = database->smdb_cursor(database, &cursor, 0);
1N/A if (result != SMDBE_OK)
1N/A {
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: %s: set cursor: %s\n", db_name,
1N/A sm_errstring(result));
1N/A goto fatal;
1N/A }
1N/A
1N/A while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
1N/A SMDB_CURSOR_GET_NEXT)) ==
1N/A SMDBE_OK)
1N/A {
1N/A#if 0
1N/A /* skip magic @:@ entry */
1N/A if (db_key.size == 2 &&
1N/A db_key.data[0] == '@' &&
1N/A db_key.data[1] == '\0' &&
1N/A db_value.size == 2 &&
1N/A db_value.data[0] == '@' &&
1N/A db_value.data[1] == '\0')
1N/A continue;
1N/A#endif /* 0 */
1N/A
1N/A (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1N/A "%.*s:%.*s\n",
1N/A (int) db_key.size,
1N/A (char *) db_key.data,
1N/A (int) db_value.size,
1N/A (char *) db_value.data);
1N/A }
1N/A
1N/A if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
1N/A {
1N/A (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1N/A "praliases: %s: get value at cursor: %s\n",
1N/A db_name, sm_errstring(result));
1N/A goto fatal;
1N/A }
1N/A }
1N/A else for (; *argv != NULL; ++argv)
1N/A {
1N/A int get_res;
1N/A
1N/A memset(&db_key, '\0', sizeof db_key);
1N/A memset(&db_value, '\0', sizeof db_value);
1N/A db_key.data = *argv;
1N/A db_key.size = strlen(*argv);
1N/A get_res = database->smdb_get(database, &db_key, &db_value, 0);
1N/A if (get_res == SMDBE_NOT_FOUND)
1N/A {
1N/A db_key.size++;
1N/A get_res = database->smdb_get(database, &db_key,
1N/A &db_value, 0);
1N/A }
1N/A if (get_res == SMDBE_OK)
1N/A {
1N/A (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1N/A "%.*s:%.*s\n",
1N/A (int) db_key.size,
1N/A (char *) db_key.data,
1N/A (int) db_value.size,
1N/A (char *) db_value.data);
1N/A }
1N/A else
1N/A (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1N/A "%s: No such key\n",
1N/A (char *)db_key.data);
1N/A }
1N/A
1N/A fatal:
1N/A if (cursor != NULL)
1N/A (void) cursor->smdbc_close(cursor);
1N/A if (database != NULL)
1N/A (void) database->smdb_close(database);
1N/A if (colon != NULL)
1N/A *colon = ':';
1N/A return;
1N/A}