/*
* $Id: util.c,v 1.13 2002/10/22 19:02:15 ljb Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
#include <unistd.h>
#include <irr_notify.h>
#include <pgp.h>
/*
* Could have an email user or TCP user.
* In case of a TCP user set the email fields
* to single space for uniform treatment.
*/
void chk_email_fields (trans_info_t *ti) {
if (ti->subject == NULL)
ti->subject = strdup (" ");
if (ti->date == NULL)
ti->date = strdup (" ");
if (ti->msg_id == NULL)
ti->msg_id = strdup (" ");
ti->hdr_fields |= (SUBJECT_F|DATE_F|MSG_ID_F);
}
/*
* Return 0 if something wrong is found , ie, a malformed
* transaction header has been detected.
* Else return 1.
*/
int chk_hdr_flds (u_int hdr_flds) {
return ((int) !((~hdr_flds) & NOTIFY_REQUIRED_FLDS));
}
/* Remove the sender from our notify if he/she appears
* in the list of notifyees. The sender always gets a response
* so another notification is redundant.
*
* Return:
* void
* remove the sender's address from *addr_buf
*/
void remove_sender (char *sender, char *addr_buf, char **next) {
char buf[MAXLINE];
char *q, *bnext, *p = NULL;
int found = 0;
/* Some email ID's appear as 'gerald@merit.edu (Gerald Andrew Winters)'
* For these cases want to terminate string at first blank so sender
* does not get an redundant notify
*/
if ((p = strchr (sender, ' ')) != NULL)
*p = '\0';
bnext = buf;
for (q = addr_buf; q < *next; q += strlen (q) + 1) {
if (strcasecmp (sender, q)) {
strcpy (bnext, q);
bnext += strlen (q) + 1;
}
else
found = 1;
}
if (found) {
memcpy (addr_buf, buf, bnext - buf);
*next = (addr_buf + (bnext - buf));
}
if (p != NULL)
*p = ' ';
}
/* Interpret the IRRd return code and place the result in the
* 'irrd_result_t' struct. IRRd will return 'C\n' for success
* or an error otherwise (IRRd should give a text msg indicating
* what the error was).
*
* Return:
* 0 means the there were no errors from IRRd
* 1 otherwise
*/
int put_transaction_code_new (trace_t *tr, irrd_result_t *p, char *irrd_ret_code) {
int ret_code = 0;
/*fprintf (dfile, "put_transaction_code () irrd result: %s", irrd_ret_code);*/
if (irrd_ret_code == NULL)
trace (NORM, tr, "put_transaction_code (NULL return code).\n");
else
trace (NORM, tr, "put_transaction_code (return code(%s)).\n", irrd_ret_code);
/* JW 7/7/00 Will this work?
if (irrd_ret_code != NULL && *irrd_ret_code == 'C')
p->svr_res = SUCCESS_RESULT;
else {
*/
if (irrd_ret_code == NULL)
p->svr_res = SUCCESS_RESULT;
else {
p->svr_res = IRRD_ERROR_RESULT;
/* Skip the 'F' or whatever machine return code
* but do get the text error msg
*/
if (irrd_ret_code != NULL)
p->err_msg = strdup (++irrd_ret_code);
else
p->err_msg = strdup ("Error message not available!\n");
ret_code = 1;
}
return ret_code;
}
/* Interpret the IRRd return code and place the result in the
* 'irrd_result_t' struct. IRRd will return 'C\n' for success
* or an error otherwise (IRRd should give a text msg indicating
* what the error was).
*
* Return:
* 0 means the there were no errors from IRRd
* 1 otherwise
*/
int put_transaction_code (trace_t *tr, irrd_result_t *p, char *irrd_ret_code) {
int ret_code = 0;
/*fprintf (dfile, "put_transaction_code () irrd result: %s", irrd_ret_code);*/
if (irrd_ret_code == NULL)
trace (NORM, tr, "put_transaction_code (NULL return code).\n");
/* else
trace (NORM, tr, "put_transaction_code (return code(%s)).\n", irrd_ret_code); */
if (irrd_ret_code != NULL && *irrd_ret_code == 'C')
p->svr_res = SUCCESS_RESULT;
else {
p->svr_res = IRRD_ERROR_RESULT;
/* Skip the 'F' or whatever machine return code
* but do get the text error msg
*/
if (irrd_ret_code != NULL)
p->err_msg = strdup (++irrd_ret_code);
else
p->err_msg = strdup ("Error message not available!\n");
ret_code = 1;
}
return ret_code;
}
/* Is the object a 'key-cert' object?
*
* return:
* non-zero means we have a key-cert object
* 0 otherwise
*/
int is_keycert_obj (irrd_result_t *p) {
if (p->obj_type == NULL)
return 0;
return !strcasecmp (p->obj_type, "key-cert");
}
/* JW get rid of */
int put_transaction_code_old (trace_t *tr, FILE *fin, char code, long fpos) {
long restore_pos;
if ((restore_pos = ftell (fin)) == -1L)
return 0;
if (fseek (fin, fpos, SEEK_SET)) {
fprintf (stderr, "ERROR: put_transaction_code() fseek(%ld) error!\n", fpos);
return 0;
}
else {
if (fputc ((int) code, fin) == EOF)
/*fprintf (dfile, "put_transaction_code() fputc(%c) error\n", code);*/
if (fseek (fin, restore_pos, SEEK_SET)) {
/*fprintf (dfile, "ERROR: put_transaction_code() fseek(%ld) restore fpos error!\n", restore_pos);*/
return 0;
}
}
return 1;
}
void skip_transaction (FILE *fin, long *offset) {
char buf[MAXLINE];
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
*offset += strlen (buf);
if (buf[0] == '\n')
break;
}
}
/* Add the element pointed to by 'obj' to the end of the linked list.
*
* Return:
* void
*/
void add_outcome_list_obj (trace_t *tr, ret_info_t *start, irrd_result_t *obj) {
obj->next = NULL;
if (start->first == NULL)
start->first = obj;
else
start->last->next = obj;
start->last = obj;
}
/* Initialize an irrd_result_t struct. If an INTERNAL_ERROR_RESULT, NOOP_RESULT, or
* USER_ERROR occurs the 'svr_res' field is initialized. Otherwise 'svr_res'
* will be uninitialized. In this case, 'svr_res' will be initialized when
* the update is applied to IRRd from the IRRd return code. The 'op', 'source'
* and 'offset' fields are used to send the transaction to IRRd.
*
* Also see if outcome was a NOOP. Calling functions need to know if every
* object was a NOOP.
*
* Return:
* 1 if outcome was a NOOP
* 0 otherwise
*/
/*
obj = (irrd_result_t *) calloc (1, sizeof (irrd_result_t));
*/
int update_trans_outcome_list (trace_t *tr, ret_info_t *start,
trans_info_t *ti, long offset,
enum SERVER_RES svr_res, char *err_msg) {
irrd_result_t *obj;
int noop_count = 0;
/* fprintf (dfile, "enter update_trans_outcome_list ()...\n");*/
obj = (irrd_result_t *) malloc (sizeof (irrd_result_t));
memset ((char *) obj, 0, sizeof (irrd_result_t));
if (err_msg != NULL) {
obj->err_msg = strdup (err_msg);
obj->svr_res = svr_res;
}
else if (svr_res == NULL_SUBMISSION)
obj->svr_res = NULL_SUBMISSION;
else if ((ti->hdr_fields & OP_F) && !strcmp (ti->op, NOOP_OP)) {
obj->svr_res = NOOP_RESULT;
noop_count = 1;
}
else if (ti->hdr_fields & ERROR_FLDS)
obj->svr_res = USER_ERROR;
obj->hdr_fields = ti->hdr_fields;
if (ti->hdr_fields & OP_F)
obj->op = strdup (ti->op);
if (ti->hdr_fields & SOURCE_F)
obj->source = strdup (ti->source);
if (ti->obj_type != NULL)
obj->obj_type = strdup (ti->obj_type);
if (ti->obj_key != NULL)
obj->obj_key = strdup (ti->obj_key);
if (ti->keycertfn != NULL)
obj->keycertfn = strdup (ti->keycertfn);
obj->offset = offset;
/* fprintf (dfile, "update_trans_outcome (): offset (%ld)\n", obj->offset);*/
add_outcome_list_obj (tr, start, obj);
/* fprintf (dfile, "exit update_trans_outcome_list ()...\n");*/
return noop_count;
}
/* Set all unset elements in the 'irrd_result_t' list to 'res'. This
* function should be called when an error of any kind has been
* found (eg, syntax error, network error, internal error, ...).
* The reason is to support transaction semactics which calls for
* a transaction to be aborted if the entire trans cannot be applied.
* So this routine will set the proper trans outcome to those updates
* that would have been sent to IRRd if it were not for the error occuring.
*
* Return:
* void
*/
void reinit_return_list (trace_t *tr, ret_info_t *start, enum SERVER_RES res) {
irrd_result_t *p;
for (p = start->first; p != NULL; p = p->next)
if (p->svr_res == 0)
p->svr_res = res;
}
/* Add or delete the PGP public key to our production ring.
* 'ir' is a struct with a pointer to the location of
* the public key file and 'pgpdir' is a pointer to the
* location of the production rings.
*
* Return:
* void
*/
void update_pgp_ring (trace_t *tr, irrd_result_t *ir, char *pgpdir) {
int p[2], pgp_ok = 0;
char curline[4096], pgppath[256];
FILE *pgpout;
char *pgp_add = "^Keys added successfully";
char *pgp_del = "^Removed.";
regex_t re;
printf ("enter update_pgp_ring...\n");
if (ir->op == NULL ||
(strcmp (ir->op, ADD_OP) && strcmp (ir->op, DEL_OP)))
return;
printf ("operation (%s) key-cert (%s) certfn (%s) pgpdir (%s)\n",
ir->op, ir->obj_key, ir->keycertfn, pgpdir);
printf ("processing ADD pgp key operation\n");
if (strcmp (ir->op, DEL_OP))
regcomp (&re, pgp_add, REG_EXTENDED|REG_NOSUB);
else
regcomp (&re, pgp_del, REG_EXTENDED|REG_NOSUB);
/* There is a bug in 5.0i in which command line parms
* for the path's to the rings are ignored. To get
* around this we must set the PGPPATH environ var.
*/
strcpy (pgppath, "PGPPATH=");
strcat (pgppath, pgpdir);
if (putenv (pgppath)) {
/* JW This should be written to an error log!!!!! */
printf ("Coudn't set environment var (%s) for pgp. Abort!\n", pgpdir);
return;
}
pipe(p);
if (fork() == 0) { /* Child */
dup2(p[0], 1);
dup2(p[0], 2);
close(p[1]);
if (strcmp (ir->op, DEL_OP))
execlp (PGPK, PGPK, "--batchmode=1", "-a", ir->keycertfn, NULL);
else {
strcpy (curline, "0x");
strcat (curline, (ir->obj_key + 7));
execlp (PGPK, PGPK, "--batchmode=1", "-r", curline, NULL);
}
/* JW this should go into an error log!!!!! */
printf ("child: oops! shouldn't be here, execlp fail\n");
_exit(127);
}
close(p[0]);
if ((pgpout = fdopen(p[1], "r")) == NULL) {
/* JW This should be written to an error log!!!!! */
printf ("Internal error. Couldn't open pipe: update_pgp_ring (%s)",
ir->obj_key);
return;
}
/* Look for a successful operation from PGP */
while (fgets (curline, 4095, pgpout) != NULL) {
if (0 == regexec (&re, curline, 0, NULL, 0))
pgp_ok = 1;
}
fclose (pgpout);
if (!pgp_ok) /* JW This should be written to an error log!!!!! */
printf ("Oops! Couldn't (%s) pgp key (%s) to local ring\n",
ir->op, ir->obj_key);
}
/* Loop through the submission file 'fin', initializing the 'ti'
* struct with the header info and adding to a global linked list
* pointed to by 'start'. Most important is to see if there are
* any errors in the submission (eg, syntax error, auth error, ...)
* which should cause the entire transaction to abort.
*
* Also determine if all objects in the submission are NOOP's.
*
* Input:
* -pipeline input file with info headers (fin)
* -flag to indicate there were no objects in the trans (submission_count_lines)
* -pointer to the linked list of trans info structures (start)
*
* Return:
* -1 If any errors (user or server) are encountered, this signals
* the calling routine to abort the transaction
* -0 otherwise
* -flag value (0 or 1) to indicate if all objects in trans are NOOP's (all_noop)
*/
int pick_off_header_info (trace_t *tr, FILE *fin, int submission_count_lines,
ret_info_t *start, int *all_noop) {
int corrupt_hdr, abort_trans = 0, obj_count = 0, noop_count = 0;
long offset;
trans_info_t ti;
char buf[MAXLINE];
/* initialize. if all objects are NOOP's then return all_noop = 1 to
* calling function */
*all_noop = 0;
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
if (strncmp (HDR_START, buf, strlen (HDR_START) - 1))
continue;
corrupt_hdr = 0;
/* Parse the header lines HDR-START ... HDR-END, fill in
* the 'ti' struct with the header info and return 0 if
* a 'HDR-END' field is encountered */
if (parse_header (tr, fin, &offset, &ti)) {
corrupt_hdr = abort_trans = 1;
}
else if (update_has_errors (&ti))
abort_trans = 1;
if (corrupt_hdr)
update_trans_outcome_list (tr, start, &ti, offset, INTERNAL_ERROR_RESULT,
"\" Internal error: malformed header!\"\n");
else if (submission_count_lines == 0)
update_trans_outcome_list (tr, start, &ti, offset, NULL_SUBMISSION, NULL);
else
noop_count += update_trans_outcome_list (tr, start, &ti, offset, 0, NULL);
free_ti_mem (&ti);
obj_count++;
}
/* Return if all the objects in the transaction were NOOP's */
*all_noop = (obj_count == noop_count);
return abort_trans;
}
/* Add or delete the PGP public key to/from our production ring.
*
* Input:
* -pointer to a struct with the file name of the key file, the
* operation (ie, add or del) and the hex id of the key (ir)
* -a fully qualified path name to the pgp rings (pgpdir)
*
* Return:
* void
*/
void update_pgp_ring_new (trace_t *tr, irrd_result_t *ir, char *pgpdir) {
fprintf (stderr, "JW:update_pgp_ring_new() pgpdir (%s)\n", pgpdir);
/* sanity checks */
if (ir == NULL || ir->op == NULL || ir->obj_key == NULL) {
trace (ERROR, tr, "update_pgp_ring () NULL result pointer...\n");
return;
}
else if (ir->op == NULL) {
trace (ERROR, tr, "update_pgp_ring () NULL op for key/hex ID (%s)\n",
(ir->obj_key != NULL ? ir->obj_key : "NULL"));
return;
}
else if (ir->obj_key == NULL) {
trace (ERROR, tr, "update_pgp_ring () NULL key/hex ID\n");
return;
}
/* if it's a 'REPLACE_OP' or 'NOOP', nothing to do to rings */
if (strcmp (ir->op, ADD_OP) && strcmp (ir->op, DEL_OP))
return;
/* check the hexid which is in 'PGPKEY-........' format */
if (!pgp_hexid_check ((ir->obj_key + 7), NULL)) {
trace (ERROR, tr, " update_pgp_ring () malformed hex_id\n");
return;
}
else if (pgpdir == NULL) {
trace (ERROR, tr,
"update_pgp_ring () Yikes! NULL PGP dir/PGPPATH pointer\n");
return;
}
/* everything looks good, now update our rings */
/* add a key to our local ring */
if (strcmp (ir->op, DEL_OP)) {
if (!pgp_add (tr, pgpdir, ir->keycertfn, NULL))
trace (ERROR, tr, "update_pgp_ring () pgp error in adding key (%s)\n",
ir->obj_key);
}
/* remove a key from our local ring */
else if (!pgp_del (tr, pgpdir, (ir->obj_key + 7))) {
trace (ERROR, tr, "update_pgp_ring () pgp error in deleting key (%s)\n",
ir->obj_key);
}
fprintf (stderr, "JW: exit update_pgp_ring_new () ...\n");
}
syntax highlighted by Code2HTML, v. 0.9.1