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