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 #ifndef lint 15 static char copyright[] = 16 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ 17 All rights reserved.\n\ 18 Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\ 19 Copyright (c) 1988, 1993\n\ 20 The Regents of the University of California. All rights reserved.\n"; 21 #endif /* ! lint */ 22 23 #ifndef lint 24 static char id[] = "@(#)$Id: praliases.c,v 8.59.4.19 2001/02/28 02:37:57 ca Exp $"; 25 #endif /* ! lint */ 26 27 #include <sys/types.h> 28 #include <ctype.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #ifdef EX_OK 32 # undef EX_OK /* unistd.h may have another use for this */ 33 #endif /* EX_OK */ 34 #include <sysexits.h> 35 36 37 #ifndef NOT_SENDMAIL 38 # define NOT_SENDMAIL 39 #endif /* ! NOT_SENDMAIL */ 40 #include <sendmail/sendmail.h> 41 #include <sendmail/pathnames.h> 42 #include <libsmdb/smdb.h> 43 44 static void praliases __P((char *, int, char **)); 45 46 uid_t RealUid; 47 gid_t RealGid; 48 char *RealUserName; 49 uid_t RunAsUid; 50 uid_t RunAsGid; 51 char *RunAsUserName; 52 int Verbose = 2; 53 bool DontInitGroups = FALSE; 54 uid_t TrustedUid = 0; 55 BITMAP256 DontBlameSendmail; 56 57 extern void syserr __P((const char *, ...)); 58 59 # define DELIMITERS " ,/" 60 # define PATH_SEPARATOR ':' 61 62 int 63 main(argc, argv) 64 int argc; 65 char **argv; 66 { 67 char *cfile; 68 char *filename = NULL; 69 FILE *cfp; 70 int ch; 71 char afilebuf[MAXLINE]; 72 char buf[MAXLINE]; 73 struct passwd *pw; 74 static char rnamebuf[MAXNAME]; 75 extern char *optarg; 76 extern int optind; 77 78 79 clrbitmap(DontBlameSendmail); 80 RunAsUid = RealUid = getuid(); 81 RunAsGid = RealGid = getgid(); 82 pw = getpwuid(RealUid); 83 if (pw != NULL) 84 { 85 if (strlen(pw->pw_name) > MAXNAME - 1) 86 pw->pw_name[MAXNAME] = 0; 87 snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 88 } 89 else 90 (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 91 (int) RealUid); 92 RunAsUserName = RealUserName = rnamebuf; 93 94 cfile = _PATH_SENDMAILCF; 95 while ((ch = getopt(argc, argv, "C:f:")) != -1) 96 { 97 switch ((char)ch) { 98 case 'C': 99 cfile = optarg; 100 break; 101 case 'f': 102 filename = optarg; 103 break; 104 case '?': 105 default: 106 (void)fprintf(stderr, 107 "usage: praliases [-C cffile] [-f aliasfile]\n"); 108 exit(EX_USAGE); 109 } 110 } 111 argc -= optind; 112 argv += optind; 113 114 if (filename != NULL) 115 { 116 praliases(filename, argc, argv); 117 exit(EX_OK); 118 } 119 120 if ((cfp = fopen(cfile, "r")) == NULL) 121 { 122 fprintf(stderr, "praliases: %s: %s\n", 123 cfile, errstring(errno)); 124 exit(EX_NOINPUT); 125 } 126 127 while (fgets(buf, sizeof(buf), cfp) != NULL) 128 { 129 register char *b, *p; 130 131 b = strchr(buf, '\n'); 132 if (b != NULL) 133 *b = '\0'; 134 135 b = buf; 136 switch (*b++) 137 { 138 case 'O': /* option -- see if alias file */ 139 if (strncasecmp(b, " AliasFile", 10) == 0 && 140 !(isascii(b[10]) && isalnum(b[10]))) 141 { 142 /* new form -- find value */ 143 b = strchr(b, '='); 144 if (b == NULL) 145 continue; 146 while (isascii(*++b) && isspace(*b)) 147 continue; 148 } 149 else if (*b++ != 'A') 150 { 151 /* something else boring */ 152 continue; 153 } 154 155 /* this is the A or AliasFile option -- save it */ 156 if (strlcpy(afilebuf, b, sizeof afilebuf) >= 157 sizeof afilebuf) 158 { 159 fprintf(stderr, 160 "praliases: AliasFile filename too long: %.30s\n", 161 b); 162 (void) fclose(cfp); 163 exit(EX_CONFIG); 164 } 165 b = afilebuf; 166 167 for (p = b; p != NULL; ) 168 { 169 while (isascii(*p) && isspace(*p)) 170 p++; 171 if (*p == '\0') 172 break; 173 b = p; 174 175 p = strpbrk(p, DELIMITERS); 176 177 /* find end of spec */ 178 if (p != NULL) 179 { 180 bool quoted = FALSE; 181 182 for (; *p != '\0'; p++) 183 { 184 /* 185 ** Don't break into a quoted 186 ** string. 187 */ 188 189 if (*p == '"') 190 quoted = !quoted; 191 else if (*p == ',' && !quoted) 192 break; 193 } 194 195 /* No more alias specs follow */ 196 if (*p == '\0') 197 { 198 /* chop trailing whitespace */ 199 while (isascii(*p) && 200 isspace(*p) && 201 p > b) 202 p--; 203 *p = '\0'; 204 p = NULL; 205 } 206 } 207 208 if (p != NULL) 209 { 210 char *e = p - 1; 211 212 /* chop trailing whitespace */ 213 while (isascii(*e) && 214 isspace(*e) && 215 e > b) 216 e--; 217 *++e = '\0'; 218 *p++ = '\0'; 219 } 220 praliases(b, argc, argv); 221 } 222 223 default: 224 continue; 225 } 226 } 227 (void) fclose(cfp); 228 exit(EX_OK); 229 /* NOTREACHED */ 230 return EX_OK; 231 } 232 233 static void 234 praliases(filename, argc, argv) 235 char *filename; 236 int argc; 237 char **argv; 238 { 239 int result; 240 char *colon; 241 char *db_name; 242 char *db_type; 243 SMDB_DATABASE *database = NULL; 244 SMDB_CURSOR *cursor = NULL; 245 SMDB_DBENT db_key, db_value; 246 SMDB_DBPARAMS params; 247 SMDB_USER_INFO user_info; 248 249 colon = strchr(filename, PATH_SEPARATOR); 250 if (colon == NULL) 251 { 252 db_name = filename; 253 db_type = SMDB_TYPE_DEFAULT; 254 } 255 else 256 { 257 *colon = '\0'; 258 db_name = colon + 1; 259 db_type = filename; 260 } 261 262 /* clean off arguments */ 263 for (;;) 264 { 265 while (isascii(*db_name) && isspace(*db_name)) 266 db_name++; 267 268 if (*db_name != '-') 269 break; 270 while (*db_name != '\0' && 271 !(isascii(*db_name) && isspace(*db_name))) 272 db_name++; 273 } 274 275 /* Skip non-file based DB types */ 276 if (db_type != NULL && *db_type != '\0') 277 { 278 if (db_type != SMDB_TYPE_DEFAULT && 279 strcmp(db_type, "hash") != 0 && 280 strcmp(db_type, "btree") != 0 && 281 strcmp(db_type, "dbm") != 0) 282 { 283 fprintf(stderr, 284 "praliases: Skipping non-file based alias type %s\n", 285 db_type); 286 return; 287 } 288 } 289 290 if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) 291 { 292 if (colon != NULL) 293 *colon = ':'; 294 fprintf(stderr, "praliases: illegal alias specification: %s\n", 295 filename); 296 goto fatal; 297 } 298 299 memset(¶ms, '\0', sizeof params); 300 params.smdbp_cache_size = 1024 * 1024; 301 302 user_info.smdbu_id = RunAsUid; 303 user_info.smdbu_group_id = RunAsGid; 304 strlcpy(user_info.smdbu_name, RunAsUserName, SMDB_MAX_USER_NAME_LEN); 305 306 result = smdb_open_database(&database, db_name, O_RDONLY, 0, 307 SFF_ROOTOK, db_type, &user_info, ¶ms); 308 if (result != SMDBE_OK) 309 { 310 fprintf(stderr, "praliases: %s: open: %s\n", 311 db_name, 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 fprintf(stderr, "praliases: %s: set cursor: %s\n", 324 db_name, 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 printf("%.*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 fprintf(stderr, 353 "praliases: %s: get value at cursor: %s\n", 354 db_name, 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 printf("%.*s:%.*s\n", 376 (int) db_key.size, 377 (char *) db_key.data, 378 (int) db_value.size, 379 (char *) db_value.data); 380 } 381 else 382 printf("%s: No such key\n", (char *) db_key.data); 383 } 384 385 fatal: 386 if (cursor != NULL) 387 (void) cursor->smdbc_close(cursor); 388 if (database != NULL) 389 (void) database->smdb_close(database); 390 if (colon != NULL) 391 *colon = ':'; 392 return; 393 } 394 395 /*VARARGS1*/ 396 void 397 #ifdef __STDC__ 398 message(const char *msg, ...) 399 #else /* __STDC__ */ 400 message(msg, va_alist) 401 const char *msg; 402 va_dcl 403 #endif /* __STDC__ */ 404 { 405 const char *m; 406 VA_LOCAL_DECL 407 408 m = msg; 409 if (isascii(m[0]) && isdigit(m[0]) && 410 isascii(m[1]) && isdigit(m[1]) && 411 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 412 m += 4; 413 VA_START(msg); 414 (void) vfprintf(stderr, m, ap); 415 VA_END; 416 (void) fprintf(stderr, "\n"); 417 } 418 419 /*VARARGS1*/ 420 void 421 #ifdef __STDC__ 422 syserr(const char *msg, ...) 423 #else /* __STDC__ */ 424 syserr(msg, va_alist) 425 const char *msg; 426 va_dcl 427 #endif /* __STDC__ */ 428 { 429 const char *m; 430 VA_LOCAL_DECL 431 432 m = msg; 433 if (isascii(m[0]) && isdigit(m[0]) && 434 isascii(m[1]) && isdigit(m[1]) && 435 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 436 m += 4; 437 VA_START(msg); 438 (void) vfprintf(stderr, m, ap); 439 VA_END; 440 (void) fprintf(stderr, "\n"); 441 } 442