1 /* 2 * Copyright (c) 1998-2001 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.94 2007/05/11 18:50:36 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]\n"); 103 exit(EX_USAGE); 104 } 105 } 106 argc -= optind; 107 argv += optind; 108 109 if (filename != NULL) 110 { 111 praliases(filename, argc, argv); 112 exit(EX_OK); 113 } 114 115 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, 116 NULL)) == NULL) 117 { 118 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 119 "praliases: %s: %s\n", cfile, 120 sm_errstring(errno)); 121 exit(EX_NOINPUT); 122 } 123 124 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 125 { 126 register char *b, *p; 127 128 b = strchr(buf, '\n'); 129 if (b != NULL) 130 *b = '\0'; 131 132 b = buf; 133 switch (*b++) 134 { 135 case 'O': /* option -- see if alias file */ 136 if (sm_strncasecmp(b, " AliasFile", 10) == 0 && 137 !(isascii(b[10]) && isalnum(b[10]))) 138 { 139 /* new form -- find value */ 140 b = strchr(b, '='); 141 if (b == NULL) 142 continue; 143 while (isascii(*++b) && isspace(*b)) 144 continue; 145 } 146 else if (*b++ != 'A') 147 { 148 /* something else boring */ 149 continue; 150 } 151 152 /* this is the A or AliasFile option -- save it */ 153 if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >= 154 sizeof afilebuf) 155 { 156 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 157 "praliases: AliasFile filename too long: %.30s\n", 158 b); 159 (void) sm_io_close(cfp, SM_TIME_DEFAULT); 160 exit(EX_CONFIG); 161 } 162 b = afilebuf; 163 164 for (p = b; p != NULL; ) 165 { 166 while (isascii(*p) && isspace(*p)) 167 p++; 168 if (*p == '\0') 169 break; 170 b = p; 171 172 p = strpbrk(p, DELIMITERS); 173 174 /* find end of spec */ 175 if (p != NULL) 176 { 177 bool quoted = false; 178 179 for (; *p != '\0'; p++) 180 { 181 /* 182 ** Don't break into a quoted 183 ** string. 184 */ 185 186 if (*p == '"') 187 quoted = !quoted; 188 else if (*p == ',' && !quoted) 189 break; 190 } 191 192 /* No more alias specs follow */ 193 if (*p == '\0') 194 { 195 /* chop trailing whitespace */ 196 while (isascii(*p) && 197 isspace(*p) && 198 p > b) 199 p--; 200 *p = '\0'; 201 p = NULL; 202 } 203 } 204 205 if (p != NULL) 206 { 207 char *e = p - 1; 208 209 /* chop trailing whitespace */ 210 while (isascii(*e) && 211 isspace(*e) && 212 e > b) 213 e--; 214 *++e = '\0'; 215 *p++ = '\0'; 216 } 217 praliases(b, argc, argv); 218 } 219 220 default: 221 continue; 222 } 223 } 224 (void) sm_io_close(cfp, SM_TIME_DEFAULT); 225 exit(EX_OK); 226 /* NOTREACHED */ 227 return EX_OK; 228 } 229 230 static void 231 praliases(filename, argc, argv) 232 char *filename; 233 int argc; 234 char **argv; 235 { 236 int result; 237 char *colon; 238 char *db_name; 239 char *db_type; 240 SMDB_DATABASE *database = NULL; 241 SMDB_CURSOR *cursor = NULL; 242 SMDB_DBENT db_key, db_value; 243 SMDB_DBPARAMS params; 244 SMDB_USER_INFO user_info; 245 246 colon = strchr(filename, PATH_SEPARATOR); 247 if (colon == NULL) 248 { 249 db_name = filename; 250 db_type = SMDB_TYPE_DEFAULT; 251 } 252 else 253 { 254 *colon = '\0'; 255 db_name = colon + 1; 256 db_type = filename; 257 } 258 259 /* clean off arguments */ 260 for (;;) 261 { 262 while (isascii(*db_name) && isspace(*db_name)) 263 db_name++; 264 265 if (*db_name != '-') 266 break; 267 while (*db_name != '\0' && 268 !(isascii(*db_name) && isspace(*db_name))) 269 db_name++; 270 } 271 272 /* Skip non-file based DB types */ 273 if (db_type != NULL && *db_type != '\0') 274 { 275 if (db_type != SMDB_TYPE_DEFAULT && 276 strcmp(db_type, "hash") != 0 && 277 strcmp(db_type, "btree") != 0 && 278 strcmp(db_type, "dbm") != 0) 279 { 280 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 281 "praliases: Skipping non-file based alias type %s\n", 282 db_type); 283 return; 284 } 285 } 286 287 if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) 288 { 289 if (colon != NULL) 290 *colon = ':'; 291 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 292 "praliases: illegal alias specification: %s\n", filename); 293 goto fatal; 294 } 295 296 memset(¶ms, '\0', sizeof params); 297 params.smdbp_cache_size = 1024 * 1024; 298 299 user_info.smdbu_id = RunAsUid; 300 user_info.smdbu_group_id = RunAsGid; 301 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, 302 SMDB_MAX_USER_NAME_LEN); 303 304 result = smdb_open_database(&database, db_name, O_RDONLY, 0, 305 SFF_ROOTOK, db_type, &user_info, ¶ms); 306 if (result != SMDBE_OK) 307 { 308 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 309 "praliases: %s: open: %s\n", 310 db_name, sm_errstring(result)); 311 goto fatal; 312 } 313 314 if (argc == 0) 315 { 316 memset(&db_key, '\0', sizeof db_key); 317 memset(&db_value, '\0', sizeof db_value); 318 319 result = database->smdb_cursor(database, &cursor, 0); 320 if (result != SMDBE_OK) 321 { 322 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 323 "praliases: %s: set cursor: %s\n", db_name, 324 sm_errstring(result)); 325 goto fatal; 326 } 327 328 while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 329 SMDB_CURSOR_GET_NEXT)) == 330 SMDBE_OK) 331 { 332 #if 0 333 /* skip magic @:@ entry */ 334 if (db_key.size == 2 && 335 db_key.data[0] == '@' && 336 db_key.data[1] == '\0' && 337 db_value.size == 2 && 338 db_value.data[0] == '@' && 339 db_value.data[1] == '\0') 340 continue; 341 #endif /* 0 */ 342 343 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 344 "%.*s:%.*s\n", 345 (int) db_key.size, 346 (char *) db_key.data, 347 (int) db_value.size, 348 (char *) db_value.data); 349 } 350 351 if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 352 { 353 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 354 "praliases: %s: get value at cursor: %s\n", 355 db_name, sm_errstring(result)); 356 goto fatal; 357 } 358 } 359 else for (; *argv != NULL; ++argv) 360 { 361 int get_res; 362 363 memset(&db_key, '\0', sizeof db_key); 364 memset(&db_value, '\0', sizeof db_value); 365 db_key.data = *argv; 366 db_key.size = strlen(*argv); 367 get_res = database->smdb_get(database, &db_key, &db_value, 0); 368 if (get_res == SMDBE_NOT_FOUND) 369 { 370 db_key.size++; 371 get_res = database->smdb_get(database, &db_key, 372 &db_value, 0); 373 } 374 if (get_res == SMDBE_OK) 375 { 376 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 377 "%.*s:%.*s\n", 378 (int) db_key.size, 379 (char *) db_key.data, 380 (int) db_value.size, 381 (char *) db_value.data); 382 } 383 else 384 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 385 "%s: No such key\n", 386 (char *)db_key.data); 387 } 388 389 fatal: 390 if (cursor != NULL) 391 (void) cursor->smdbc_close(cursor); 392 if (database != NULL) 393 (void) database->smdb_close(database); 394 if (colon != NULL) 395 *colon = ':'; 396 return; 397 } 398