1 /* milter-callback - a sendmail milter to perform variuos sender verifications
2  Copyright (C) 2008  Eugene M. Zheganin, milter-callback@norma.perm.ru
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #ifdef WITH_PGSQL
19 #include <milter-callback.h>
20 #include <commonprocs.h>
21 
22 extern char myHostName[MAXHOSTNAME];
23 struct connList connPool;
24 
25 int
pushHistory(struct mlfiPriv * privData,char * action,char * formattedEmail)26 pushHistory(struct mlfiPriv *privData, char *action, char *formattedEmail){
27 #ifdef WITH_SPF
28     char *pgStatFormat = "insert into history (connectdate, connectfrom, helofrom, relaypresip, mxnum, mxesthatreject, mxesthataccept, mxesoutoforder, mxesthattempfail, gracefuldns, whitelisted, resolvedrelayip, receivinghost, envfrom, action, spf, reverserelay, fakerelay) values('%s','%s','%s','%s',%d,%d,%d,%d,%d,%s,%s,'%s','%s','%s', '%s',%d,%d,%d)";
29 #else
30     char *pgStatFormat = "insert into history (connectdate, connectfrom, helofrom, relaypresip, mxnum, mxesthatreject, mxesthataccept, mxesoutoforder, mxesthattempfail, gracefuldns, whitelisted, resolvedrelayip, receivinghost, envfrom, action, reverserelay, fakerelay) values('%s','%s','%s','%s',%d,%d,%d,%d,%d,%s,%s,'%s','%s','%s', '%s',%d,%d)";
31 #endif
32     char *pgStat = NULL;
33     int wantedSize = 0;
34     int wantedTimeSize = 0;
35     char *curTimePres = NULL;
36     char *curTimePresFormat = "%.2d/%.2d/%d %.2d:%.2d:%.2d";
37     int curYear, curMonth;
38     time_t now;
39     char whitelistedBool[6];
40     char gracefulDNSBool[6];
41     int pgConnId;
42     struct tm *curTime;
43     char tmpLog[MAXLOGLINE];
44 
45     void
46     intToStrBool (int intBool, char *boolContainer, int boolContainerSize, struct mlfiPriv *privData) {
47 	logNow("Entered intToStrBool().", 3, privData);
48 	bzero(boolContainer, boolContainerSize);
49 	if (intBool == 1) {
50     	    strncpy(boolContainer, "true", boolContainerSize);
51 	} else {
52     	    strncpy(boolContainer, "false", boolContainerSize);
53 	}
54     }
55 
56     logNow("Entered pushHistory().", 3, privData);
57 
58     pgConnId = getPgConn();
59 
60     now = time(NULL);
61     curTime = localtime(&now);
62     curYear = curTime->tm_year + 1900;
63     curMonth = curTime->tm_mon + 1;
64     wantedTimeSize = snprintf(curTimePres, 0, curTimePresFormat,
65     		curMonth, curTime->tm_mday, curYear,
66 		curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
67     wantedTimeSize++;
68     curTimePres = malloc(wantedTimeSize);
69     if (curTimePres == NULL) {
70         logNow("Cannot allocate memory.", 0, privData);
71         exit(EXIT_FAILURE);
72     }
73     bzero(curTimePres, wantedTimeSize);
74     snprintf(curTimePres, wantedTimeSize, curTimePresFormat,
75     		curMonth, curTime->tm_mday, curYear,
76     		curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
77     snprintf(tmpLog, MAXLOGLINE, "Aquired current date, %s.", curTimePres);
78     logNow(&tmpLog[0], 3, privData);
79     logNow("Trying to get the size needed for DML statement.", 3, privData);
80     snprintf(tmpLog, MAXLOGLINE, "Sample of milter data [connectfrom]: \"%s\".", privData->mcfi_connectfrom);
81     logNow(&tmpLog[0], 3, privData);
82     snprintf(tmpLog, MAXLOGLINE, "Sample of milter data [helofrom]: \"%s\".", privData->mcfi_helofrom);
83     logNow(&tmpLog[0], 3, privData);
84     intToStrBool(privData->whitelisted, &whitelistedBool[0], 6, privData);
85     intToStrBool(privData->gracefulDNS, &gracefulDNSBool[0], 6, privData);
86     wantedSize = snprintf(pgStat, 0, pgStatFormat,
87     			curTimePres, privData->mcfi_connectfrom,
88     			privData->mcfi_helofrom, privData -> af == AF_INET ? privData->relayPresIP : privData->relayPresIP6,
89 			privData->MXesNum, privData->MXesThatReject, privData->MXesThatAccept,
90 			privData->MXesOutOfOrder, privData->MXesThatTempfail, gracefulDNSBool,
91 #ifdef WITH_SPF
92     			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> SPFResult, privData -> reverseRes, privData -> fakeRes);
93 #else
94 			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> reverseRes, privData -> fakeRes);
95 #endif
96     wantedSize++;
97     snprintf(tmpLog, MAXLOGLINE, "Got the size needed for DML statement, it's %d.", wantedSize);
98     logNow(&tmpLog[0], 3, privData);
99     pgStat = malloc(wantedSize);
100     bzero(pgStat, wantedSize);
101     if (pgStat == NULL) {
102         logNow("Cannot allocate memory.", 0, privData);
103         exit(EXIT_FAILURE);
104     }
105     snprintf(pgStat, wantedSize, pgStatFormat,
106     			curTimePres, privData->mcfi_connectfrom,
107     			privData->mcfi_helofrom, privData -> af == AF_INET ? privData->relayPresIP : privData->relayPresIP6,
108 			privData->MXesNum, privData->MXesThatReject, privData->MXesThatAccept,
109 			privData->MXesOutOfOrder, privData->MXesThatTempfail, gracefulDNSBool,
110 #ifdef WITH_SPF
111     			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> SPFResult, privData -> reverseRes, privData -> fakeRes);
112 #else
113 			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> reverseRes, privData -> fakeRes);
114 #endif
115     snprintf(tmpLog, MAXLOGLINE, "Got the DML statement for insert: \"%s\".", pgStat);
116     logNow(&tmpLog[0], 3, privData);
117 
118     connPool.pgResArr[pgConnId] = PQexec(connPool.pgConnArr[pgConnId], pgStat);
119     if (PQresultStatus(connPool.pgResArr[pgConnId]) != PGRES_COMMAND_OK){
120         snprintf(tmpLog, MAXLOGLINE, "INSERT command failed: %s", PQerrorMessage(connPool.pgConnArr[pgConnId]));
121         logNow(&tmpLog[0], 0, privData);
122         snprintf(tmpLog, MAXLOGLINE, "The result status is: %s",PQresStatus(PQresultStatus(connPool.pgResArr[pgConnId])));
123         logNow(&tmpLog[0], 0, privData);
124         PQclear(connPool.pgResArr[pgConnId]);
125         return 1;
126     }
127     privData->SQLlogged = 1;
128     PQclear(connPool.pgResArr[pgConnId]);
129     /* freeing lock */
130     unlockPgConn(pgConnId);
131 
132     logNow("Trying to free pgStat in pushHistory().", 3, privData);
133     free(pgStat);
134     logNow("Trying to free curTimePres in pushHistory().", 3, privData);
135     free(curTimePres);
136     return 0;
137 }
138 #endif
139