1 /* 2 * Copyright (c) 1998-2001, 2008 Proofpoint, 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 Proofpoint, 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.98 2013-11-22 20:51:53 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 32 #include <sysexits.h> 33 34 35 #ifndef NOT_SENDMAIL 36 # define NOT_SENDMAIL 37 #endif 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)) >= 0) 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 !smdb_is_db_type(db_type)) 278 { 279 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 280 "praliases: Skipping non-file based alias type %s\n", 281 db_type); 282 return; 283 } 284 } 285 286 if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) 287 { 288 if (colon != NULL) 289 *colon = ':'; 290 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 291 "praliases: illegal alias specification: %s\n", filename); 292 goto fatal; 293 } 294 295 memset(¶ms, '\0', sizeof params); 296 params.smdbp_cache_size = 1024 * 1024; 297 298 user_info.smdbu_id = RunAsUid; 299 user_info.smdbu_group_id = RunAsGid; 300 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, 301 SMDB_MAX_USER_NAME_LEN); 302 303 result = smdb_open_database(&database, db_name, O_RDONLY, 0, 304 SFF_ROOTOK, db_type, &user_info, ¶ms); 305 if (result != SMDBE_OK) 306 { 307 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 308 "praliases: %s: open: %s\n", 309 db_name, sm_errstring(result)); 310 goto fatal; 311 } 312 313 if (argc == 0) 314 { 315 memset(&db_key, '\0', sizeof db_key); 316 memset(&db_value, '\0', sizeof db_value); 317 318 result = database->smdb_cursor(database, &cursor, 0); 319 if (result != SMDBE_OK) 320 { 321 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 322 "praliases: %s: set cursor: %s\n", db_name, 323 sm_errstring(result)); 324 goto fatal; 325 } 326 327 while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 328 SMDB_CURSOR_GET_NEXT)) == 329 SMDBE_OK) 330 { 331 #if 0 332 /* skip magic @:@ entry */ 333 if (db_key.size == 2 && 334 db_key.data[0] == '@' && 335 db_key.data[1] == '\0' && 336 db_value.size == 2 && 337 db_value.data[0] == '@' && 338 db_value.data[1] == '\0') 339 continue; 340 #endif /* 0 */ 341 342 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 343 "%.*s:%.*s\n", 344 (int) db_key.size, 345 (char *) db_key.data, 346 (int) db_value.size, 347 (char *) db_value.data); 348 } 349 350 if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 351 { 352 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 353 "praliases: %s: get value at cursor: %s\n", 354 db_name, sm_errstring(result)); 355 goto fatal; 356 } 357 } 358 else for (; *argv != NULL; ++argv) 359 { 360 int get_res; 361 362 memset(&db_key, '\0', sizeof db_key); 363 memset(&db_value, '\0', sizeof db_value); 364 db_key.data = *argv; 365 db_key.size = strlen(*argv); 366 get_res = database->smdb_get(database, &db_key, &db_value, 0); 367 if (get_res == SMDBE_NOT_FOUND) 368 { 369 db_key.size++; 370 get_res = database->smdb_get(database, &db_key, 371 &db_value, 0); 372 } 373 if (get_res == SMDBE_OK) 374 { 375 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 376 "%.*s:%.*s\n", 377 (int) db_key.size, 378 (char *) db_key.data, 379 (int) db_value.size, 380 (char *) db_value.data); 381 } 382 else 383 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 384 "%s: No such key\n", 385 (char *)db_key.data); 386 } 387 388 fatal: 389 if (cursor != NULL) 390 (void) cursor->smdbc_close(cursor); 391 if (database != NULL) 392 (void) database->smdb_close(database); 393 if (colon != NULL) 394 *colon = ':'; 395 return; 396 } 397