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.11 2000/09/13 01:11:10 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 bool stop; 361 errno = database->smdb_cursor(database, &cursor, 0); 362 if (errno != SMDBE_OK) 363 { 364 365 fprintf(stderr, 366 "%s: cannot make cursor for type %s map %s\n", 367 progname, typename, mapname); 368 exit(EX_SOFTWARE); 369 } 370 371 memset(&db_key, '\0', sizeof db_key); 372 memset(&db_val, '\0', sizeof db_val); 373 374 for (stop = FALSE, lineno = 0; !stop; lineno++) 375 { 376 errno = cursor->smdbc_get(cursor, &db_key, &db_val, 377 SMDB_CURSOR_GET_NEXT); 378 if (errno != SMDBE_OK) 379 { 380 stop = TRUE; 381 } 382 if (!stop) 383 printf("%.*s\t%.*s\n", 384 (int) db_key.data.size, 385 (char *) db_key.data.data, 386 (int) db_val.data.size, 387 (char *)db_val.data.data); 388 389 } 390 (void) cursor->smdbc_close(cursor); 391 } 392 else 393 { 394 lineno = 0; 395 while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 396 { 397 register char *p; 398 399 lineno++; 400 401 /* 402 ** Parse the line. 403 */ 404 405 p = strchr(ibuf, '\n'); 406 if (p != NULL) 407 *p = '\0'; 408 else if (!feof(stdin)) 409 { 410 fprintf(stderr, 411 "%s: %s: line %d: line too long (%ld bytes max)\n", 412 progname, mapname, lineno, (long) sizeof ibuf); 413 exitstat = EX_DATAERR; 414 continue; 415 } 416 417 if (ibuf[0] == '\0' || ibuf[0] == '#') 418 continue; 419 if ( 420 #if _FFR_DELIM 421 sep == '\0' && 422 #endif /* _FFR_DELIM */ 423 isascii(ibuf[0]) && isspace(ibuf[0])) 424 { 425 fprintf(stderr, 426 "%s: %s: line %d: syntax error (leading space)\n", 427 progname, mapname, lineno); 428 exitstat = EX_DATAERR; 429 continue; 430 } 431 432 memset(&db_key, '\0', sizeof db_key); 433 memset(&db_val, '\0', sizeof db_val); 434 db_key.data.data = ibuf; 435 436 for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++) 437 { 438 if (foldcase && isascii(*p) && isupper(*p)) 439 *p = tolower(*p); 440 } 441 db_key.data.size = p - ibuf; 442 if (inclnull) 443 db_key.data.size++; 444 445 if (*p != '\0') 446 *p++ = '\0'; 447 while (ISSEP(*p)) 448 p++; 449 if (!allowempty && *p == '\0') 450 { 451 fprintf(stderr, 452 "%s: %s: line %d: no RHS for LHS %s\n", 453 progname, mapname, lineno, 454 (char *) db_key.data.data); 455 exitstat = EX_DATAERR; 456 continue; 457 } 458 459 db_val.data.data = p; 460 db_val.data.size = strlen(p); 461 if (inclnull) 462 db_val.data.size++; 463 464 /* 465 ** Do the database insert. 466 */ 467 468 if (verbose) 469 { 470 printf("key=`%s', val=`%s'\n", 471 (char *) db_key.data.data, 472 (char *) db_val.data.data); 473 } 474 475 errno = database->smdb_put(database, &db_key, &db_val, 476 putflags); 477 switch (errno) 478 { 479 case SMDBE_KEY_EXIST: 480 st = 1; 481 break; 482 483 case 0: 484 st = 0; 485 break; 486 487 default: 488 st = -1; 489 break; 490 } 491 492 if (st < 0) 493 { 494 fprintf(stderr, 495 "%s: %s: line %d: key %s: put error: %s\n", 496 progname, mapname, lineno, 497 (char *) db_key.data.data, 498 errstring(errno)); 499 exitstat = EX_IOERR; 500 } 501 else if (st > 0) 502 { 503 fprintf(stderr, 504 "%s: %s: line %d: key %s: duplicate key\n", 505 progname, mapname, 506 lineno, (char *) db_key.data.data); 507 exitstat = EX_DATAERR; 508 } 509 } 510 } 511 512 /* 513 ** Now close the database. 514 */ 515 516 errno = database->smdb_close(database); 517 if (errno != SMDBE_OK) 518 { 519 fprintf(stderr, "%s: close(%s): %s\n", 520 progname, mapname, errstring(errno)); 521 exitstat = EX_IOERR; 522 } 523 smdb_free_database(database); 524 525 exit(exitstat); 526 /* NOTREACHED */ 527 return exitstat; 528 } 529 530 /*VARARGS1*/ 531 void 532 #ifdef __STDC__ 533 message(const char *msg, ...) 534 #else /* __STDC__ */ 535 message(msg, va_alist) 536 const char *msg; 537 va_dcl 538 #endif /* __STDC__ */ 539 { 540 const char *m; 541 VA_LOCAL_DECL 542 543 m = msg; 544 if (isascii(m[0]) && isdigit(m[0]) && 545 isascii(m[1]) && isdigit(m[1]) && 546 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 547 m += 4; 548 VA_START(msg); 549 (void) vfprintf(stderr, m, ap); 550 VA_END; 551 (void) fprintf(stderr, "\n"); 552 } 553 554 /*VARARGS1*/ 555 void 556 #ifdef __STDC__ 557 syserr(const char *msg, ...) 558 #else /* __STDC__ */ 559 syserr(msg, va_alist) 560 const char *msg; 561 va_dcl 562 #endif /* __STDC__ */ 563 { 564 const char *m; 565 VA_LOCAL_DECL 566 567 m = msg; 568 if (isascii(m[0]) && isdigit(m[0]) && 569 isascii(m[1]) && isdigit(m[1]) && 570 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 571 m += 4; 572 VA_START(msg); 573 (void) vfprintf(stderr, m, ap); 574 VA_END; 575 (void) fprintf(stderr, "\n"); 576 } 577