/*
* $Id: notify.c,v 1.22 2002/10/17 20:25:56 ljb Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include <unistd.h>
#include <time.h>
#include <irr_notify.h>
#include <pgp.h>
extern char *test_addr;
/* '\0' terminated set of email addrs.
* Theses addrs are used to notify users
* that authorised changes have occured
* to their objects.
*/
char notify_addrs[MAX_ADDR_SIZE];
char *nnext;
int nndx[MAX_NDX_SIZE];
int num_notify;
/* '\0' terminated set of email addrs.
* These addrs are used to notify users of
* unauthorised updates.
*/
char forward_addrs[MAX_ADDR_SIZE];
char *fnext;
int fndx[MAX_NDX_SIZE];
int num_forward;
/* For uniform treatment, even though
* there is only one sender, make it
* like a forward_addr or notify_addr case
*/
char sender_addrs[MAX_ADDR_SIZE];
char *snext;
int sndx[1];
int num_sender;
char buf[MAXLINE];
/* local yokel's */
static void perform_rpsdist_trans (trace_t *, FILE *, ret_info_t *,
int, char *, long, char *IRRd_HOST,
int IRRd_PORT, char *dbpdir);
static void perform_transactions (trace_t *, FILE *, ret_info_t *, int,
char *, int, char *);
/* static void perform_transactions_new (trace_t *, FILE *, ret_info_t *, int,
char *, int, char *); */
static void remove_tempfiles (trace_t *);
static FILE *rpsdist_fopen (char *);
static char *send_rps_dist_trans (trace_t *, FILE *, ret_info_t *, char *,
char *, long, char *, int);
static char *init_jentries (trace_t *, char *, long, char *, FILE *);
static char *init_irrd_updates (trace_t *, FILE *, FILE *, ret_info_t *, char *);
static char *init_pgp_updates (trace_t *, FILE *, ret_info_t *, char *, int *);
static long get_irrd_cs (trace_t *, char *, char *, int);
static void pgp_files_backout (char *);
static char *rpsdist_timestamp (char *);
/* Control the action of performing the udpates and sending
* out notifications. Briefly, for auth failures all referenced
* upd_to: fields will be notified. For error-free updates (ie,
* no syntax and no auth errors) notifications will be sent to
* all referenced notify: and mnt_nfy: field addresses. The
* sender is always notified unless the '-x' command line flag is set
* (see below).
*
* notify () will send the updates to IRRd. If IRRd encounters
* an error and/or cannot apply the update the IRRd error message
* will be relayed in the notification.
*
* 'null_notification' = 1 causes notify () to skip
* all notifications. In this case, notify () will send the
* updates to IRRd but no notifications will be sent. '*tmpfname'
* is the file template for 'mkstemp ()' to use to build
* the notification files. There will be one notification file
* per unique notify/updto email address.
*
* 'null_submission' means the user sent in an empty submission.
* For an email submission all we have is the email header and an
* empty body. For a TCP submission all we have is an empty body
* and a return IP address. Note that 'null_submission' would
* have been better name 'non_null_lines' since 'null_submission'
* equal to 0 means we have a NULL submission.
*
* Return:
* void
* Results of the updates are included in the notifications.
*/
void notify (trace_t *tr, char *tmpfname, FILE *fin,
int null_submission, int null_notification, int dump_stdout,
char *web_origin_str, int rps_dist_flag, char *IRRd_HOST, int IRRd_PORT,
char *db_admin, char *pgpdir, char *dbdir, char *tlogfn,
long tlog_fpos, FILE *ack_fd, char * from_ip) {
ret_info_t rstart;
trans_info_t trans_info;
char buf[MAXLINE];
irrd_result_t *p;
long offset = 0;
char pbuf[256];
/*fprintf (dfile, "Enter notify()\n");*/
rstart.first = rstart.last = NULL;
if (rps_dist_flag)
perform_rpsdist_trans (tr, fin, &rstart, null_submission,
tlogfn, tlog_fpos, IRRd_HOST, IRRd_PORT, dbdir);
else
perform_transactions (tr, fin, &rstart, null_submission,
IRRd_HOST, IRRd_PORT, pgpdir);
/* JW want to go to this when we make irr_submit/IRRd transaction compliant
perform_transactions_new (tr, fin, &rstart, null_submission,
IRRd_HOST, IRRd_PORT, pgpdir);
*/
p = rstart.first;
/* just to be safe rewind */
if (fseek (fin, 0L, SEEK_SET) != 0) {
fprintf (stderr, "ERROR: cannot rewind input file, exit!\n");
exit (0);
}
/* init global data structures */
nnext = notify_addrs;
fnext = forward_addrs;
snext = sender_addrs;
num_notify = num_forward = num_sender = 0;
/* pointer to array of file names and handles to
* notify/forward mail replies.
*/
num_hdls = 0;
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
if (strncmp (HDR_START, buf, strlen (HDR_START) - 1))
continue;
/* fprintf (dfile, "found a start header %s strlen-(%d)\n", buf, strlen (buf));*/
if (parse_header (tr, fin, &offset, &trans_info))
break; /* illegal hdr field found or EOF
* (ie, no object after hdr)
*/
/* Make sure sender is not getting duplicate notifications */
if (trans_info.hdr_fields & FROM_F)
remove_sender (trans_info.sender_addrs, trans_info.notify_addrs,
&(trans_info.nnext));
else if (dump_stdout) { /* We have a tcp user, ie, an IRRj user */
trans_info.hdr_fields |= FROM_F;
if(from_ip == NULL)
from_ip = "localhost";
sprintf(pbuf,"TCP(%s)", from_ip);
strcpy (trans_info.sender_addrs, pbuf);
trans_info.snext += strlen (trans_info.sender_addrs) + 1;
}
trans_info.web_origin_str = web_origin_str;
if (web_origin_str != NULL) {
sprintf(pbuf,"%s Route Registry Update", trans_info.source ? trans_info.source : "");
trans_info.subject = strdup (pbuf);
}
/* JW this is for debug only */
/* print_hdr_struct (dfile, &trans_info); */
chk_email_fields (&trans_info);
if (!(trans_info.hdr_fields & OP_F))
trans_info.op = strdup ("UPDATE");
if (!(trans_info.hdr_fields & OBJ_KEY_F))
trans_info.obj_key = strdup ("");
if (!(trans_info.hdr_fields & OBJ_TYPE_F))
trans_info.obj_type = strdup ("");
if (chk_hdr_flds (trans_info.hdr_fields)) {
build_notify_responses (tr, tmpfname, fin, &trans_info, p, db_admin,
MAX_IRRD_OBJ_SIZE, null_notification);
if ((trans_info.hdr_fields & OLD_OBJ_FILE_F) &&
(*trans_info.old_obj_fname < '0' || *trans_info.old_obj_fname > '9'))
unlink (trans_info.old_obj_fname);
}
/*else
fprintf (dfile, "nofify () bad hdr file found, skipping...\n");*/
free_ti_mem (&trans_info);
p = p->next;
}
send_notifies (tr, null_notification, ack_fd, dump_stdout);
remove_tempfiles (tr);
/*fprintf (dfile, "Exit notify ()\n");*/
}
/* Close and remove all the notification temp files.
*
* Return:
* void
*/
void remove_tempfiles (trace_t *tr) {
int i;
for (i = 0; i < num_hdls; i++) {
fclose (msg_hdl[i].fp);
remove (msg_hdl[i].fname);
}
}
/* Move to this function in phase transition 2 when we convert
* irr_submit/irrd to transaction
*
* 'submission_count_lines' is a count of the non-null lines
* in the submission. Equal to 0 means the user supplied an
* empty submission.
*
* Return:
*
*/
void perform_transactions_new (trace_t *tr, FILE *fin, ret_info_t *start,
int submission_count_lines,
char *IRRd_HOST, int IRRd_PORT, char *pgpdir) {
int all_noop;
char *ret_code;
irrd_result_t *p;
/* rewind */
fseek (fin, 0L, SEEK_SET);
/* JW:!!!!: Need to have pick_off_header_info () check for all NOOP's
* want to avoid sending a transaction in which all objects are NOOP's
*/
/* Loop through the submission file, initializing the 'ti'
* struct with the header info and added to the linked list of 'ti's
* pointed to by 'start'. If any errors (user or server)
* are encountered then abort the transaction.
*/
if (pick_off_header_info (tr, fin, submission_count_lines, start, &all_noop)) {
trace (NORM, tr, "Submission error(s) found. Abort transaction.\n");
/* We are aborting the transaction. So set the proper
* user return information to let the user know that the objects
* with no errors are being skipped because of transaction
* semantics.
*/
reinit_return_list (tr, start, SKIP_RESULT);
}
else if (submission_count_lines == 0)
trace (ERROR, tr, "NULL submission.\n");
/* if all the obj's in the trans are NOOP's then don't send to irrd/rps-dist */
else if (!all_noop) {
trace (NORM, tr, "calling irrd_trans ().\n");
/* Send the transaction to rps dist to be added to the DB */
ret_code = irrd_transaction_new (tr, (char *) WARN_TAG, fin, start,
IRRd_HOST, IRRd_PORT);
trace (NORM, tr, "return from irrd_trans ().\n");
/* Remove any key certificate files from our temp directory area */
for (p = start->first; p != NULL; p = p->next) {
/* check for no IRRd errors and we have a key-cert object */
if (!put_transaction_code_new (tr, p, ret_code) &&
is_keycert_obj (p))
update_pgp_ring_new (tr, p, pgpdir);
if (p->keycertfn != NULL)
remove (p->keycertfn);
}
}
trace (NORM, tr, "exit perform_transactions_new ().\n");
}
/*
*
* 'submission_count_lines' is a count of the non-null lines
* in the submission. Equal to 0 means the user supplied an
* empty submission.
*
* Return:
*
*/
void perform_rpsdist_trans (trace_t *tr, FILE *fin, ret_info_t *start,
int submission_count_lines, char *tlogfn,
long tlog_fpos, char *IRRd_HOST, int IRRd_PORT,
char *dbdir) {
int all_noop;
char *ret_code;
irrd_result_t *p;
/* rewind */
fseek (fin, 0L, SEEK_SET);
/* JW:!!!!: need a check to make sure all the sources are consistent,
* ie, cannot accept a transaction that spans multiple source DB's
*/
/* Loop through the submission file, initializing the 'ti'
* struct with the header info and added to the linked list of 'ti's
* pointed to by 'start'. If any errors (user or server)
* are encountered then abort the transaction.
*/
if (pick_off_header_info (tr, fin, submission_count_lines, start, &all_noop)) {
trace (NORM, tr, "Submission error(s) found. Abort transaction.\n");
/* We are aborting the transaction. So set the proper
* user return information to let the user know that the objects
* with no errors are being skipped because of transaction
* semantics.
*/
reinit_return_list (tr, start, SKIP_RESULT);
}
else if (submission_count_lines == 0)
trace (NORM, tr, "Empty submission.\n");
/* if all the obj's in the trans are NOOP's then don't send to irrd/rps-dist */
else if (!all_noop) {
/* send the transaction to RPS-DIST */
ret_code = send_rps_dist_trans (tr, fin, start, dbdir, tlogfn, tlog_fpos,
IRRd_HOST, IRRd_PORT);
if (ret_code == NULL)
trace (NORM, tr, "perform_rpsdist_trans (): back from send_rps_dist_trans (), good trans!\n");
else
trace (NORM, tr, "perform_rpsdist_trans (): back from send_rps_dist_trans () bad trans (%s)\n", ret_code);
/* Place the irrd result in our linked list for notifications */
for (p = start->first; p != NULL; p = p->next) {
if (!(p->svr_res & NOOP_RESULT))
put_transaction_code_new (tr, p, ret_code);
/* remove any inital PGP public key files */
if (p->keycertfn != NULL)
remove (p->keycertfn);
}
}
trace (NORM, tr, "exit perform_rpsdist_trans ()\n");
return;
}
/* Build the communication files and send the names to RPS-DIST. Routine
* expects that there are no errors in the transaction (auth, syntax, ...)
* and that there is at least one valid update to be committed by IRRd
* (ie, not a file of all NOOP's or an empty submission).
*
* Input:
* -the canonicalized object file (prepended with pipeline headers) (fin)
* -pointer to the 'source' DB for this transaction (start)
* -pointer to the absolute directory path of the DB cache. This is where
* the RPS-DIST communication files will go (dbdir)
* -name of the bcc transaction log (tlogfn)
* -starting file position within the transaction log of this transaction.
* The user's original entry is needed to build the journal entry for
* RPS-DIST (tlog_fpos)
* -IRRd host. Might be needed to contact IRRd to determine trans
* outcome (IRRd_HOST)
* -IRRd port. Might be needed to contact IRRd to determine trans
* outcome (IRRd_PORT)
*
* Return:
* -NULL to indicate the transaction was successfully committed by IRRd
* -A text message indicating a transaction error occured and was rolled
* back. Also is possible transaction outcome can not be determined if
* RPS-DIST times out and IRRd cannot be contacted.
*/
char *send_rps_dist_trans (trace_t *tr, FILE *fin, ret_info_t *start,
char *dbdir, char *tlogfn, long tlog_fpos,
char *IRRd_HOST, int IRRd_PORT) {
int pgp_updates_count;
char *ret_code;
char template_n [1024], irrd_n[1024], pgp_n[1024], journal_n[1024];
FILE *irrd_f = NULL, *pgp_f = NULL, *journal_f = NULL;
/* sanity check */
if (dbdir == NULL) {
trace (ERROR, tr, "send_rps_dist_trans () Unspecified DB cache. Abort rps_dist transaction!\n");
return "SERVER ERROR: Unspecified DB cache. Please set the 'irr_directory' in your irrd.conf file";
}
/* create the irrd, pgp and journal files */
sprintf (template_n, "%s/irr_submit.XXXXXX", dbdir);
strcpy (irrd_n, template_n);
strcpy (pgp_n, template_n);
strcpy (journal_n, template_n);
if (((irrd_f = rpsdist_fopen (irrd_n)) == NULL) ||
((pgp_f = rpsdist_fopen (pgp_n)) == NULL) ||
((journal_f = rpsdist_fopen (journal_n)) == NULL)) {
trace (ERROR, tr, "send_rps_dist_trans () rps dist file creation error. Abort rps_dist transaction!\n");
ret_code = "SERVER ERROR: rps dist file creation error";
goto ABORT_TRANS;
}
trace (NORM, tr, "Debug. comm file names:\n");
trace (NORM, tr, "Debug. irrd (%s)\n", irrd_n);
trace (NORM, tr, "Debug. pgp (%s)\n", pgp_n);
trace (NORM, tr, "Debug. jentry (%s)\n", journal_n);
/* initialize the irrd, pgp and journal files */
/* This is the !us...!ue data */
if ((ret_code = init_irrd_updates (tr, fin, irrd_f, start, (char *) WARN_TAG)))
goto ABORT_TRANS;
fclose (irrd_f);
irrd_f = NULL;
/* This is the PGP update data for the server's local pgp ring */
if ((ret_code = init_pgp_updates (tr, pgp_f, start, template_n,
&pgp_updates_count)))
goto ABORT_TRANS;
fclose (pgp_f);
pgp_f = NULL;
/* 'NULL' file name is a flag value for RPS-DIST that there are
* no pgp updates */
if (pgp_updates_count == 0) {
remove (pgp_n);
strcpy (pgp_n, "NULL");
}
/* This is the journal entry for the user's submission */
if ((ret_code = init_jentries (tr, tlogfn, tlog_fpos, start->first->source, journal_f)))
goto ABORT_TRANS;
fclose (journal_f);
trace (NORM, tr, "calling rps_dist_trans ()\n");
/*
trace (NORM, tr, "Debug. Bye-bye\n");
exit (0);
*/
/* Send the transaction to rps dist to be added to the DB */
ret_code = rpsdist_transaction (tr, irrd_n, pgp_n, journal_n,
start->first->source, "localhost", 7777);
if (ret_code != NULL)
trace (NORM, tr, "return from irrd_trans (%s).\n", ret_code);
else
trace (NORM, tr, "return from irrd_trans (NULL return) Yuck!\n");
/* "C\n means IRRd commited the transaction */
if (!strcmp (ret_code, "C\n"))
ret_code = NULL;
/* "cs" means we did not get an IRRd trans result. So get the "cs"
* from IRRd to see if the trans succeeded */
else if ((*ret_code < '0' || *ret_code >'9') &&
(get_irrd_cs (tr, start->first->source, IRRd_HOST, IRRd_PORT) <
atol (ret_code)))
ret_code = "Transaction result not known. Query IRRd to determine transaction result or resubmit your transaction at a later time.";
return ret_code;
ABORT_TRANS:
trace (ERROR, tr, "send_rps_dist_trans () Aborting transaction! (%s)\n", ret_code);
/* clean up our rps dist communication files */
if (irrd_f != NULL)
fclose (irrd_f);
if (pgp_f != NULL)
fclose (pgp_f);
if (journal_f != NULL)
fclose (journal_f);
if (strcmp (irrd_n, ""))
remove (irrd_n);
if (strcmp (pgp_n, "NULL") &&
strcmp (pgp_n, "")) {
pgp_files_backout (pgp_n);
remove (pgp_n);
}
if (strcmp (journal_n, ""))
remove (journal_n);
return ret_code;
}
/* Get the latest current serial for DB 'source'.
*
* Input:
* -the DB source to get the current serial for (source)
* -the IRRd host (host)
* -the IRRd port (port)
*
* Return:
* -the latest current serial
* -0 if there was any type of error
*/
long get_irrd_cs (trace_t *tr, char *source, char *host, int port) {
char *data;
regmatch_t cs_rm[2];
regex_t cs_re;
char *cs = "^[^:]+:[^:]+:[[:digit:]]+-([[:digit:]]+)\n$";
/* get the !j output from IRRd */
data = irrd_curr_serial (tr, source, host, port);
/* now parse the output and return the currentserial */
if (data != NULL) {
regcomp (&cs_re, cs, REG_EXTENDED);
if (regexec (&cs_re, data, 2, cs_rm, 0) == 0) {
*(data + cs_rm[1].rm_eo) = '\0';
return atol ((char *) (data + cs_rm[1].rm_so));
}
}
return 0;
}
/* Open up a streams file.
*
* Return:
* A stream file pointer if the operation was a success.
* NULL if the file could not be opened.
*/
FILE *rpsdist_fopen (char *fname) {
FILE *fp;
int fd;
fd = mkstemp (fname);
if (fd == -1)
return NULL;
if ((fp = fdopen (fd, "w")) == NULL) {
close(fd);
return NULL;
}
return fp;
}
/* Generate an RFC 2769 timestamp (pg. 13). Timestamps are of
* the form:
* YYYYMMDD HH:MM:SS [+/-]hh:mm
*
* eg, 20000717 12:28:51 +04:00
*
* Input:
* void
*
* Return:
* an RPS DIST RFC 2769 timestamp
*/
char *rpsdist_timestamp (char *ts) {
time_t now;
now = time (NULL);
strftime (ts, 256, "%Y%m%d %H:%M:%S ", gmtime (&now));
/* UTC_OFFSET is the [+/-]hh:mm value, ie, the amount
* we are away from UTC time */
strcat (ts, UTC_OFFSET);
return ts;
}
/* Remove any PGP key files from the RPS-DIST cache area.
* See init_pgp_updates () for the file format.
*
* Input:
* -name of the PGP control file which has the fully qualified
* path name of the PGP key files (pgpfn)
*
* Return:
* void
*/
void pgp_files_backout (char *pgpfn) {
int rm = 0;
char buf[1024];
FILE *fin;
/* sanity check */
if (pgpfn == NULL ||
(fin = fopen (pgpfn, "r")) == NULL)
return; /* we're hosed ... */
/* remove any PGP key files we may have created in the
* RPS-DIST cache area */
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
if (rm) {
buf[strlen (buf) - 1] = '\0'; /* get rid of the '\n' */
remove (buf);
}
rm = !strcmp ("ADD", buf);
}
fclose (fin);
}
/* Build the RPS-DIST journal entry. See RFC 2769, pg 30 for a
* description of the journal format.
*
* Input
* -the name of the trace log where the initial user copy is (logfn)
* -the file position with the trace log where the submission begins (fpos)
* -the journal entry output file for RPS-DIST (fout)
*
* Return:
* NULL if no errors occur in building the ouput file (fout)
* otherwise a string message explaining the error condition
*/
char *init_jentries (trace_t *tr, char *logfn, long fpos, char *source, FILE *fout) {
int first_line = 1, in_headers = 1, pgp_reg = 0;
int passwd = 0, in_sig = 0, need_sig = 1, in_blankline = 0;
regex_t mailfromre, pgpbegre, pgpsigre, pgpendre, blanklinere, passwdre, EOT;
char curline[MAXLINE], ts[256], *ret_code;
FILE *fin;
char *mailfrom = "^From[ \t]";
char *pgpbegin = "^-----BEGIN PGP SIGNED MESSAGE-----";
char *pgpsig = "^-----BEGIN PGP SIGNATURE-----";
char *pgpend = "^-----END PGP SIGNATURE-----";
char *blankline = "^[ \t]*\n$";
char *password = "^password:|^override:";
char *eot = "^---\n$";
/* sanity check */
if (logfn == NULL) {
ret_code = "SERVER ERROR: Can't find the initial submission log.";
goto JENTRY_ABORT;
}
/* open the transaction carbon copy log file */
if ((fin = fopen (logfn, "r")) == NULL) {
ret_code = "SERVER ERROR: RPS-DIST PGP fopen () error.";
goto JENTRY_ABORT;
}
/* compile our regular expressions */
regcomp (&mailfromre, mailfrom, REG_EXTENDED|REG_NOSUB);
regcomp (&pgpbegre, pgpbegin, REG_EXTENDED|REG_NOSUB);
regcomp (&pgpsigre, pgpsig, REG_EXTENDED|REG_NOSUB);
regcomp (&pgpendre, pgpend, REG_EXTENDED|REG_NOSUB);
regcomp (&blanklinere, blankline, REG_EXTENDED|REG_NOSUB);
regcomp (&passwdre, password, REG_EXTENDED|REG_ICASE|REG_NOSUB);
regcomp (&EOT, eot, REG_EXTENDED|REG_NOSUB);
/* seek to the beginning of the submission */
fseek (fin, fpos, SEEK_SET);
/* prepend the redistribution header (RFC 2769, section A.2) */
fprintf (fout, "transaction-label: %s\n", source);
fprintf (fout, "sequence: 1234567890\n");
fprintf (fout, "timestamp: %s\n", rpsdist_timestamp (ts));
fprintf (fout, "integrity: authorized\n\n");
/* copy the transaction "as-is" from the user for the RPS-DIST
* journal file */
while (fgets (curline, MAXLINE - 1, fin) != NULL) {
if (first_line && regexec (&mailfromre, curline, 0, 0, 0) != 0)
in_headers = 0;
first_line = 0;
/* skip email header to conform to the RPS-DIST redistribution encoding */
if (in_headers && regexec (&blanklinere, curline, 0, 0, 0) == 0)
in_headers = 0;
if (in_headers)
continue;
in_blankline = 0;
/* check for an end of transaction line '---' */
if (regexec (&EOT, curline, 0, 0, 0) == 0)
break; /* all done, exit transaction */
/* check for a password, eg, 'password: foo' and skip to
* conform to the RPS-DIST redistribution encoding */
if (!pgp_reg && regexec (&passwdre, curline, 0, 0, 0) == 0) {
passwd = 1;
continue; /* skip the regular signature begin */
}
/* check for a '-----BEGIN PGP SIGNED MESSAGE-----' and skip it to
* conform to the RPS-DIST redistribution encoding */
if (!pgp_reg && regexec (&pgpbegre, curline, 0, 0, 0) == 0) {
pgp_reg = 1;
continue; /* skip the regular signature */
}
/* check for a '-----BEGIN PGP SIGNATURE-----' and skip if a regular
* signature to conform to the RPS-DIST redistribution encoding */
if (regexec (&pgpsigre, curline, 0, 0, 0) == 0) {
in_sig = 1;
if (!pgp_reg) {
fputs ("\nsignature:\n", fout);
need_sig = 0;
}
}
/* skip the PGP sig for regular sig's and keep for detached */
if (in_sig) {
/* skip pgp regular sig's */
if (pgp_reg)
continue;
else
fputs ("+", fout);
}
/* check for a '-----END PGP SIGNATURE-----', stop adding
* '+'s for RPSL line continuation at the beginning of each line */
if (in_sig && regexec (&pgpendre, curline, 0, 0, 0) == 0)
in_sig = 0;
/* check for a blank line as the last line. need to know
* when adding the 'signature' meta-object as the server
* add's a blank line after transactions. on the last
* transaction in the file there will not be a blank line
* as the last line (ie, from the server). */
if (regexec (&blanklinere, curline, 0, 0, 0) == 0)
in_blankline = 1;
/* write a line to our journal */
fputs (curline, fout);
}
/* add a 'signature' meta-object if one is needed */
if (need_sig) {
if (!in_blankline)
fputs ("\n", fout);
if (pgp_reg)
fputs ("signature:\n <PGP REGULAR>\n", fout);
else if (passwd)
fputs ("signature:\n <CLEARTEXT PASSWORD>\n", fout);
else
fputs ("signature:\n <MAIL FROM>\n", fout);
}
/* make purify happy */
regfree (&mailfromre);
regfree (&pgpbegre);
regfree (&pgpsigre);
regfree (&pgpendre);
regfree (&blanklinere);
regfree (&passwdre);
regfree (&EOT);
fclose (fin);
return NULL;
JENTRY_ABORT: /* if we get here, someth'in went wrong */
sprintf (curline, "init_jentries() %s Abort rps_dist transaction!", ret_code);
trace (ERROR, tr, "%s\n", curline);
return strdup (curline);
}
/* Make the !us...!ue file for submission to IRRd by RPS-DIST.
*
* Input:
* -pipeline input file with all the canonicalized objects (fin)
* note that each canonicalized object is preceeded with pipeline
* header info.
* -routine expects a file to be opened and ready for writing (fout)
* -a pointer to the begining of the linked list of updates (start)
*
* Return:
* NULL if no errors occur in building the ouput file (fout)
* otherwise a string message explaining the error condition
*/
char *init_irrd_updates (trace_t *tr, FILE *fin, FILE *fout, ret_info_t *start,
char *warn_tag) {
int n, line_cont, line_begin;
irrd_result_t *p;
char *ret_code;
char *OP[] = {"ADD\n\n", "DEL\n\n"}, buf[MAXLINE];
/* !us<DB source> */
fprintf (fout, "!us%s\n", start->first->source);
/* Loop through the submission file and build the
* !us...!ue IRRd update file
*/
for (p = start->first; p != NULL; p = p->next) {
/* Skip NOOP operations */
if (!(p->svr_res & NOOP_RESULT)) {
/* determine the operation, 'ADD' or 'DEL' ... */
n = 0;
if (!strcmp (p->op, DEL_OP))
n = 1;
/* ... and write the operation to the IRRd update file */
if (fputs (OP[n], fout) == EOF) {
ret_code = "SERVER ERROR: RPS-DIST IRRd operation disk error.";
goto IRRd_ABORT;
}
/* seek to the beginning of object */
fseek (fin, p->offset, SEEK_SET);
/* line cont in the fgets () sense, not in the rpsl sense.
* ie, the current input line was larger than our memory buffer
*/
line_cont = 0;
/* copy the canonicalized submission object from the input
* file to the IRR update file */
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
n = strlen (buf);
line_begin = !line_cont;
line_cont = (buf[n - 1] != '\n');
/* skip possible 'WARNING:...' lines at the end of the object */
if (line_begin && !strncmp (buf, warn_tag, strlen (warn_tag)))
continue;
fputs (buf, fout);
if (line_begin && buf[0] == '\n') /* looking for a blank line */
break;
}
}
}
/* !ue */
fprintf (fout, "!ue\n");
return NULL;
IRRd_ABORT: /* if we get here, someth'in went wrong */
sprintf (buf, "init_irrd_updates() %s Abort rps_dist transaction!", ret_code);
trace (ERROR, tr, "%s\n", buf);
return strdup (buf);
}
/* Build the RPS-DIST PGP file. RPS-DIST will use the file built
* in this routine to update the server's local PGP rings. The format
* of the file will be like this:
*
* DEL
* 0x....
*
* ADD
* <fully qualified file name>
* ...
*
* Note: the reason for not writing 'ADD' keys directly to the file
* is because it is easier to give pgp a file name to add the key
* then to read it and send it to pgp's stdin.
*
* Input:
* -routine expects a file to be opened and ready for writing (fout)
* -a pointer to the begining of the linked list of updates (start)
*
* Return:
* -a count of the number of PGP udpates (pgp_updates_count)
* -NULL if there were no errors encountered
* -otherwise a string message explaining the error condition
*/
char *init_pgp_updates (trace_t *tr, FILE *fout, ret_info_t *start,
char *template_n, int *pgp_updates_count) {
int n;
irrd_result_t *p;
char *ret_code;
char *OP[] = {"ADD\n", "DEL\n"}, buf[MAXLINE], fn[1024];
FILE *fin = NULL, *dst = NULL;
/* keep track of the number of PGP udates we find */
*pgp_updates_count = 0;
/* Loop through the submission list and collect data on the PGP updates */
for (p = start->first; p != NULL; p = p->next) {
if (!(p->svr_res & NOOP_RESULT) &&
is_keycert_obj (p)) {
/* determine the operation, 'ADD' or 'DEL' ... */
n = 0;
if (!strcmp (p->op, DEL_OP))
n = 1;
/* ... and write the operation to the PGP update file */
if (fputs (OP[n], fout) == EOF) {
ret_code = "SERVER ERROR: RPS-DIST PGP operation disk error.";
goto PGP_ABORT;
}
/* 'DEL' operation */
if (n)
fprintf (fout, "0x%s\n\n", (p->obj_key + 7));
/* 'ADD' operation */
else {
/* make sure the public key exists ... */
if (p->keycertfn == NULL) {
ret_code = "SERVER ERROR: RPS-DIST PGP missing keycert file.";
goto PGP_ABORT;
}
/* ... now open it */
if ((fin = fopen (p->keycertfn, "r")) == NULL) {
ret_code = "SERVER ERROR: RPS-DIST PGP fopen () error.";
goto PGP_ABORT;
}
/* open the output public key file */
strcpy (fn, template_n);
if ((dst = rpsdist_fopen (fn)) == NULL) {
ret_code = "SERVER ERROR: RPS-DIST PGP file creation error.";
goto PGP_ABORT;
}
/* transfer the public key to an rps-dist PGP key update file */
while (fgets (buf, MAXLINE - 1, fin) != NULL)
fputs (buf, dst);
/* write the PGP key filename to the RPS-DIST PGP control file */
fputs (fn, fout);
/* This is the old code
* open the public key file *
if ((fin = fopen (p->keycertfn, "r")) == NULL) {
ret_code = "SERVER ERROR: RPS-DIST PGP fopen () error.";
goto PGP_ABORT;
}
* transfer the public key to the rps-dist PGP update file *
while (fgets (buf, MAXLINE - 1, fin) != NULL)
fputs (buf, fout);
End of old code */
/* close and remove the input public key file */
fputs ("\n", fout);
fclose (fin);
/* removal of the initial public key files is done in rpsdist_trans () */
fclose (dst);
fin = dst = NULL;
}
/* count the number of PGP updates, there could be 0 */
(*pgp_updates_count)++;
}
}
return NULL;
PGP_ABORT: /* if we get here, someth'in went wrong */
if (fin != NULL)
fclose (fin);
if (dst != NULL)
fclose (dst);
sprintf (buf, "init_pgp_updates () %s Abort rps_dist transaction!", ret_code);
trace (ERROR, tr, "%s\n", buf);
return strdup (buf);
}
/* This is the old guy. We are migrating away from this version of performing
* the transactions. However this works and is what we will use for now.
*
* Our migration path will be like this:
*
* (old guy) -> (irr_submit, irrd transaction compliant) -> (rpsdist)
*
* To get to the next step, this routine should be phased out and
* perform_transactions_new () should be used.
* Then to get to the last step perform_transactions_new () should be
* phased out in favor of perform_rpsdist_trans ().
*/
void perform_transactions (trace_t *tr, FILE *fin, ret_info_t *start,
int null_submission,
char *IRRd_HOST, int IRRd_PORT, char *pgpdir) {
char buf[MAXLINE], *ret_code;
int fd, num_trans = 0;
int open_conn = 0, abort_trans = 0;
long offset;
trans_info_t ti;
irrd_result_t *p;
/* pgp_data_t pdat; */
/* fprintf (dfile, "\n----\nEnter perform_transactions()\n");*/
/* rewind */
fseek (fin, 0L, SEEK_SET);
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
if (strncmp (HDR_START, buf, strlen (HDR_START) - 1))
continue;
/* JW commented out to dup rawhoisd
if (!abort_trans)
*/
offset = ftell (fin);
/* fprintf (dfile, "HDR_START offset (%ld)\n", offset);*/
/* illegal hdr field found or EOF or no object after hdr */
if (parse_header (tr, fin, &offset, &ti)) {
abort_trans = 1;
/* fprintf (dfile, "calling update_trans_outcome_list (internal error)...\n"); */
update_trans_outcome_list (tr, start, &ti, offset, INTERNAL_ERROR_RESULT,
"\" Internal error: malformed header!\"\n");
free_ti_mem (&ti);
continue;
}
else if (update_has_errors (&ti))
abort_trans = 1;
else if (null_submission == 0) {
update_trans_outcome_list (tr, start, &ti, offset, NULL_SUBMISSION, NULL);
continue;
}
update_trans_outcome_list (tr, start, &ti, offset, 0, NULL);
free_ti_mem (&ti);
}
/* JW commented out to dup rawhoisd
* want to bring back for transaction semantic support
if (abort_trans)
reinit_return_list (dfile, start, SKIP_RESULT);
else {
*/
for (p = start->first; p != NULL; p = p->next) {
/* JW want to bring back in later, dup rawhoisd
if (p->svr_res & NOOP_RESULT)
continue;
*/
/* JW take next 3 sections out to reverse rawhoisd behavior */
if (p->svr_res & INTERNAL_ERROR_RESULT ||
p->svr_res & NULL_SUBMISSION) {
trace (ERROR, tr,
"Internal error or NULL submission. Object not added to IRRd.\n");
continue;
}
if (p->svr_res & USER_ERROR) {
trace (NORM, tr,
"Syntax or authorization error. Object not added to IRRd.\n");
continue;
}
if (p->svr_res & NOOP_RESULT) {
trace (NORM, tr, "NOOP object. Object not added to IRRd.\n");
continue;
}
/* what the eff is this segment doing? */
if (EOF == fseek (fin, p->offset, SEEK_SET))
fprintf (stderr, "ERROR: fseek (%ld)\n", p->offset);
else {
fgets (buf, MAXLINE - 1, fin);
/*fprintf (dfile, "irrd_trans () line: %s", buf);*/
fseek (fin, p->offset, SEEK_SET);
}
/* fprintf (dfile, "perform_trans () calling irrd_transaction ()...\n");*/
ret_code = irrd_transaction (tr, (char *) WARN_TAG, &fd, fin, p->op,
p->source, ++num_trans, &open_conn,
IRRd_HOST, IRRd_PORT);
/* check for no IRRd errors and we have a key-cert object */
if (!put_transaction_code (tr, p, ret_code) &&
is_keycert_obj (p) &&
p->op != NULL) {
update_pgp_ring_new (tr, p, pgpdir);
/*
if (strcmp (p->op, DEL_OP)) {
pgp_add (tr, pgpdir, p->keycertfn, &pdat);
pgp_free (&pdat);
}
else
pgp_del (tr, pgpdir, p->obj_key + 7);
*/
}
}
if (open_conn) {
end_irrd_session (tr, fd); /* send '!q' */
fflush (fin); /* JW only needed when irrd commands are sent to terminal */
close_connection (fd);
}
/* Remove any key certificate files from our temp directory area */
for (p = start->first; p != NULL; p = p->next)
if (p->keycertfn != NULL)
remove (p->keycertfn);
/* JW want to bring back in later, dup rawhoisd
}
*/
/* fprintf (dfile, "Exit perform_transactions()\n----\n");*/
}
syntax highlighted by Code2HTML, v. 0.9.1