/*
* $Id: notify_msgs.c,v 1.6 2002/10/17 20:25:56 ljb Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <irr_notify.h>
extern config_info_t ci;
/*
* Move the file position pointer beyond the current object.
* It is possible through NOOP's and/or no notifers and/or
* forwarder's that the current object has not been used
* for anything. So we need to move on to the next transaction
* in the file.
*/
void read_past_obj (FILE *fp) {
char buf[10*MAXLINE];
while (fgets (buf, MAXLINE - 1, fp) != NULL) {
if (buf[0] == '\n')
break;
}
}
/*
* Dump the object to file. Every object should have
* a blank line after it, even the last object in the file.
*/
/* JW need to put a check for "large objects". When object exeeds
* size limit, [snip...] is printed and rest of object is skipped.
*/
int dump_object_to_file (trace_t *tr, FILE *fp, FILE *fin, long obj_pos,
int max_line_size) {
char buf[10*MAXLINE];
char *cp;
int count = 0, print_snip = 1;
strcpy (buf, "\n");
trace (TR_TRACE, tr, "dump_object_to_file () dumping object to file...\n");
fseek (fin, obj_pos, SEEK_SET);
while ((cp = fgets (buf, MAXLINE - 1, fin)) != NULL) {
count++;
if (buf[0] == '\n')
break;
if (--max_line_size < 0 &&
!(is_changed (buf) ||
is_source (buf) ||
buf[0] == ERROR_TAG[0] ||
buf[0] == WARN_TAG[0])) {
if (print_snip && max_line_size < 0) {
fputs (SNIP_MSG, fp);
print_snip = 0;
}
continue;
}
fputs (buf, fp);
}
if (cp == NULL &&
count < 4)
return -1;
/* want to make sure next line written is not concated to this one */
if (buf[strlen (buf) - 1] != '\n')
fprintf (fp, "\n");
return 1;
}
/* Copy the file whose name is '*old_fname' to the file pointed
* bye '*msg_fd' (ie, the user notification file). If the file
* name begins with a digit, function assumes the name is an offset
* in the input file. Otherwise the file is opened and copied to
* the notification file with no special treatment.
*
* Return:
* 1 if there were no errors
* -1 otherwise
*/
int dump_old_obj (trace_t *tr, FILE *msg_fp, FILE *fin, char *old_fname,
int max_line_size) {
FILE *fp_old;
long fpos;
int ret_code;
/*fprintf (dfile, "\n---\ndump_old_obj() file name-(%s)\n", old_fname);*/
/* file pointer is an offset in the input file */
if (*old_fname >= '0' && *old_fname <= '9') {
fpos = ftell (fin);
ret_code = dump_object_to_file (tr, msg_fp, fin, strtol (old_fname, NULL, 10),
max_line_size);
fseek (fin, fpos, SEEK_SET);
}
else if ((fp_old = fopen (old_fname, "r")) == NULL) {
trace (NORM, tr, "ERROR: dump_old_obj () could not open file \"%s\"\n",
old_fname);
ret_code = -1;
}
else {
ret_code = dump_object_to_file (tr, msg_fp, fp_old, 0L, max_line_size);
fclose (fp_old);
}
/* fprintf (dfile, "dump_old_obj() file name-(%s) ret_code-(%d)\n---\n\n", old_fname, ret_code);*/
return ret_code;
}
void maint_request (trace_t *tr, FILE *fin, long obj_pos, trans_info_t *ti,
char *to_addr, char *tmpfname, int max_line_size ) {
long fpos;
FILE *fp;
char buf[MAXLINE], email[256];
int fd, status, pid, w, no_mail = 0;
fpos = ftell (fin);
/* create the file name */
strcpy(buf, tmpfname);
fd = mkstemp(buf);
if ((fp = fdopen (fd, "w")) == NULL) {
trace (NORM, tr, "maint_request () could not open file \"%s\"\n", buf);
return;
}
#ifdef HAVE_SENDMAIL
fprintf (fp, "From: %s\nReply-To: %s\n", to_addr, to_addr);
fprintf (fp, "To: %s\nSubject: %s\n", to_addr, ti->subject);
#endif
if (ti->new_mnt_error)
fputs ("\n-- New maintainer request --\n\n", fp);
else
fputs ("\n-- Maintainer deletion request (passed auth check) --\n\n", fp);
if (ti->web_origin_str == NULL) {
fprintf (fp, "-FROM: %s\n", ti->sender_addrs);
fprintf (fp, "-DATE: %s\n\n\n", ti->date);
} else
fprintf (fp, WEB_UPDATE, ti->web_origin_str);
if (dump_object_to_file (tr, fp, fin, obj_pos, max_line_size) > 0) {
trace (TR_TRACE, tr, "maint_request () sending mail to (%s)...\n", email
);
fclose (fp);
#ifdef HAVE_SENDMAIL
sprintf (email, "%s < %s", SENDMAIL_CMD, buf);
#elif HAVE_MAIL
sprintf (email, "%s \"%s\" < %s", MAIL_CMD, to_addr, buf);
#else
trace (NORM, tr, "No mail or sendmail found\n");
trace (NORM, tr, "Could not send a \"new maintainer\" request msg\n");
no_mail = 1;
#endif
if (!no_mail) {
trace (NORM, tr, "mail %s\n", to_addr);
chmod (email, 00666);
if ((pid = fork ()) == 0) {
execlp ("sh", "sh", "-c", email, 0);
exit (127);
}
while ((w = wait (&status)) != pid && w != -1);
}
}
else
fclose (fp);
fseek (fin, fpos, SEEK_SET);
unlink (buf);
}
/*
* Create a notification/forward file. Save the file pointer
* in a global array of file pointers (ie, msg_hdl[]). num_hdls
* gives the number of file pointers in msg_hdl[] and also
* points to the next available index.
*/
int create_notify_file (trace_t *tr, char *p, char *tmpfname) {
char buf[MAXLINE];
int fd;
/* create the file name */
strcpy(buf, tmpfname);
fd = mkstemp (buf);
if (num_hdls >= MAX_HDLS || fd == -1) {
trace (NORM, tr, "ERROR: create_notify_file () file hdl overflow (%d) or tempfile error\n",
num_hdls);
close(fd);
return -1;
}
else if ((msg_hdl[num_hdls].fp = fdopen (fd, "w+")) == NULL) {
trace (NORM, tr,
"ERROR: create_notify_file() could not open file \"%s\"\n", buf);
close(fd);
unlink(buf);
return -1;
}
msg_hdl[num_hdls].fname = strdup (buf);
return num_hdls++;
}
/* return index of element in list or return -1 */
int present_in_list (char *list, char *last, char *target_str) {
char *p;
int i = 0;
for (p = list; p < last; p += strlen (p) + 1, i++)
if (!strcasecmp (target_str, p))
return i;
return -1;
}
/* Add mail addr *p to list (ie, notify or forward list)
* pointed to by *next.
*/
int add_list_member (trace_t *tr, char *p, char *buf, char **next) {
if ((MAX_ADDR_SIZE - (*next - buf)) > strlen (p)) {
strcpy (*next, p);
*next += strlen (p) + 1;
return 1;
}
else {
trace (NORM, tr, "ERROR: add_list_member () buffer ?_addrs overflow!\n");
return -1;
}
}
void init_response_header (trace_t *tr, FILE *fp, char *from, char *to, enum NOTIFY_T response_type,
trans_info_t *ti, char *db_admin) {
#ifdef HAVE_SENDMAIL
if (ti->web_origin_str == NULL || response_type != SENDER_RESPONSE) {
if (db_admin != NULL)
fprintf (fp, "From: %s\nReply-To: %s\n", db_admin, db_admin);
fprintf (fp, "To: %s\nSubject: %s\n", to, ti->subject);
}
#endif
switch (response_type) {
case SENDER_RESPONSE:
fprintf (fp, SENDER_HEADER);
break;
case FORWARD_RESPONSE:
if (ci.forward_header_msg != NULL)
fprintf (fp, ci.forward_header_msg);
else
fprintf (fp, FORWARD_HEADER);
break;
case NOTIFY_RESPONSE:
if (ci.notify_header_msg != NULL)
fprintf(fp, ci.notify_header_msg);
else
fprintf (fp, NOTIFY_HEADER, ti->source);
break;
default:
trace (NORM, tr,
"ERROR: init_response_header() unknown repsone type-(%d)\n",
response_type);
break;
}
fprintf (fp, DIAG_HEADER);
if (ti->web_origin_str == NULL)
fprintf (fp, MAIL_HEADERS, from, ti->subject, ti->date, ti->msg_id);
else if ( response_type != SENDER_RESPONSE )
fprintf (fp, WEB_UPDATE, ti->web_origin_str);
}
void init_response_footer (FILE *fp) {
if (ci.footer_msg != NULL)
fprintf (fp, ci.footer_msg);
else {
fprintf (fp, RESPONSE_FOOTER);
}
}
/*
* Create a response file and init the file with the response header
* text.
*/
void init_response (trace_t *tr, char *tmpfname, char *from, char *addrs_buf,
char *last, char *gbl_buf, char **gbl_last, int ndx[],
int *next_ndx, enum NOTIFY_T response_type, trans_info_t *ti,
char *db_admin) {
char *p;
int j;
/* fprintf (dfile, "Enter init_responses()\n");*/
for (p = addrs_buf; p < last; p += strlen (p) + 1) {
/* fprintf (dfile, "init_response () examine addr-(%s)\n", p);*/
if ((j = present_in_list (gbl_buf, *gbl_last, p)) < 0) {
/* fprintf (dfile, "\"%s\" not in list, adding...\n", p);*/
if (add_list_member (tr, p, gbl_buf, gbl_last) < 0) {
return;
}
if ((j = create_notify_file (tr, p, tmpfname)) < 0) {
return;
}
init_response_header (tr, msg_hdl[j].fp, from, p, response_type, ti, db_admin);
ndx[*next_ndx] = j;
(*next_ndx)++;
/*fprintf (dfile, "init_response(): create_notify_file: (file hdl num-(%d))\n", ndx[j]);*/
}
}
}
/*
* JW later must look at length of maint list and break up
* onto additional lines if necessary.
*/
void dump_maint_list (FILE *fp, char *maint_list) {
fprintf (fp, "%s%s", ERROR_TAG, maint_list);
}
void forwarder_response (trace_t *tr, FILE *fin, long obj_pos, trans_info_t *ti,
FILE *msg_fp) {
fprintf (msg_fp, "%s", MSG_SEPERATOR);
if (!strcmp (ti->op, REPLACE_OP))
fprintf (msg_fp, "%s", FORWARD_REPL_MSG);
else if (!strcmp (ti->op, DEL_OP))
fprintf (msg_fp, "%s", FORWARD_DEL_MSG);
else
fprintf (msg_fp, "%s", FORWARD_ADD_MSG);
dump_object_to_file (tr, msg_fp, fin, obj_pos, 10000);
}
void notifier_response (trace_t *tr, FILE *fin, long obj_pos, trans_info_t *ti,
FILE *msg_fp, int max_obj_line_size) {
/*fprintf (dfile, "notifier_response(op-(%s))\n", ti->op);*/
fprintf (msg_fp, "%s", MSG_SEPERATOR);
if (!strcmp (ti->op, REPLACE_OP)) {
fprintf (msg_fp, "%s", PREV_OBJ_MSG);
dump_old_obj (tr, msg_fp, fin, ti->old_obj_fname, max_obj_line_size);
fprintf (msg_fp, "%s", NOTIFY_REPL_MSG);
}
else if (!strcmp (ti->op, DEL_OP)) {
fprintf (msg_fp, "%s", NOTIFY_DEL_MSG);
dump_old_obj (tr, msg_fp, fin, ti->old_obj_fname, max_obj_line_size);
}
else
fprintf (msg_fp, "%s", NOTIFY_ADD_MSG);
if (strcmp (ti->op, DEL_OP))
dump_object_to_file (tr, msg_fp, fin, obj_pos, max_obj_line_size);
}
void sender_response (trace_t *tr, FILE *fin, long obj_pos, trans_info_t *ti,
FILE *msg_fp, irrd_result_t *irrd_res,
char *db_admin, char *tmpfname, int max_obj_line_size) {
char buf[MAXLINE];
/* print the transaction outcome */
if (irrd_res->svr_res & SUCCESS_RESULT) {
fprintf (msg_fp, SENDER_OP_SUCCESS, ti->op, ti->obj_type, ti->obj_key);
trace (NORM, tr, SENDER_OP_SUCCESS, ti->op, ti->obj_type, ti->obj_key);
if (ti->syntax_warns)
dump_object_to_file (tr, msg_fp, fin, obj_pos, max_obj_line_size);
return;
}
if (irrd_res->svr_res & NOOP_RESULT) {
fprintf (msg_fp, SENDER_OP_NOOP, ti->obj_type, ti->obj_key);
trace (NORM, tr, SENDER_OP_NOOP, ti->obj_type, ti->obj_key);
return;
}
if (irrd_res->svr_res & NULL_SUBMISSION) {
fprintf (msg_fp, NULL_SUBMISSION_MSG);
trace (NORM, tr, NULL_SUBMISSION_MSG, ti->op, ti->obj_type, ti->obj_key);
return;
}
if (irrd_res->svr_res & IRRD_ERROR_RESULT) {
fprintf (msg_fp, SENDER_NET_ERROR, ti->op, ti->obj_type, ti->obj_key,
irrd_res->err_msg);
trace (NORM, tr, SENDER_NET_ERROR, ti->op, ti->obj_type, ti->obj_key,
irrd_res->err_msg);
return;
}
if (irrd_res->svr_res & INTERNAL_ERROR_RESULT) {
fprintf (msg_fp, INTERNAL_ERROR, ti->op, ti->obj_type, ti->obj_key,
irrd_res->err_msg);
trace (NORM, tr, INTERNAL_ERROR, ti->op, ti->obj_type, ti->obj_key,
irrd_res->err_msg);
return;
}
if (irrd_res->svr_res & SKIP_RESULT) {
fprintf (msg_fp, SENDER_SKIP_RESULT, ti->op, ti->obj_type, ti->obj_key);
trace (NORM, tr, SENDER_SKIP_RESULT, ti->op, ti->obj_type, ti->obj_key);
return;
}
fprintf (msg_fp, "\n");
fprintf (msg_fp, SENDER_OP_FAILED, ti->op, ti->obj_type, ti->obj_key);
dump_object_to_file (tr, msg_fp, fin, obj_pos, max_obj_line_size);
trace (NORM, tr, SENDER_OP_FAILED, ti->op, ti->obj_type, ti->obj_key);
if (ti->syntax_errors) {
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s\n", ERROR_TAG, "Syntax errors");
return;
}
if (ti->del_no_exist) {
sprintf (buf, "%s%s", ERROR_TAG, DEL_NO_EXIST_MSG);
fprintf (msg_fp, buf, ti->source);
fprintf (msg_fp, "\n");
trace (NORM, tr, buf, ti->source);
return;
}
if (ti->maint_no_exist != NULL) {
fprintf (msg_fp, "%s%s", ERROR_TAG, MAINT_NO_EXIST_MSG);
dump_maint_list (msg_fp, ti->maint_no_exist);
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s", ERROR_TAG, MAINT_NO_EXIST_MSG);
return;
}
if (ti->bad_override) {
sprintf (buf, "%s%s", ERROR_TAG, BAD_OVERRIDE_MSG);
if (ti->override != NULL)
fprintf (msg_fp, buf, ti->override);
else
fprintf (msg_fp, buf, "?");
trace (NORM, tr, BAD_OVERRIDE_MSG);
fprintf (msg_fp, "\n");
return;
}
if (ti->unknown_user) {
fprintf (msg_fp, "%s%s", ERROR_TAG, UNKNOWN_USER_MSG);
return;
}
if (ti->new_mnt_error) {
if (db_admin != NULL) {
fprintf (msg_fp, "%s%s %s", ERROR_TAG, NEW_MNT_ERROR_MSG_2, db_admin);
maint_request (tr, fin, obj_pos, ti, db_admin, tmpfname,
max_obj_line_size);
}
else
fprintf (msg_fp, "%s%s", ERROR_TAG, NEW_MNT_ERROR_MSG);
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s", ERROR_TAG, NEW_MNT_ERROR_MSG);
return;
}
if (ti->del_mnt_error) {
if (db_admin != NULL) {
fprintf (msg_fp, "%s%s %s", ERROR_TAG, DEL_MNT_ERROR_MSG_2, db_admin);
maint_request (tr, fin, obj_pos, ti, db_admin, tmpfname,
max_obj_line_size);
}
else
fprintf (msg_fp, "%s%s", ERROR_TAG, DEL_MNT_ERROR_MSG);
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s", ERROR_TAG, DEL_MNT_ERROR_MSG);
return;
}
if (ti->authfail) {
fprintf (msg_fp, "%s%s", ERROR_TAG, AUTHFAIL_MSG);
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s", ERROR_TAG, AUTHFAIL_MSG);
return;
}
if (ti->otherfail) {
fprintf (msg_fp, "%s%s\n", ERROR_TAG, ti->otherfail);
fprintf (msg_fp, "\n");
trace (NORM, tr, "%s%s\n", ERROR_TAG, ti->otherfail);
return;
}
}
void build_notify_responses (trace_t *tr, char *tmpfname, FILE *fin,
trans_info_t *ti, irrd_result_t *irrd_res,
char *db_admin, int max_obj_line_size,
int null_notification) {
char *p;
int j;
long fpos = ftell (fin);
/* Response to sender */
if (snext == sender_addrs){
init_response (tr, tmpfname, ti->sender_addrs, ti->sender_addrs, ti->snext,
sender_addrs, &snext, sndx, &num_sender, SENDER_RESPONSE, ti,
db_admin);
}
sender_response (tr, fin, fpos, ti, msg_hdl[sndx[0]].fp, irrd_res,
db_admin, tmpfname, max_obj_line_size);
if (null_notification)
return;
/* Response to forwarder's (ie, 'upd-to:'s) */
if (irrd_res->hdr_fields & AUTHFAIL_F) {
init_response (tr, tmpfname, ti->sender_addrs, ti->forward_addrs, ti->fnext,
forward_addrs, &fnext, fndx, &num_forward, FORWARD_RESPONSE, ti,
db_admin);
for (p = ti->forward_addrs; p < ti->fnext; p += strlen (p) + 1) {
if ((j = present_in_list (forward_addrs, fnext, p)) < 0) {
trace (ERROR, tr, "build_notify_responses() \"%s\" not in forward list\n",
p);
continue;
}
trace (NORM, tr, "upd-to: %s\n", p);
forwarder_response (tr, fin, fpos, ti, msg_hdl[fndx[j]].fp);
}
return;
}
/* want to allow for the possiblility of auth fail
* and no maint exist conditions
*/
if (ti->maint_no_exist != NULL)
return;
if (!(irrd_res->svr_res & SUCCESS_RESULT))
return;
/* Response to notifiee's (ie, notify:'s and mnt-nfy:'s).
* If we get here, then the transaction was a success.
*/
init_response (tr, tmpfname, ti->sender_addrs, ti->notify_addrs, ti->nnext,
notify_addrs, &nnext, nndx, &num_notify, NOTIFY_RESPONSE, ti,
db_admin);
for (p = ti->notify_addrs; p < ti->nnext; p += strlen (p) + 1) {
if ((j = present_in_list (notify_addrs, nnext, p)) < 0) {
trace (NORM, tr, "ERROR: build_notify_responses() \"%s\" not in notify list\n", p);
continue;
}
trace (NORM, tr, "notify: %s\n", p);
notifier_response (tr, fin, fpos, ti, msg_hdl[nndx[j]].fp,
max_obj_line_size);
}
}
void send_email (trace_t *tr, char *addrs, char *last, int ndx[],
FILE *log_fp, int null_notification, int dump_stdout) {
char buf[10*MAXLINE], *p;
int i = 0;
for (p = addrs; p < last; p += strlen (p) + 1, i++) {
init_response_footer (msg_hdl[ndx[i]].fp);
if (log_fp != NULL || dump_stdout) {
if (!dump_stdout && log_fp != NULL)
fprintf (log_fp, "\nMail to: \"%s\"\n", p);
else if (dump_stdout && log_fp != NULL)
fputs ("\nTCP reponse: \n", log_fp);
if (fseek (msg_hdl[ndx[i]].fp, 0L, SEEK_SET) == EOF) {
fputs ("ERROR: send_notifies() rewind seek error, skipping...\n", log_fp);
trace (ERROR, tr, "send_notifies() feek error! (%s)\n", strerror(errno));
continue;
}
/* write the sender response to the ack log */
while (fgets (buf, MAXLINE - 1, msg_hdl[ndx[i]].fp) != NULL) {
if (log_fp != NULL)
fputs (buf, log_fp);
if (dump_stdout) /* dump response to STDOUT */
printf ("%s", buf);
trace (TR_TRACE, tr, "%s", buf);
}
}
if (!null_notification && !dump_stdout && strcmp (p, UNKNOWN_USER_NAME)) { /* notify's to email */
fflush (msg_hdl[ndx[i]].fp);
chmod (msg_hdl[ndx[i]].fname, S_IRWXO|S_IRGRP|S_IRWXU);
#ifdef HAVE_SENDMAIL
sprintf (buf, "%s < %s", SENDMAIL_CMD, msg_hdl[ndx[i]].fname);
#elif HAVE_MAIL
sprintf (buf, "%s \"%s\" < %s", MAIL_CMD, p, msg_hdl[ndx[i]].fname);
#else
trace (NORM, tr, "No mail or sendmail found\n");
trace (NORM, tr, "No response sent to (%s)\n", p);
continue;
#endif
trace (NORM, tr, "mail %s\n", p);
if (system (buf) < 0) {
trace (NORM, tr, "ERROR: send_email () \"%s\"\n", strerror (errno));
break;
}
}
}
}
/*
* Send the notifications to the notifiee's.
*/
void send_notifies (trace_t *tr, int null_notification, FILE *ack_fp, int dump_stdout) {
/*fprintf (dfile, "enter send_notifies ()...\n");*/
#if (defined(HAVE_SENDMAIL) || defined(HAVE_MAIL))
send_email (tr, sender_addrs, snext, sndx, ack_fp, null_notification, dump_stdout);
if (null_notification)
return;
send_email (tr, notify_addrs, nnext, nndx, NULL, 0, 0);
send_email (tr, forward_addrs, fnext, fndx, NULL, 0, 0);
#else
trace (NORM, tr, "*****No sendmail or mail binary found on system!***\n");
trace (NORM, tr, "*****No notifications will be sent***\n");
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1