Home | History | Annotate | Download | only in aux
      1 /*
      2  * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers.
      3  *	All rights reserved.
      4  * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
      5  * Copyright (c) 1988, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * By using this file, you agree to the terms and conditions set
      9  * forth in the LICENSE file which can be found at the top level of
     10  * the sendmail distribution.
     11  *
     12  */
     13 
     14 #include <sm/gen.h>
     15 
     16 SM_IDSTR(copyright,
     17 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
     18 	All rights reserved.\n\
     19      Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
     20      Copyright (c) 1988, 1993\n\
     21 	The Regents of the University of California.  All rights reserved.\n")
     22 
     23 SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $")
     24 
     25 #include <sys/types.h>
     26 #include <ctype.h>
     27 #include <stdlib.h>
     28 #include <unistd.h>
     29 #ifdef EX_OK
     30 # undef EX_OK		/* unistd.h may have another use for this */
     31 #endif /* EX_OK */
     32 #include <sysexits.h>
     33 
     34 
     35 #ifndef NOT_SENDMAIL
     36 # define NOT_SENDMAIL
     37 #endif /* ! NOT_SENDMAIL */
     38 #include <sendmail/sendmail.h>
     39 #include <sendmail/pathnames.h>
     40 #include <libsmdb/smdb.h>
     41 
     42 static void praliases __P((char *, int, char **));
     43 
     44 uid_t	RealUid;
     45 gid_t	RealGid;
     46 char	*RealUserName;
     47 uid_t	RunAsUid;
     48 gid_t	RunAsGid;
     49 char	*RunAsUserName;
     50 int	Verbose = 2;
     51 bool	DontInitGroups = false;
     52 uid_t	TrustedUid = 0;
     53 BITMAP256 DontBlameSendmail;
     54 
     55 # define DELIMITERS		" ,/"
     56 # define PATH_SEPARATOR		':'
     57 
     58 int
     59 main(argc, argv)
     60 	int argc;
     61 	char **argv;
     62 {
     63 	char *cfile;
     64 	char *filename = NULL;
     65 	SM_FILE_T *cfp;
     66 	int ch;
     67 	char afilebuf[MAXLINE];
     68 	char buf[MAXLINE];
     69 	struct passwd *pw;
     70 	static char rnamebuf[MAXNAME];
     71 	extern char *optarg;
     72 	extern int optind;
     73 
     74 	clrbitmap(DontBlameSendmail);
     75 	RunAsUid = RealUid = getuid();
     76 	RunAsGid = RealGid = getgid();
     77 	pw = getpwuid(RealUid);
     78 	if (pw != NULL)
     79 	{
     80 		if (strlen(pw->pw_name) > MAXNAME - 1)
     81 			pw->pw_name[MAXNAME] = 0;
     82 		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
     83 	}
     84 	else
     85 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
     86 		    "Unknown UID %d", (int) RealUid);
     87 	RunAsUserName = RealUserName = rnamebuf;
     88 
     89 	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
     90 	while ((ch = getopt(argc, argv, "C:f:")) != -1)
     91 	{
     92 		switch ((char)ch) {
     93 		case 'C':
     94 			cfile = optarg;
     95 			break;
     96 		case 'f':
     97 			filename = optarg;
     98 			break;
     99 		case '?':
    100 		default:
    101 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    102 			    "usage: praliases [-C cffile] [-f aliasfile]"
    103 			    " [key ...]\n");
    104 			exit(EX_USAGE);
    105 		}
    106 	}
    107 	argc -= optind;
    108 	argv += optind;
    109 
    110 	if (filename != NULL)
    111 	{
    112 		praliases(filename, argc, argv);
    113 		exit(EX_OK);
    114 	}
    115 
    116 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
    117 			      NULL)) == NULL)
    118 	{
    119 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    120 				     "praliases: %s: %s\n", cfile,
    121 				     sm_errstring(errno));
    122 		exit(EX_NOINPUT);
    123 	}
    124 
    125 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
    126 	{
    127 		register char *b, *p;
    128 
    129 		b = strchr(buf, '\n');
    130 		if (b != NULL)
    131 			*b = '\0';
    132 
    133 		b = buf;
    134 		switch (*b++)
    135 		{
    136 		  case 'O':		/* option -- see if alias file */
    137 			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
    138 			    !(isascii(b[10]) && isalnum(b[10])))
    139 			{
    140 				/* new form -- find value */
    141 				b = strchr(b, '=');
    142 				if (b == NULL)
    143 					continue;
    144 				while (isascii(*++b) && isspace(*b))
    145 					continue;
    146 			}
    147 			else if (*b++ != 'A')
    148 			{
    149 				/* something else boring */
    150 				continue;
    151 			}
    152 
    153 			/* this is the A or AliasFile option -- save it */
    154 			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
    155 			    sizeof afilebuf)
    156 			{
    157 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    158 				    "praliases: AliasFile filename too long: %.30s\n",
    159 					b);
    160 				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
    161 				exit(EX_CONFIG);
    162 			}
    163 			b = afilebuf;
    164 
    165 			for (p = b; p != NULL; )
    166 			{
    167 				while (isascii(*p) && isspace(*p))
    168 					p++;
    169 				if (*p == '\0')
    170 					break;
    171 				b = p;
    172 
    173 				p = strpbrk(p, DELIMITERS);
    174 
    175 				/* find end of spec */
    176 				if (p != NULL)
    177 				{
    178 					bool quoted = false;
    179 
    180 					for (; *p != '\0'; p++)
    181 					{
    182 						/*
    183 						**  Don't break into a quoted
    184 						**  string.
    185 						*/
    186 
    187 						if (*p == '"')
    188 							quoted = !quoted;
    189 						else if (*p == ',' && !quoted)
    190 							break;
    191 					}
    192 
    193 					/* No more alias specs follow */
    194 					if (*p == '\0')
    195 					{
    196 						/* chop trailing whitespace */
    197 						while (isascii(*p) &&
    198 						       isspace(*p) &&
    199 						       p > b)
    200 							p--;
    201 						*p = '\0';
    202 						p = NULL;
    203 					}
    204 				}
    205 
    206 				if (p != NULL)
    207 				{
    208 					char *e = p - 1;
    209 
    210 					/* chop trailing whitespace */
    211 					while (isascii(*e) &&
    212 					       isspace(*e) &&
    213 					       e > b)
    214 						e--;
    215 					*++e = '\0';
    216 					*p++ = '\0';
    217 				}
    218 				praliases(b, argc, argv);
    219 			}
    220 
    221 		  default:
    222 			continue;
    223 		}
    224 	}
    225 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
    226 	exit(EX_OK);
    227 	/* NOTREACHED */
    228 	return EX_OK;
    229 }
    230 
    231 static void
    232 praliases(filename, argc, argv)
    233 	char *filename;
    234 	int argc;
    235 	char **argv;
    236 {
    237 	int result;
    238 	char *colon;
    239 	char *db_name;
    240 	char *db_type;
    241 	SMDB_DATABASE *database = NULL;
    242 	SMDB_CURSOR *cursor = NULL;
    243 	SMDB_DBENT db_key, db_value;
    244 	SMDB_DBPARAMS params;
    245 	SMDB_USER_INFO user_info;
    246 
    247 	colon = strchr(filename, PATH_SEPARATOR);
    248 	if (colon == NULL)
    249 	{
    250 		db_name = filename;
    251 		db_type = SMDB_TYPE_DEFAULT;
    252 	}
    253 	else
    254 	{
    255 		*colon = '\0';
    256 		db_name = colon + 1;
    257 		db_type = filename;
    258 	}
    259 
    260 	/* clean off arguments */
    261 	for (;;)
    262 	{
    263 		while (isascii(*db_name) && isspace(*db_name))
    264 			db_name++;
    265 
    266 		if (*db_name != '-')
    267 			break;
    268 		while (*db_name != '\0' &&
    269 		       !(isascii(*db_name) && isspace(*db_name)))
    270 			db_name++;
    271 	}
    272 
    273 	/* Skip non-file based DB types */
    274 	if (db_type != NULL && *db_type != '\0')
    275 	{
    276 		if (db_type != SMDB_TYPE_DEFAULT &&
    277 		    strcmp(db_type, "hash") != 0 &&
    278 		    strcmp(db_type, "btree") != 0 &&
    279 		    strcmp(db_type, "dbm") != 0)
    280 		{
    281 			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    282 				      "praliases: Skipping non-file based alias type %s\n",
    283 				db_type);
    284 			return;
    285 		}
    286 	}
    287 
    288 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
    289 	{
    290 		if (colon != NULL)
    291 			*colon = ':';
    292 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    293 		    "praliases: illegal alias specification: %s\n", filename);
    294 		goto fatal;
    295 	}
    296 
    297 	memset(&params, '\0', sizeof params);
    298 	params.smdbp_cache_size = 1024 * 1024;
    299 
    300 	user_info.smdbu_id = RunAsUid;
    301 	user_info.smdbu_group_id = RunAsGid;
    302 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
    303 			  SMDB_MAX_USER_NAME_LEN);
    304 
    305 	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
    306 				    SFF_ROOTOK, db_type, &user_info, &params);
    307 	if (result != SMDBE_OK)
    308 	{
    309 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    310 			      "praliases: %s: open: %s\n",
    311 			      db_name, sm_errstring(result));
    312 		goto fatal;
    313 	}
    314 
    315 	if (argc == 0)
    316 	{
    317 		memset(&db_key, '\0', sizeof db_key);
    318 		memset(&db_value, '\0', sizeof db_value);
    319 
    320 		result = database->smdb_cursor(database, &cursor, 0);
    321 		if (result != SMDBE_OK)
    322 		{
    323 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    324 			    "praliases: %s: set cursor: %s\n", db_name,
    325 			    sm_errstring(result));
    326 			goto fatal;
    327 		}
    328 
    329 		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
    330 						   SMDB_CURSOR_GET_NEXT)) ==
    331 						   SMDBE_OK)
    332 		{
    333 #if 0
    334 			/* skip magic @:@ entry */
    335 			if (db_key.size == 2 &&
    336 			    db_key.data[0] == '@' &&
    337 			    db_key.data[1] == '\0' &&
    338 			    db_value.size == 2 &&
    339 			    db_value.data[0] == '@' &&
    340 			    db_value.data[1] == '\0')
    341 				continue;
    342 #endif /* 0 */
    343 
    344 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
    345 					     "%.*s:%.*s\n",
    346 					     (int) db_key.size,
    347 					     (char *) db_key.data,
    348 					     (int) db_value.size,
    349 					     (char *) db_value.data);
    350 		}
    351 
    352 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
    353 		{
    354 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
    355 				"praliases: %s: get value at cursor: %s\n",
    356 				db_name, sm_errstring(result));
    357 			goto fatal;
    358 		}
    359 	}
    360 	else for (; *argv != NULL; ++argv)
    361 	{
    362 		int get_res;
    363 
    364 		memset(&db_key, '\0', sizeof db_key);
    365 		memset(&db_value, '\0', sizeof db_value);
    366 		db_key.data = *argv;
    367 		db_key.size = strlen(*argv);
    368 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
    369 		if (get_res == SMDBE_NOT_FOUND)
    370 		{
    371 			db_key.size++;
    372 			get_res = database->smdb_get(database, &db_key,
    373 						     &db_value, 0);
    374 		}
    375 		if (get_res == SMDBE_OK)
    376 		{
    377 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
    378 					     "%.*s:%.*s\n",
    379 					     (int) db_key.size,
    380 					     (char *) db_key.data,
    381 					     (int) db_value.size,
    382 					     (char *) db_value.data);
    383 		}
    384 		else
    385 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
    386 					     "%s: No such key\n",
    387 					     (char *)db_key.data);
    388 	}
    389 
    390  fatal:
    391 	if (cursor != NULL)
    392 		(void) cursor->smdbc_close(cursor);
    393 	if (database != NULL)
    394 		(void) database->smdb_close(database);
    395 	if (colon != NULL)
    396 		*colon = ':';
    397 	return;
    398 }
    399