How can I configure exim to run a script for each e-mail - smtp

I need to run a shell script under exim that can read each incoming e-mail, optionally rewrites them and then continues sending the email.
And ideal solution would be analogous to UNIX pipes:
cat *incoming email* | **some-script.sh** | *back to exim processing*
I want the script to run very early, so that I can for example change the destination address.
Is this possible with Exim, and how?

You can create the router that use pipe transport with your script on the other side of pipe:
begin routers
preprocessor:
driver = accept
condition = if{ !eq{$header_X-Preproceeded}{yes}}
transport = myscript
no_more
. . . . .
begin transports
myscript:
driver = pipe
user = scriptowner
command = /path/to/script --opt1 --opt2
If incoming message does not have X-Preproceeded header or its value doesn't set to yes then message is passed to the myscript transport. That is performed via piping source | script and all the message is passed to the script's stdin. After proceeding if you want to return proceeded message to the exim, you should add the x-Preproceeded: yes header to the message to prevent it to be routed to the next lap. Then you have to submit it via sendmail command.
#!/bin/sh
. . . .
mandatory_empty_line = ''
cat << ENDOFTEXT | /usr/sbin/sendmail -t
$headers
X_Preproceeded: yes
$mandatory_empty_line
$message_body
ENDOFTEXT
Keep in mind that effective user running script should be added to the trusted users by exim's config to allow sending from arbitrary address. Otherwise exim will replace any sender's address by scriptowner#mydomain.tld

Related

Lines with common words in outputs of 2 scripts

I need to run two linux shell scripts and get lines from the second script that contain same words as lines in the output from the first (not the whole line is the same). For example:
Script #1 output:
Router 1: Ip address 10.0.0.1
Router 2: Ip address 10.0.1.1
Router 3: Ip address 10.0.2.1
Script #2 output:
Router 1: Model: Cisco 2960
Router 2: Model: Juniper MX960
Router 5: Model: Huwei S3300
So, finally I need a list of routers that are present in both outputs, but only lines from the second script, i.e. lines with model.
Considering the above two script output is stored/redirected to tmp1 and tmp2 respectively.
Below script will output the common Router X present in both the files.
#!/bin/bash
tmp1="$1"
tmp2="$2"
while read -r line
do
routerName=$(echo "$line" | cut -d ":" -f 1)
if grep -q "$routerName" "$tmp2"
then
# Instead of printing you can add any logic
echo $routerName
fi
done < "$tmp1"
save the above script as filename.sh and pass the arguments
./filename.sh tmpScript1output_file tmpScript2output_file

Perl script not processing html form correctly

I am using a formmail Perl script (Matt's script archive) from London Perl mongers to process several web forms I created. I have the script in the cgi-bin and it seems to be working; however the email output is just a long list with no formatting. I am working on the Perl script in Notepad and I am on a windows computer. I only did a few modifications to personalized the script for my client. I barely now anything about Perl. I have used this script before; but I don't know why the output is a long list with no formatting. I uploaded the script through the server's cpanel as I can't get it to ftp with my current ftp program. The server they are using is old and apparently insecure. I don't know if that makes a difference. How can I get the output to resemble a regular email and not just a list.
the email looks like this below:
Below is the result of your feedback form. It was submitted by
hello () on Thursday, August 13, 2015 at 17:35:02
---------------------------------------------------------------------------
todayDate: 08/13/2015
ssn: 123456789
refer: self
birthdate: 08/02/2015
age: 32
gender1: Female
religion: yes
ethnicity: ethnic
address: 1234
city: big
state: CA
zip: 12345
homephone: 5105105100 32135684
workphone: 5105105100
cellphone: 5105105100
creditcard: na
nameOnCard: na
Occupation: work
employerName: hello there
employerAddress: 1234 street
employerCity: all city
employerState: CA
employerZip: 12345
education: BA Degree
inSchool2: No
marriedOrcommit: Yes
howLong: forever
namePartner: honey
occupationPartner: working hard
youPrev: none
I am using the following Perl script:
#!/usr/bin/perl -wT
#
# NMS FormMail Version 3.14c1
#
use strict;
use vars qw(
$DEBUGGING $emulate_matts_code $secure %more_config
$allow_empty_ref $max_recipients $mailprog #referers
#allow_mail_to #recipients %recipient_alias
#valid_ENV $date_fmt $style $send_confirmation_mail
$confirmation_text $locale $charset $no_content
$double_spacing $wrap_text $wrap_style $postmaster
$address_style
);
# PROGRAM INFORMATION
# -------------------
# FormMail.pl Version 3.14c1
#
# This program is licensed in the same way as Perl
# itself. You are free to choose between the GNU Public
# License <http://www.gnu.org/licenses/gpl.html> or
# the Artistic License
# <http://www.perl.com/pub/a/language/misc/Artistic.html>
#
# For help on configuration or installation see the
# README file or the POD documentation at the end of
# this file.
# USER CONFIGURATION SECTION
# --------------------------
# Modify these to your own settings. You might have to
# contact your system administrator if you do not run
# your own web server. If the purpose of these
# parameters seems unclear, please see the README file.
#
BEGIN
{
$DEBUGGING = 1;
$emulate_matts_code= 0;
$secure = 1;
$allow_empty_ref = 1;
$max_recipients = 2;
$mailprog = '/usr/lib/sendmail -oi -t';
$postmaster = 'sylviavanhorn#gmail.com';
#referers = qw(expressivehearts.com localhost);
#allow_mail_to = qw(sylviavanhorn#gmail.com localhost);
#recipients = ();
%recipient_alias = ();
#valid_ENV = qw(REMOTE_HOST REMOTE_ADDR REMOTE_USER HTTP_USER_AGENT);
$locale = '';
$charset = 'iso-8859-1';
$date_fmt = '%A, %B %d, %Y at %H:%M:%S';
$style = '/public/css/jane.css';
$no_content = 0;
$double_spacing = 0;
$wrap_text = 0;
$wrap_style = 1;
$address_style = 0;
$send_confirmation_mail = 0;
$confirmation_text = <<'END_OF_CONFIRMATION';
From: expressivehearts#gmail.com
Subject: New Client Forms Submission
Thank you for your submission.
END_OF_CONFIRMATION
# You may need to uncomment the line below and adjust the path.
# use lib './lib';
# USER CUSTOMISATION SECTION
# --------------------------
# Place any custom code here
# Email Header
print MAIL "To: $postmaster\n";
print MAIL "From: $realname\n";
print MAIL "Subject: $subject\n\n";
print MAIL "Content-type: text/html\n";
# USER CUSTOMISATION << END >>
# ----------------------------
# (no user serviceable parts beyond here)
}
#
# The code below consists of module source inlined into this
# script to make it a standalone CGI.
Please note: I only pasted a part of the Perl script as it is very long; it is supposed to be a standalone script.
The title to your question is "Perl script not processing html form correctly". I'm not sure what that means. In what way is formmail not processing the form correctly? It is taking all your form inputs and sending an email that contains all of the information. That is what it it supposed to do. It is working exactly as expected. It is not correct to say that it is not working correctly.
As simbabque says in his comment, this stuff really is antique and shouldn't be used any more. And I speak as the person who started the nms project. It's really only still there because otherwise there's a danger that people would gravitate back to Matt's scripts (Which are even worse!)
The original intention with the nms programs was that they reproduced what Matt's scripts did. So, yes, Formmail produces an unformatted list of its inputs. That's how things worked back then. I'm not really sure why anyone would need anything else.
If you really want formatted output from a 15-year-old CGI program, then look at the TFMail program from nms (http://nms-cgi.sourceforge.net/scripts.shtml) but, really, there are far better ways to do this these days.

EXPECT Script for Cisco / Juniper Config Backup

Firstly I am asking this as a beginner in scripting, currently I have an expect script which automatically logs in to predefined Cisco devices and runs certain commands, I would like to update my script so that this same script can also backup Juniper devices.
Ideally what I would like the script to do is (in pseudo code)
login / send credentials
expect prompt
send command "show version"
if output contains "JUNOS" then
send command 1
send command 2
send command 3
otherwise if output contains "Cisco" then
send command 1
send command 2
send command 3
Im sorry if this has been asked before, but I have tried searching and searching and couldn't find an answer if anyone can assist with this I would really appreciate it. I have also included my current expect script for your reference (this script gets called by a BASH Script)
set timeout 5
set hostname [lindex $argv 0]
set username "user"
set password "pass"
spawn ssh $username#$hostname
expect "Password:"
send "$password\n"
expect "#" {
send "terminal length 0\n"
send "show running-config\n"
expect "end\r"
send "\n"
send "exit\n"
}
---- UPDATE ---
Thanks for your input Dinesh - I have updated my script to include what you provided (as below)
set timeout 5
set hostname [lindex $argv 0]
set username "user"
set password "pass"
set prompt "(>|#|\\\$) $"
spawn ssh $username#$hostname
expect "*assword:"
send $password\r
send \r
expect -re $prompt {
send "show version\r"
expect -re $prompt
expect *;
set output $expect_out(buffer);
#Basic string check logic with Tcl
if { [string first "JUNOS" $output ]!=-1 } {
send "show configuration | display set | no-more"
expect -re $prompt
send "exit\r"
} else {
send "terminal length 0\r"
expect -re $prompt
send "show run\r"
expect "end"
send \r
expect -re $prompt
send "exit\r"
}
}
However when i run this script the issue I have is that the output of the "show version" doesn't seem to be matching my "string check" and the script therefore ignores the "if" statement and proceeds with the "else" statement.
The output of the "show version" command is below - what will I need to modify so that the "JUNOS" string gets matched?
user#host> show version
Hostname: host
Model: srx240h
JUNOS Software Release [11.4R7.5]
--- EDIT 2: Output from the script
05c4rw#testpc:~/script$ ./ssh.sh
spawn ssh user#juniperhost
## LOGIN BANNER - Removed for brevity
user#juniperhost's password:
--- JUNOS 11.4R7.5 built 2013-03-01 11:40:03 UTC
user#juniperhost> show version
Hostname: juniperhost
Model: srx240h
JUNOS Software Release [11.4R7.5]
user#juniperhost> show configuration | display set | no-more
set version 11.4R7.5
## *** OUTPUT REMOVED FOR BREVITY / PRIVACY ***
## *** END OF OUTPUT from previous command
user#juniper> spawn ssh user#ciscohost
password:
## LOGIN BANNER - removed for brevitiy
ciscohost#05c4rw#testpc:~/script$
set timeout 5
set hostname [lindex $argv 0]
set username "user"
set password "pass"
spawn ssh $username#$hostname
expect "Password:"
send "$password\r"
expect "#" {
send "terminal length 0\r"
expect "#"
# This is to clean up the previous expect_out(buffer) content
# So that, we can get the exact output what we need.
expect *;
send "show running-config\r"
expect "end"
#Now, the content of 'expect_out(buffer)' has the whole 'show run' output
set output $expect_out(buffer);
#Basic string check logic with Tcl
if { [string first "JUNOS" $output ]!=-1 } {
# Apply your logic here
# send "command1"
# expect "#"
} else {
# Same as above
# I assume, there are 2 possibilities. So, keeping 'else' part alone.
# Have 'else if', if you have more than 2.
}
}
Notice that each line sent by the script is terminated with \r. This denotes a return character and is exactly what you would press if you entered these lines at the shell, so that is exactly what Expect has to send. It is a common mistake to terminate send commands to a process followed by \n. In this context, \n denotes a linefeed character. You do not interactively end lines with a linefeed. So Expect must not either. So, always use \r.
You can have a look at here if you are interested to know more about the why you need expect *. (which is a separate story)
I can see that there are some commands used only with send in your example. Basically, expect will work with two feasible commands such as send and expect. In this case, if send is used, then it is mandatory to have expect (in most of the cases) afterwards. (while the vice-versa is not required to be mandatory)
This is because without that we will be missing out what is happening in the spawned process as expect will assume that you simply need to send one string value and not expecting anything else from the session.
This might not be what you were looking for but thought I will post it just in case.
You might want to look into something like Rancid instead of having those scripts. Rancid will not only backup your device configs, it will also provide you with a diff on the devices it is managing at pre-defined intervals (for e.g if you set the interval to 15 mins, rancid will login to your devices every 15 mins grab the configs, back them up and do a diff with the previous version and show you the diff)

Using Expect, how do I extract certain value from a file and input into a variable of an Expect script

I have two files. One is called bgp_ip.log and the other is an expect script called bgp.sh
bgp_ip.log contains just one IP address which was input into the file by another script called getip.sh which is working fine.
Now I'm trying to figure out how to get bgp.sh to extract the IP address in bgp_ip.log and place it into a variable container. In this script context, the variable container is called $BGP_IP as shown in the script below:
The reason for having this variable so that the script below is able to execute the Router BGP commands based on the IP address obtained from bgp_ip.log
#!/usr/bin/expect
set username "testaccount"
set password "testaccount"
set hostname "R-KANSAS-01"
set BGP_IP "?????" <<<< I'm not sure how can I extract the IP from bgp_ip.log and place into this variable
spawn telnet "$hostname"
expect "login: " {
send "$username\n"
expect "Password: "
send "$password\n"
expect "> "
send "show bgp summary instance $BGP_IP\n"
log_file "R-KANSAN-01_temp.log"
log_user 1
expect "#"
send "exit\n"; exit 0
interact
}
Any help is appreciated..Thanks.
You need to read the file and get the data from it
set file_name "bgp_ip.log"
set fp [open $file_name "r"]
set BGP_IP [read $fp]
close $fp
The variable BGP_IP will hold the IP address. I am assuming that the file contains only the IP address and nothing else.
If not, then you need regexp to get it.
Just add this code before spawning telnet in your code.

IP address of form submitter (remote IP address) using Perl and HTML::Mason

I am using HTML::Mason to serve a web page containing a form. When the form is filled and submitted, I want to know the IP address of the remote client.
I tried printing $r->headers_in but I get
Apache2::Request=SCALAR(0x1961ba0)->headers_in
am I using the wrong argument?
For a CGI application, the remote IP address is in $ENV{REMOTE_ADDR}.
If you are using mod_perl, then the equivalent value is at $r->connection->remote_ip where $r is your Apache2::Request object.
The output you show will be produced if you have the method call in double quotes, like
print "$r->headers_in\n"
it will work properly if you remove the quotes
print $r->headers_in, "\n"
The $r->headers_in method returns an APR::Table object. You can dump the contents of this using the do method and a suitable subroutine (which must return 1 for the iteration through the table to continue) like this:
my $table = $r->headers_in;
$table->do(sub {
printf "%s: %s\n", #_;
1;
});