int main(int argc, char **cargv) { int dbdata_type; uschar **argv = USS cargv; uschar buffer[256]; uschar name[256]; void *reset_point = store_get(0); name[0] = 0; /* No name set */ /* Sort out the database type, verify what we are working on and then process user requests */ dbdata_type = check_args(argc, argv, US"fixdb", US""); printf("Modifying Exim hints database %s/db/%s\n", argv[1], argv[2]); for(;;) { open_db dbblock; open_db *dbm; void *record; dbdata_retry *retry; dbdata_wait *wait; dbdata_callout_cache *callout; dbdata_ratelimit *ratelimit; int i, oldlength; uschar *t; uschar field[256], value[256]; store_reset(reset_point); printf("> "); if (Ufgets(buffer, 256, stdin) == NULL) break; buffer[Ustrlen(buffer)-1] = 0; field[0] = value[0] = 0; /* If the buffer contains just one digit, or just consists of "d", use the previous name for an update. */ if ((isdigit((uschar)buffer[0]) && (buffer[1] == ' ' || buffer[1] == '\0')) || Ustrcmp(buffer, "d") == 0) { if (name[0] == 0) { printf("No previous record name is set\n"); continue; } (void)sscanf(CS buffer, "%s %s", field, value); } else { name[0] = 0; (void)sscanf(CS buffer, "%s %s %s", name, field, value); } /* Handle an update request */ if (field[0] != 0) { int verify = 1; dbm = dbfn_open(argv[1], argv[2], O_RDWR, &dbblock); if (dbm == NULL) continue; if (Ustrcmp(field, "d") == 0) { if (value[0] != 0) printf("unexpected value after \"d\"\n"); else printf("%s\n", (dbfn_delete(dbm, name) < 0)? "not found" : "deleted"); dbfn_close(dbm); continue; } else if (isdigit((uschar)field[0])) { int fieldno = Uatoi(field); if (value[0] == 0) { printf("value missing\n"); dbfn_close(dbm); continue; } else { record = dbfn_read_with_length(dbm, name, &oldlength); if (record == NULL) printf("not found\n"); else { time_t tt; int length = 0; /* Stops compiler warning */ switch(dbdata_type) { case type_retry: retry = (dbdata_retry *)record; length = sizeof(dbdata_retry) + Ustrlen(retry->text); switch(fieldno) { case 0: retry->basic_errno = Uatoi(value); break; case 1: retry->more_errno = Uatoi(value); break; case 2: if ((tt = read_time(value)) > 0) retry->first_failed = tt; else printf("bad time value\n"); break; case 3: if ((tt = read_time(value)) > 0) retry->last_try = tt; else printf("bad time value\n"); break; case 4: if ((tt = read_time(value)) > 0) retry->next_try = tt; else printf("bad time value\n"); break; case 5: if (Ustrcmp(value, "yes") == 0) retry->expired = TRUE; else if (Ustrcmp(value, "no") == 0) retry->expired = FALSE; else printf("\"yes\" or \"no\" expected=n"); break; default: printf("unknown field number\n"); verify = 0; break; } break; case type_wait: printf("Can't change contents of wait database record\n"); break; case type_misc: printf("Can't change contents of misc database record\n"); break; case type_callout: callout = (dbdata_callout_cache *)record; length = sizeof(dbdata_callout_cache); switch(fieldno) { case 0: callout->result = Uatoi(value); break; case 1: callout->postmaster_result = Uatoi(value); break; case 2: callout->random_result = Uatoi(value); break; default: printf("unknown field number\n"); verify = 0; break; } break; case type_ratelimit: ratelimit = (dbdata_ratelimit *)record; length = sizeof(dbdata_ratelimit); switch(fieldno) { case 0: if ((tt = read_time(value)) > 0) ratelimit->time_stamp = tt; else printf("bad time value\n"); break; case 1: ratelimit->time_usec = Uatoi(value); break; case 2: ratelimit->rate = Ustrtod(value, NULL); break; default: printf("unknown field number\n"); verify = 0; break; } break; } dbfn_write(dbm, name, record, length); } } } else { printf("field number or d expected\n"); verify = 0; } dbfn_close(dbm); if (!verify) continue; } /* The "name" q causes an exit */ else if (Ustrcmp(name, "q") == 0) return 0; /* Handle a read request, or verify after an update. */ dbm = dbfn_open(argv[1], argv[2], O_RDONLY, &dbblock); if (dbm == NULL) continue; record = dbfn_read_with_length(dbm, name, &oldlength); if (record == NULL) { printf("record %s not found\n", name); name[0] = 0; } else { int count_bad = 0; printf("%s\n", CS print_time(((dbdata_generic *)record)->time_stamp)); switch(dbdata_type) { case type_retry: retry = (dbdata_retry *)record; printf("0 error number: %d %s\n", retry->basic_errno, retry->text); printf("1 extra data: %d\n", retry->more_errno); printf("2 first failed: %s\n", print_time(retry->first_failed)); printf("3 last try: %s\n", print_time(retry->last_try)); printf("4 next try: %s\n", print_time(retry->next_try)); printf("5 expired: %s\n", (retry->expired)? "yes" : "no"); break; case type_wait: wait = (dbdata_wait *)record; t = wait->text; printf("Sequence: %d\n", wait->sequence); if (wait->count > WAIT_NAME_MAX) { printf("**** Data corrupted: count=%d=0x%x max=%d ****\n", wait->count, wait->count, WAIT_NAME_MAX); wait->count = WAIT_NAME_MAX; count_bad = 1; } for (i = 1; i <= wait->count; i++) { Ustrncpy(value, t, MESSAGE_ID_LENGTH); value[MESSAGE_ID_LENGTH] = 0; if (count_bad && value[0] == 0) break; if (Ustrlen(value) != MESSAGE_ID_LENGTH || Ustrspn(value, "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ-") != MESSAGE_ID_LENGTH) { int j; printf("\n**** Data corrupted: bad character in message id ****\n"); for (j = 0; j < MESSAGE_ID_LENGTH; j++) printf("%02x ", value[j]); printf("\n"); break; } printf("%s ", value); t += MESSAGE_ID_LENGTH; } printf("\n"); break; case type_misc: break; case type_callout: callout = (dbdata_callout_cache *)record; printf("0 callout: %s (%d)\n", print_cache(callout->result), callout->result); if (oldlength > sizeof(dbdata_callout_cache_address)) { printf("1 postmaster: %s (%d)\n", print_cache(callout->postmaster_result), callout->postmaster_result); printf("2 random: %s (%d)\n", print_cache(callout->random_result), callout->random_result); } break; case type_ratelimit: ratelimit = (dbdata_ratelimit *)record; printf("0 time stamp: %s\n", print_time(ratelimit->time_stamp)); printf("1 fract. time: .%06d\n", ratelimit->time_usec); printf("2 sender rate: % .3f\n", ratelimit->rate); break; } } /* The database is closed after each request */ dbfn_close(dbm); } printf("\n"); return 0; }
void pipe_transport_init(transport_instance *tblock) { pipe_transport_options_block *ob = (pipe_transport_options_block *)(tblock->options_block); /* Set up the setup entry point, to be called in the privileged state */ tblock->setup = pipe_transport_setup; /* If pipe_as_creator is set, then uid/gid should not be set. */ if (tblock->deliver_as_creator && (tblock->uid_set || tblock->gid_set || tblock->expand_uid != NULL || tblock->expand_gid != NULL)) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "both pipe_as_creator and an explicit uid/gid are set for the %s " "transport", tblock->name); /* If a fixed uid field is set, then a gid field must also be set. */ if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "user set without group for the %s transport", tblock->name); /* Temp_errors must consist only of digits and colons, but there can be spaces round the colons, so allow them too. */ if (ob->temp_errors != NULL && Ustrcmp(ob->temp_errors, "*") != 0) { size_t p = Ustrspn(ob->temp_errors, "0123456789: "); if (ob->temp_errors[p] != 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "temp_errors must be a list of numbers or an asterisk for the %s " "transport", tblock->name); } /* Only one of return_output/return_fail_output or log_output/log_fail_output should be set. */ if (tblock->return_output && tblock->return_fail_output) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "both return_output and return_fail_output set for %s transport", tblock->name); if (tblock->log_output && tblock->log_fail_output) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "both log_output and log_fail_output set for the %s transport", tblock->name); /* If batch SMTP is set, force the check and escape strings, and arrange that headers are also escaped. */ if (ob->use_bsmtp) { ob->check_string = US"."; ob->escape_string = US".."; ob->options |= topt_escape_headers; } /* If not batch SMTP, and message_prefix or message_suffix are unset, insert default values for them. */ else { if (ob->message_prefix == NULL) ob->message_prefix = US"From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n"; if (ob->message_suffix == NULL) ob->message_suffix = US"\n"; } /* The restrict_to_path and use_shell options are incompatible */ if (ob->restrict_to_path && ob->use_shell) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "both restrict_to_path and use_shell set for %s transport", tblock->name); /* The allow_commands and use_shell options are incompatible */ if (ob->allow_commands && ob->use_shell) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "both allow_commands and use_shell set for %s transport", tblock->name); /* Set up the bitwise options for transport_write_message from the various driver options. Only one of body_only and headers_only can be set. */ ob->options |= (tblock->body_only? topt_no_headers : 0) | (tblock->headers_only? topt_no_body : 0) | (tblock->return_path_add? topt_add_return_path : 0) | (tblock->delivery_date_add? topt_add_delivery_date : 0) | (tblock->envelope_to_add? topt_add_envelope_to : 0) | (ob->use_crlf? topt_use_crlf : 0); }
int main(int argc, char **cargv) { int dbdata_type = 0; int yield = 0; open_db dbblock; open_db *dbm; EXIM_CURSOR *cursor; uschar **argv = USS cargv; uschar *key; uschar keybuffer[1024]; /* Check the arguments, and open the database */ dbdata_type = check_args(argc, argv, US"dumpdb", US""); dbm = dbfn_open(argv[1], argv[2], O_RDONLY, &dbblock); if (dbm == NULL) exit(1); /* Scan the file, formatting the information for each entry. Note that data is returned in a malloc'ed block, in order that it be correctly aligned. */ key = dbfn_scan(dbm, TRUE, &cursor); while (key != NULL) { dbdata_retry *retry; dbdata_wait *wait; dbdata_callout_cache *callout; dbdata_ratelimit *ratelimit; int count_bad = 0; int i, length; uschar *t; uschar name[MESSAGE_ID_LENGTH + 1]; void *value; /* Keep a copy of the key separate, as in some DBM's the pointer is into data which might change. */ if (Ustrlen(key) > sizeof(keybuffer) - 1) { printf("**** Overlong key encountered: %s\n", key); return 1; } Ustrcpy(keybuffer, key); value = dbfn_read_with_length(dbm, keybuffer, &length); if (value == NULL) fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record " "was not found in the file - something is wrong!\n", CS keybuffer); else { /* Note: don't use print_time more than once in one statement, since it uses a single buffer. */ switch(dbdata_type) { case type_retry: retry = (dbdata_retry *)value; printf(" %s %d %d %s\n%s ", keybuffer, retry->basic_errno, retry->more_errno, retry->text, print_time(retry->first_failed)); printf("%s ", print_time(retry->last_try)); printf("%s %s\n", print_time(retry->next_try), (retry->expired)? "*" : ""); break; case type_wait: wait = (dbdata_wait *)value; printf("%s ", keybuffer); t = wait->text; name[MESSAGE_ID_LENGTH] = 0; if (wait->count > WAIT_NAME_MAX) { fprintf(stderr, "**** Data for %s corrupted\n count=%d=0x%x max=%d\n", CS keybuffer, wait->count, wait->count, WAIT_NAME_MAX); wait->count = WAIT_NAME_MAX; yield = count_bad = 1; } for (i = 1; i <= wait->count; i++) { Ustrncpy(name, t, MESSAGE_ID_LENGTH); if (count_bad && name[0] == 0) break; if (Ustrlen(name) != MESSAGE_ID_LENGTH || Ustrspn(name, "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ-") != MESSAGE_ID_LENGTH) { int j; fprintf(stderr, "**** Data for %s corrupted: bad character in message id\n", CS keybuffer); for (j = 0; j < MESSAGE_ID_LENGTH; j++) fprintf(stderr, "%02x ", name[j]); fprintf(stderr, "\n"); yield = 1; break; } printf("%s ", name); t += MESSAGE_ID_LENGTH; } printf("\n"); break; case type_misc: printf("%s %s\n", print_time(((dbdata_generic *)value)->time_stamp), keybuffer); break; case type_callout: callout = (dbdata_callout_cache *)value; /* New-style address record */ if (length == sizeof(dbdata_callout_cache_address)) { printf("%s %s callout=%s\n", print_time(((dbdata_generic *)value)->time_stamp), keybuffer, print_cache(callout->result)); } /* New-style domain record */ else if (length == sizeof(dbdata_callout_cache)) { printf("%s %s callout=%s postmaster=%s", print_time(((dbdata_generic *)value)->time_stamp), keybuffer, print_cache(callout->result), print_cache(callout->postmaster_result)); if (callout->postmaster_result != ccache_unknown) printf(" (%s)", print_time(callout->postmaster_stamp)); printf(" random=%s", print_cache(callout->random_result)); if (callout->random_result != ccache_unknown) printf(" (%s)", print_time(callout->random_stamp)); printf("\n"); } /* Old-style domain record, without separate timestamps. This code can eventually be thrown away, say in 5 years' time (it's now Feb 2003). */ else { printf("%s %s callout=%s postmaster=%s random=%s\n", print_time(((dbdata_generic *)value)->time_stamp), keybuffer, print_cache(callout->result), print_cache(callout->postmaster_result), print_cache(callout->random_result)); } break; case type_ratelimit: ratelimit = (dbdata_ratelimit *)value; printf("%s.%06d rate: %10.3f key: %s\n", print_time(ratelimit->time_stamp), ratelimit->time_usec, ratelimit->rate, keybuffer); break; } store_reset(value); } key = dbfn_scan(dbm, FALSE, &cursor); } dbfn_close(dbm); return yield; }