1 /* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1992 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1992, 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-2000 Sendmail, Inc. and its suppliers.\n\ 17 All rights reserved.\n\ 18 Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ 19 Copyright (c) 1992, 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: makemap.c,v 8.135.4.13 2000/10/05 23:00:50 gshapiro Exp $"; 25 #endif /* ! lint */ 26 27 /* $FreeBSD$ */ 28 29 #include <sys/types.h> 30 #ifndef ISC_UNIX 31 # include <sys/file.h> 32 #endif /* ! ISC_UNIX */ 33 #include <ctype.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #ifdef EX_OK 37 # undef EX_OK /* unistd.h may have another use for this */ 38 #endif /* EX_OK */ 39 #include <sysexits.h> 40 #include <sendmail/sendmail.h> 41 #include <sendmail/pathnames.h> 42 #include <libsmdb/smdb.h> 43 44 uid_t RealUid; 45 gid_t RealGid; 46 char *RealUserName; 47 uid_t RunAsUid; 48 uid_t RunAsGid; 49 char *RunAsUserName; 50 int Verbose = 2; 51 bool DontInitGroups = FALSE; 52 uid_t TrustedUid = 0; 53 BITMAP256 DontBlameSendmail; 54 55 #define BUFSIZE 1024 56 #if _FFR_DELIM 57 # define ISSEP(c) ((sep == '\0' && isascii(c) && isspace(c)) || (c) == sep) 58 #else /* _FFR_DELIM */ 59 # define ISSEP(c) (isascii(c) && isspace(c)) 60 #endif /* _FFR_DELIM */ 61 62 63 static void 64 usage(progname) 65 char *progname; 66 { 67 fprintf(stderr, 68 "Usage: %s [-C cffile] [-N] [-c cachesize] [-d] [-e] [-f] [-l] [-o] [-r] [-s] %s[-u] [-v] type mapname\n", 69 progname, 70 #if _FFR_DELIM 71 "[-t delimiter] " 72 #else /* _FFR_DELIM */ 73 "" 74 #endif /* _FFR_DELIM */ 75 ); 76 exit(EX_USAGE); 77 } 78 79 int 80 main(argc, argv) 81 int argc; 82 char **argv; 83 { 84 char *progname; 85 char *cfile; 86 bool inclnull = FALSE; 87 bool notrunc = FALSE; 88 bool allowreplace = FALSE; 89 bool allowempty = FALSE; 90 bool verbose = FALSE; 91 bool foldcase = TRUE; 92 bool unmake = FALSE; 93 #if _FFR_DELIM 94 char sep = '\0'; 95 #endif /* _FFR_DELIM */ 96 int exitstat; 97 int opt; 98 char *typename = NULL; 99 char *mapname = NULL; 100 int lineno; 101 int st; 102 int mode; 103 int smode; 104 int putflags = 0; 105 long sff = SFF_ROOTOK|SFF_REGONLY; 106 struct passwd *pw; 107 SMDB_DATABASE *database; 108 SMDB_CURSOR *cursor; 109 SMDB_DBENT db_key, db_val; 110 SMDB_DBPARAMS params; 111 SMDB_USER_INFO user_info; 112 char ibuf[BUFSIZE]; 113 #if HASFCHOWN 114 FILE *cfp; 115 char buf[MAXLINE]; 116 #endif /* HASFCHOWN */ 117 static char rnamebuf[MAXNAME]; /* holds RealUserName */ 118 extern char *optarg; 119 extern int optind; 120 121 memset(¶ms, '\0', sizeof params); 122 params.smdbp_cache_size = 1024 * 1024; 123 124 progname = strrchr(argv[0], '/'); 125 if (progname != NULL) 126 progname++; 127 else 128 progname = argv[0]; 129 cfile = _PATH_SENDMAILCF; 130 131 clrbitmap(DontBlameSendmail); 132 RunAsUid = RealUid = getuid(); 133 RunAsGid = RealGid = getgid(); 134 pw = getpwuid(RealUid); 135 if (pw != NULL) 136 (void) strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 137 else 138 (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 139 (int) RealUid); 140 RunAsUserName = RealUserName = rnamebuf; 141 user_info.smdbu_id = RunAsUid; 142 user_info.smdbu_group_id = RunAsGid; 143 (void) strlcpy(user_info.smdbu_name, RunAsUserName, 144 SMDB_MAX_USER_NAME_LEN); 145 146 147 #define OPTIONS "C:Nc:t:deflorsuv" 148 while ((opt = getopt(argc, argv, OPTIONS)) != -1) 149 { 150 switch (opt) 151 { 152 case 'C': 153 cfile = optarg; 154 break; 155 156 case 'N': 157 inclnull = TRUE; 158 break; 159 160 case 'c': 161 params.smdbp_cache_size = atol(optarg); 162 break; 163 164 case 'd': 165 params.smdbp_allow_dup = TRUE; 166 break; 167 168 case 'e': 169 allowempty = TRUE; 170 break; 171 172 case 'f': 173 foldcase = FALSE; 174 break; 175 176 case 'l': 177 smdb_print_available_types(); 178 exit(EX_OK); 179 break; 180 181 case 'o': 182 notrunc = TRUE; 183 break; 184 185 case 'r': 186 allowreplace = TRUE; 187 break; 188 189 case 's': 190 setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail); 191 setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail); 192 setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail); 193 setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail); 194 break; 195 196 #if _FFR_DELIM 197 case 't': 198 if (optarg == NULL || *optarg == '\0') 199 { 200 fprintf(stderr, "Invalid separator\n"); 201 break; 202 } 203 sep = *optarg; 204 break; 205 #endif /* _FFR_DELIM */ 206 207 case 'u': 208 unmake = TRUE; 209 break; 210 211 case 'v': 212 verbose = TRUE; 213 break; 214 215 default: 216 usage(progname); 217 /* NOTREACHED */ 218 } 219 } 220 221 if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 222 sff |= SFF_NOSLINK; 223 if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 224 sff |= SFF_NOHLINK; 225 if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 226 sff |= SFF_NOWLINK; 227 228 argc -= optind; 229 argv += optind; 230 if (argc != 2) 231 { 232 usage(progname); 233 /* NOTREACHED */ 234 } 235 else 236 { 237 typename = argv[0]; 238 mapname = argv[1]; 239 } 240 241 #if HASFCHOWN 242 /* Find TrustedUser value in sendmail.cf */ 243 if ((cfp = fopen(cfile, "r")) == NULL) 244 { 245 fprintf(stderr, "makemap: %s: %s", cfile, errstring(errno)); 246 exit(EX_NOINPUT); 247 } 248 while (fgets(buf, sizeof(buf), cfp) != NULL) 249 { 250 register char *b; 251 252 if ((b = strchr(buf, '\n')) != NULL) 253 *b = '\0'; 254 255 b = buf; 256 switch (*b++) 257 { 258 case 'O': /* option */ 259 if (strncasecmp(b, " TrustedUser", 12) == 0 && 260 !(isascii(b[12]) && isalnum(b[12]))) 261 { 262 b = strchr(b, '='); 263 if (b == NULL) 264 continue; 265 while (isascii(*++b) && isspace(*b)) 266 continue; 267 if (isascii(*b) && isdigit(*b)) 268 TrustedUid = atoi(b); 269 else 270 { 271 TrustedUid = 0; 272 pw = getpwnam(b); 273 if (pw == NULL) 274 fprintf(stderr, 275 "TrustedUser: unknown user %s\n", b); 276 else 277 TrustedUid = pw->pw_uid; 278 } 279 280 # ifdef UID_MAX 281 if (TrustedUid > UID_MAX) 282 { 283 fprintf(stderr, 284 "TrustedUser: uid value (%ld) > UID_MAX (%ld)", 285 (long) TrustedUid, 286 (long) UID_MAX); 287 TrustedUid = 0; 288 } 289 # endif /* UID_MAX */ 290 break; 291 } 292 293 294 default: 295 continue; 296 } 297 } 298 (void) fclose(cfp); 299 #endif /* HASFCHOWN */ 300 301 if (!params.smdbp_allow_dup && !allowreplace) 302 putflags = SMDBF_NO_OVERWRITE; 303 304 if (unmake) 305 { 306 mode = O_RDONLY; 307 smode = S_IRUSR; 308 } 309 else 310 { 311 mode = O_RDWR; 312 if (!notrunc) 313 { 314 mode |= O_CREAT|O_TRUNC; 315 sff |= SFF_CREAT; 316 } 317 smode = S_IWUSR; 318 } 319 320 params.smdbp_num_elements = 4096; 321 322 errno = smdb_open_database(&database, mapname, mode, smode, sff, 323 typename, &user_info, ¶ms); 324 if (errno != SMDBE_OK) 325 { 326 char *hint; 327 328 if (errno == SMDBE_UNSUPPORTED_DB_TYPE && 329 (hint = smdb_db_definition(typename)) != NULL) 330 fprintf(stderr, 331 "%s: Need to recompile with -D%s for %s support\n", 332 progname, hint, typename); 333 else 334 fprintf(stderr, 335 "%s: error opening type %s map %s: %s\n", 336 progname, typename, mapname, errstring(errno)); 337 exit(EX_CANTCREAT); 338 } 339 340 (void) database->smdb_sync(database, 0); 341 342 if (!unmake && geteuid() == 0 && TrustedUid != 0) 343 { 344 errno = database->smdb_set_owner(database, TrustedUid, -1); 345 if (errno != SMDBE_OK) 346 { 347 fprintf(stderr, 348 "WARNING: ownership change on %s failed %s", 349 mapname, errstring(errno)); 350 } 351 } 352 353 /* 354 ** Copy the data 355 */ 356 357 exitstat = EX_OK; 358 if (unmake) 359 { 360 errno = database->smdb_cursor(database, &cursor, 0); 361 if (errno != SMDBE_OK) 362 { 363 364 fprintf(stderr, 365 "%s: cannot make cursor for type %s map %s\n", 366 progname, typename, mapname); 367 exit(EX_SOFTWARE); 368 } 369 370 memset(&db_key, '\0', sizeof db_key); 371 memset(&db_val, '\0', sizeof db_val); 372 373 for (lineno = 0; ; lineno++) 374 { 375 errno = cursor->smdbc_get(cursor, &db_key, &db_val, 376 SMDB_CURSOR_GET_NEXT); 377 if (errno != SMDBE_OK) 378 break; 379 380 printf("%.*s\t%.*s\n", 381 (int) db_key.size, 382 (char *) db_key.data, 383 (int) db_val.size, 384 (char *)db_val.data); 385 386 } 387 (void) cursor->smdbc_close(cursor); 388 } 389 else 390 { 391 lineno = 0; 392 while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 393 { 394 register char *p; 395 396 lineno++; 397 398 /* 399 ** Parse the line. 400 */ 401 402 p = strchr(ibuf, '\n'); 403 if (p != NULL) 404 *p = '\0'; 405 else if (!feof(stdin)) 406 { 407 fprintf(stderr, 408 "%s: %s: line %d: line too long (%ld bytes max)\n", 409 progname, mapname, lineno, (long) sizeof ibuf); 410 exitstat = EX_DATAERR; 411 continue; 412 } 413 414 if (ibuf[0] == '\0' || ibuf[0] == '#') 415 continue; 416 if ( 417 #if _FFR_DELIM 418 sep == '\0' && 419 #endif /* _FFR_DELIM */ 420 isascii(ibuf[0]) && isspace(ibuf[0])) 421 { 422 fprintf(stderr, 423 "%s: %s: line %d: syntax error (leading space)\n", 424 progname, mapname, lineno); 425 exitstat = EX_DATAERR; 426 continue; 427 } 428 429 memset(&db_key, '\0', sizeof db_key); 430 memset(&db_val, '\0', sizeof db_val); 431 db_key.data = ibuf; 432 433 for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++) 434 { 435 if (foldcase && isascii(*p) && isupper(*p)) 436 *p = tolower(*p); 437 } 438 db_key.size = p - ibuf; 439 if (inclnull) 440 db_key.size++; 441 442 if (*p != '\0') 443 *p++ = '\0'; 444 while (ISSEP(*p)) 445 p++; 446 if (!allowempty && *p == '\0') 447 { 448 fprintf(stderr, 449 "%s: %s: line %d: no RHS for LHS %s\n", 450 progname, mapname, lineno, 451 (char *) db_key.data); 452 exitstat = EX_DATAERR; 453 continue; 454 } 455 456 db_val.data = p; 457 db_val.size = strlen(p); 458 if (inclnull) 459 db_val.size++; 460 461 /* 462 ** Do the database insert. 463 */ 464 465 if (verbose) 466 { 467 printf("key=`%s', val=`%s'\n", 468 (char *) db_key.data, 469 (char *) db_val.data); 470 } 471 472 errno = database->smdb_put(database, &db_key, &db_val, 473 putflags); 474 switch (errno) 475 { 476 case SMDBE_KEY_EXIST: 477 st = 1; 478 break; 479 480 case 0: 481 st = 0; 482 break; 483 484 default: 485 st = -1; 486 break; 487 } 488 489 if (st < 0) 490 { 491 fprintf(stderr, 492 "%s: %s: line %d: key %s: put error: %s\n", 493 progname, mapname, lineno, 494 (char *) db_key.data, 495 errstring(errno)); 496 exitstat = EX_IOERR; 497 } 498 else if (st > 0) 499 { 500 fprintf(stderr, 501 "%s: %s: line %d: key %s: duplicate key\n", 502 progname, mapname, 503 lineno, (char *) db_key.data); 504 exitstat = EX_DATAERR; 505 } 506 } 507 } 508 509 /* 510 ** Now close the database. 511 */ 512 513 errno = database->smdb_close(database); 514 if (errno != SMDBE_OK) 515 { 516 fprintf(stderr, "%s: close(%s): %s\n", 517 progname, mapname, errstring(errno)); 518 exitstat = EX_IOERR; 519 } 520 smdb_free_database(database); 521 522 exit(exitstat); 523 /* NOTREACHED */ 524 return exitstat; 525 } 526 527 /*VARARGS1*/ 528 void 529 #ifdef __STDC__ 530 message(const char *msg, ...) 531 #else /* __STDC__ */ 532 message(msg, va_alist) 533 const char *msg; 534 va_dcl 535 #endif /* __STDC__ */ 536 { 537 const char *m; 538 VA_LOCAL_DECL 539 540 m = msg; 541 if (isascii(m[0]) && isdigit(m[0]) && 542 isascii(m[1]) && isdigit(m[1]) && 543 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 544 m += 4; 545 VA_START(msg); 546 (void) vfprintf(stderr, m, ap); 547 VA_END; 548 (void) fprintf(stderr, "\n"); 549 } 550 551 /*VARARGS1*/ 552 void 553 #ifdef __STDC__ 554 syserr(const char *msg, ...) 555 #else /* __STDC__ */ 556 syserr(msg, va_alist) 557 const char *msg; 558 va_dcl 559 #endif /* __STDC__ */ 560 { 561 const char *m; 562 VA_LOCAL_DECL 563 564 m = msg; 565 if (isascii(m[0]) && isdigit(m[0]) && 566 isascii(m[1]) && isdigit(m[1]) && 567 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 568 m += 4; 569 VA_START(msg); 570 (void) vfprintf(stderr, m, ap); 571 VA_END; 572 (void) fprintf(stderr, "\n"); 573 } 574