/* * $Id: notify_msgs.c,v 1.6 2002/10/17 20:25:56 ljb Exp $ */ #include #include #include #include #include #include #include #include #include #include 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 }