OpenSDE Packages Database (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9462 lines
285 KiB

  1. # --- SDE-COPYRIGHT-NOTE-BEGIN ---
  2. # This copyright note is auto-generated by ./scripts/Create-CopyPatch.
  3. #
  4. # Filename: package/.../qmail/qmail-dkim.diff
  5. # Copyright (C) 2009 The OpenSDE Project
  6. #
  7. # More information can be found in the files COPYING and README.
  8. #
  9. # This patch file is dual-licensed. It is available under the license the
  10. # patched project is licensed under, as long as it is an OpenSource license
  11. # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
  12. # of the GNU General Public License as published by the Free Software
  13. # Foundation; either version 2 of the License, or (at your option) any later
  14. # version.
  15. # --- SDE-COPYRIGHT-NOTE-END ---
  16. This patch is an adaptation of the work of Manvendra Bhangui <mbhangui@gmail.com>
  17. http://downloads.sourceforge.net/indimail/dkim-netqmail-1.06.patch-1.0.gz?use_mirror=osdn
  18. --- qmail-1.03.orig/hier.c 2009-10-15 20:38:23.426352000 +0300
  19. +++ qmail-1.03/hier.c 2009-10-16 00:11:06.477232936 +0300
  20. @@ -188,10 +188,15 @@
  21. c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700);
  22. c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
  23. c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711);
  24. + c(auto_qmail,"bin","spawn-filter",auto_uido,auto_gidq,0711);
  25. + c(auto_qmail,"bin","dk-filter",auto_uido,auto_gidq,0555);
  26. c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711);
  27. c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
  28. c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
  29. c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
  30. + c(auto_qmail,"bin","qmail-dk",auto_uidq,auto_gidq,0711);
  31. + c(auto_qmail,"bin","qmail-dkim",auto_uidq,auto_gidq,0711);
  32. + c(auto_qmail,"bin","dkimtest",auto_uidq,auto_gidq,0711);
  33. #ifdef EXTERNAL_TODO
  34. c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
  35. #endif
  36. @@ -301,6 +306,14 @@
  37. c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
  38. c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
  39. + c(auto_qmail,"man/man8","qmail-dk.8",auto_uido,auto_gidq,0644);
  40. + c(auto_qmail,"man/cat8","qmail-dk.0",auto_uido,auto_gidq,0644);
  41. + c(auto_qmail,"man/man8","qmail-dkim.8",auto_uido,auto_gidq,0644);
  42. + c(auto_qmail,"man/cat8","qmail-dkim.0",auto_uido,auto_gidq,0644);
  43. + c(auto_qmail,"man/man8","dk-filter.8",auto_uido,auto_gidq,0644);
  44. + c(auto_qmail,"man/cat8","dk-filter.0",auto_uido,auto_gidq,0644);
  45. + c(auto_qmail,"man/man8","spawn-filter.8",auto_uido,auto_gidq,0644);
  46. + c(auto_qmail,"man/cat8","spawn-filter.0",auto_uido,auto_gidq,0644);
  47. c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
  48. c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
  49. c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
  50. diff -Naur qmail-1.03.org/dk-filter.9 qmail-1.03/dk-filter.9
  51. --- qmail-1.03.org/dk-filter.9 1970-01-01 05:30:00.000000000 +0530
  52. +++ qmail-1.03/dk-filter.9 2009-04-21 11:19:07.000000000 +0530
  53. @@ -0,0 +1,107 @@
  54. +.TH dk-filter 8
  55. +.SH NAME
  56. +dk-filter \- sign/verify using DK/DKIM (SSP/ADSP optionally) and deliver a mail message for delivery
  57. +.SH SYNOPSIS
  58. +.B FILTERARGS=QMAILHOME/bin/dk-filter
  59. +.SH DESCRIPTION
  60. +.B dk-filter
  61. +is a qfilter which can be set as a filter for
  62. +.BR spawn-filter(8) .
  63. +The filter can be set either as
  64. +.B FILTERARGS
  65. +or in the control file
  66. +.BR filterargs .
  67. +
  68. +.B dk-filter
  69. +supports DK/DKIM signing and verification and can optionally use
  70. +.B Sender Signing Practice (SSP)
  71. +or
  72. +.B Author Domain Signing Practice.
  73. +It uses the libdkim and OpenSSL libraries. To sign a message, set the
  74. +.B DKIMSIGN
  75. +or
  76. +.B DKSIGIN
  77. +environment variables to the pathname of the private key that will be
  78. +used to sign the message. If there is a % character in the environment
  79. +variable, it is removed and replaced by the domain name in the From: header.
  80. +If, after substituting the %, that file does not exist, the message will not be signed.
  81. +If there is no % and the file does not exist, the message will be rejected with error 35.
  82. +The selector (s=) will be taken from the basename of the file.
  83. +The private key should be created by
  84. +.BR dknewkey(8) .
  85. +
  86. +You can set various DK options in getopt style, by setting the environment variable DKSIGNOPTIONS
  87. + b <advice_length> Length of Advice
  88. + c <canonicalization> simple, nofws
  89. + s <privkeyfile>
  90. + h show headers included
  91. + r Skip Duplicate Headers
  92. +.EX
  93. + DKSIGNOPTIONS="-h -r -c nofws"
  94. + sets the h= tag, skips duplicate headers and sets nofws canonicalization
  95. +.EE
  96. +
  97. +You can set various DKIM options in getopt style, by setting the environment variable DKIMSIGNOPTIONS
  98. +
  99. + b <standard> 1 - allman, 2 - ietf or 3 - both
  100. + c <canonicalization> r for relaxed [DEFAULT], s - simple,
  101. + t relaxed/simple, u - simple/relaxed
  102. + l include body length tag
  103. + q include query method tag;
  104. + t include a timestamp tag
  105. + h
  106. + i <identity> the identity, if not provided it will not be included
  107. + x <expire_time> the expire time in seconds since epoch
  108. + ( DEFAULT = current time + 604800)
  109. + if set to - then it will not be included
  110. + z <hash> 1 for sha1, 2 for sha256, 3 for both
  111. + s <privkeyfile>
  112. + y <selector>
  113. +
  114. +.EX
  115. + DKIMSIGNOPTIONS="-b 1 -c r -q"
  116. + sets allman standard, with relaxed canonicalization and include query method tag
  117. +.EE
  118. +
  119. +.B dk-filter
  120. +uses the domain found in the Sender: header to set the domain tag. If not it uses the From: header. You can override this by
  121. +setting
  122. +.B DKIMDOMAIN
  123. +environment variable.
  124. +.B DKIMDOMAIN
  125. +can be set to an email address or a domain (without the at sign).
  126. +To verify a message, set the
  127. +.B DKIMVERIFY
  128. +or
  129. +.B DKVERIFY
  130. +environment variables
  131. +.B dk-filter
  132. +always inserts the
  133. +.B DKIM-Status
  134. +or
  135. +.B DomainKey-Status
  136. +header, so that messages can be
  137. +rejected later at delivery time, or in the mail reader. In that case you may set
  138. +.B DKIMVERIFY
  139. +or
  140. +.B DKVERIFY
  141. +to an empty string.
  142. +.B dk-filter
  143. +does not use any signing practice byd default. You can override this by setting the SIGN_PRACTICE to ssp or adsp (lowercase).
  144. +
  145. +.SH "EXIT CODES"
  146. +0 for success, non-zero failure
  147. +
  148. +.SH "SEE ALSO"
  149. +dknewkey(8),
  150. +dktest(8),
  151. +dkim(8),
  152. +spawn-filter(8)
  153. +
  154. +.SH "AUTHORS"
  155. +
  156. +Manvendra Bhangui.
  157. +.SH PROBLEMS
  158. +Problems with
  159. +.B dk-filter
  160. +should be forwarded to "Manvendra Bhangui" <mbhangui@gmail.com>
  161. diff -Naur qmail-1.03.org/dk-filter.sh qmail-1.03/dk-filter.sh
  162. --- qmail-1.03.org/dk-filter.sh 1970-01-01 05:30:00.000000000 +0530
  163. +++ qmail-1.03/dk-filter.sh 2009-04-21 21:35:56.000000000 +0530
  164. @@ -0,0 +1,247 @@
  165. +#
  166. +# $Log: dk-filter.sh,v $
  167. +# Revision 1.8 2009-04-21 20:42:44+05:30 Cprogrammer
  168. +# added check for dktest, dkim executables
  169. +#
  170. +# Revision 1.7 2009-04-20 10:06:58+05:30 Cprogrammer
  171. +# added DKSIGNOPTS
  172. +#
  173. +# Revision 1.6 2009-04-19 13:38:24+05:30 Cprogrammer
  174. +# added full set of dkim options
  175. +# replaced indimail/bin/echo with echo 1>&2
  176. +#
  177. +# Revision 1.5 2009-04-06 16:37:50+05:30 Cprogrammer
  178. +# added SIGN_PRACTICE
  179. +# use ietf standard insted of allman so that Yahoo verification does not fail
  180. +#
  181. +# Revision 1.4 2009-04-03 14:39:00+05:30 Cprogrammer
  182. +# added return status
  183. +#
  184. +# Revision 1.3 2009-04-03 08:55:29+05:30 Cprogrammer
  185. +# print error messages to stderr
  186. +#
  187. +# Revision 1.2 2009-04-02 20:36:25+05:30 Cprogrammer
  188. +# added -h option to dktest
  189. +# added -x - option to dkim
  190. +#
  191. +# Revision 1.1 2009-04-02 14:52:27+05:30 Cprogrammer
  192. +# Initial revision
  193. +#
  194. +#
  195. +if [ -z $QMAILREMOTE -a -z $QMAILLOCAL ]; then
  196. + echo "dk-filter should be run by spawn-filter" 1>&2
  197. + exit 1
  198. +fi
  199. +if [ -z "$DKSIGN" -a -z "$DKIMSIGN" -a -z "$DKVERIFY" -a -z "$DKIMVERIFY" ] ; then
  200. + echo "Must provide at least one of DKSIGN, DKIMSIGN, DKVERIFY, DKIMVERIFY" 1>&2
  201. + exit 1
  202. +fi
  203. +dksign=0
  204. +dkimsign=0
  205. +dkverify=0
  206. +dkimverify=0
  207. +if [ ! -z $DKSIGN ] ; then
  208. + if [ ! -f QMAILHOME/bin/dktest ] ; then
  209. + echo "QMAILHOME/bin/dktest: No such file or directory" 1>&2
  210. + exit 1
  211. + fi
  212. + dksign=1
  213. + if [ ! " $DOMAIN" = " " ] ; then
  214. + # replace '%' in filename with domain
  215. + dkkeyfn=`echo $DKSIGN | sed s{%{$DOMAIN{g`
  216. + else
  217. + dkkeyfn=$DKSIGN
  218. + fi
  219. + dkselector=`basename $dkkeyfn`
  220. +fi
  221. +if [ ! -z $DKIMSIGN ] ; then
  222. + if [ ! -f QMAILHOME/bin/dkimtest ] ; then
  223. + echo "QMAILHOME/bin/dkimtest: No such file or directory" 1>&2
  224. + exit 1
  225. + fi
  226. + dkimsign=1
  227. + if [ ! " $DOMAIN" = " " ] ; then
  228. + # replace '%' in filename with domain
  229. + dkimkeyfn=`echo $DKIMSIGN | sed s{%{$DOMAIN{g`
  230. + else
  231. + dkimkeyfn=$DKIMSIGN
  232. + fi
  233. + dkimselector=`basename $dkimkeyfn`
  234. +fi
  235. +if [ ! -z $DKVERIFY ] ; then
  236. + if [ ! -f QMAILHOME/bin/dktest ] ; then
  237. + echo "QMAILHOME/bin/dktest: No such file or directory" 1>&2
  238. + exit 1
  239. + fi
  240. + dkverify=1
  241. +fi
  242. +if [ ! -z $DKIMVERIFY ] ; then
  243. + if [ ! -f QMAILHOME/bin/dkimtest ] ; then
  244. + echo "QMAILHOME/bin/dkimtest: No such file or directory" 1>&2
  245. + exit 1
  246. + fi
  247. + dkimverify=1
  248. +fi
  249. +cat > /tmp/dk.$$
  250. +if [ $dksign -eq 1 ] ; then
  251. + #dktest: [-f] [-b advice_length] [-c nofws|simple] [-v|-s selector] [-h] [-t#] [-r] [-T][-d dnsrecord]
  252. + # DKSIGNOPTIONS="-z 1 -b 2 -x - -y $dkimselector -s $dkimkeyfn"
  253. + set -- `getopt hrb:c:s: $DKSIGNOPTIONS`
  254. + dkopts="QMAILHOME/bin/dktest"
  255. + sopt=0
  256. + while [ $1 != -- ]
  257. + do
  258. + case $1 in
  259. + -h)
  260. + dkopts="$dkopts -h"
  261. + ;;
  262. + -r)
  263. + dkopts="$dkopts -r"
  264. + ;;
  265. +
  266. + -b)
  267. + dkopts="$dkopts -b $2"
  268. + shift
  269. + ;;
  270. +
  271. + -c)
  272. + dkopts="$dkopts -c $2"
  273. + shift
  274. + ;;
  275. +
  276. + -s)
  277. + sopt=1
  278. + dkopts="$dkopts -s $2"
  279. + shift
  280. + ;;
  281. + esac
  282. + shift # next flag
  283. + done
  284. + if [ $sopt -eq 0 ] ; then
  285. + dkopts="$dkopts -s $dkkeyfn"
  286. + fi
  287. + exec 0</tmp/dk.$$
  288. + #QMAILHOME/bin/dktest -h -s $dkkeyfn
  289. + eval $dkopts
  290. + if [ $? -ne 0 ] ; then
  291. + /bin/rm -f /tmp/dk.$$
  292. + exit 1
  293. + fi
  294. +fi
  295. +if [ $dkimsign -eq 1 ] ; then
  296. + # DKIMSIGNOPTIONS="-z 1 -b 2 -x - -y $dkimselector -s $dkimkeyfn"
  297. + set -- `getopt lqthb:c:d:i:x:z:y:s: $DKIMSIGNOPTIONS`
  298. + bopt=0
  299. + xopt=0
  300. + zopt=0
  301. + yopt=0
  302. + sopt=0
  303. + dkimopts="QMAILHOME/bin/dkimtest"
  304. + while [ $1 != -- ]
  305. + do
  306. + case $1 in
  307. + -l)
  308. + dkimopts="$dkimopts -l"
  309. + ;;
  310. + -q)
  311. + dkimopts="$dkimopts -q"
  312. + ;;
  313. + -t)
  314. + dkimopts="$dkimopts -t"
  315. + ;;
  316. + -h)
  317. + dkimopts="$dkimopts -h"
  318. + ;;
  319. +
  320. + -b)
  321. + bopt=1
  322. + dkimopts="$dkimopts -b $2"
  323. + shift
  324. + ;;
  325. +
  326. + -c)
  327. + dkimopts="$dkimopts -c $2"
  328. + shift
  329. + ;;
  330. +
  331. + -i)
  332. + dkimopts="$dkimopts -i $2"
  333. + shift
  334. + ;;
  335. +
  336. + -x)
  337. + xopt=1
  338. + dkimopts="$dkimopts -x $2"
  339. + shift
  340. + ;;
  341. +
  342. + -z)
  343. + zopt=1
  344. + dkimopts="$dkimopts -z $2"
  345. + shift
  346. + ;;
  347. +
  348. + -y)
  349. + yopt=1
  350. + dkimopts="$dkimopts -y $2"
  351. + shift
  352. + ;;
  353. +
  354. + -s)
  355. + sopt=1
  356. + dkimopts="$dkimopts -s $2"
  357. + shift
  358. + ;;
  359. + esac
  360. + shift # next flag
  361. + done
  362. + if [ $zopt -eq 0 ] ; then
  363. + dkimopts="$dkimopts -z 1"
  364. + fi
  365. + if [ $bopt -eq 0 ] ; then
  366. + dkimopts="$dkimopts -b 2"
  367. + fi
  368. + if [ $xopt -eq 0 ] ; then
  369. + dkimopts="$dkimopts -x -"
  370. + fi
  371. + if [ $yopt -eq 0 ] ; then
  372. + dkimopts="$dkimopts -y $dkimselector"
  373. + fi
  374. + if [ $sopt -eq 0 ] ; then
  375. + dkimopts="$dkimopts -s $dkimkeyfn"
  376. + fi
  377. + exec 0</tmp/dk.$$
  378. + eval $dkimopts
  379. + if [ $? -ne 0 ] ; then
  380. + /bin/rm -f /tmp/dk.$$
  381. + exit 1
  382. + fi
  383. +fi
  384. +if [ $dkimverify -eq 1 ] ; then
  385. + practice=$SIGN_PRACTICE
  386. + if [ " $practice" = " " ] ; then
  387. + practice=0
  388. + elif [ " $practice" = " ssp" ] ; then
  389. + practice=1
  390. + elif [ " $practice" = " adsp" ] ; then
  391. + practice=2
  392. + fi
  393. + exec 0</tmp/dk.$$
  394. + QMAILHOME/bin/dkimtest -p $practice -v
  395. + if [ $? -ne 0 ] ; then
  396. + /bin/rm -f /tmp/dk.$$
  397. + exit 1
  398. + fi
  399. +fi
  400. +if [ $dkverify -eq 1 ] ; then
  401. + exec 0</tmp/dk.$$
  402. + QMAILHOME/bin/dktest -v
  403. + if [ $? -ne 0 ] ; then
  404. + /bin/rm -f /tmp/dk.$$
  405. + exit 1
  406. + fi
  407. +fi
  408. +exec 0</tmp/dk.$$
  409. +/bin/rm -f /tmp/dk.$$
  410. +cat
  411. +exit $?
  412. diff -Naur qmail-1.03.org/dkimbase.cpp qmail-1.03/dkimbase.cpp
  413. --- qmail-1.03.org/dkimbase.cpp 1970-01-01 05:30:00.000000000 +0530
  414. +++ qmail-1.03/dkimbase.cpp 2009-04-21 11:19:07.000000000 +0530
  415. @@ -0,0 +1,333 @@
  416. +/*
  417. + * $Log: dkimbase.cpp,v $
  418. + * Revision 1.3 2009-03-26 15:10:32+05:30 Cprogrammer
  419. + * fixed indentation
  420. + *
  421. + * Revision 1.2 2009-03-25 08:37:27+05:30 Cprogrammer
  422. + * fixed indentation
  423. + *
  424. + * Revision 1.1 2009-03-21 08:43:08+05:30 Cprogrammer
  425. + * Initial revision
  426. + *
  427. + *
  428. + * Copyright 2005 Alt-N Technologies, Ltd.
  429. + *
  430. + * Licensed under the Apache License, Version 2.0 (the "License");
  431. + * you may not use this file except in compliance with the License.
  432. + * You may obtain a copy of the License at
  433. + *
  434. + * http://www.apache.org/licenses/LICENSE-2.0
  435. + *
  436. + * This code incorporates intellectual property owned by Yahoo! and licensed
  437. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  438. + *
  439. + * Unless required by applicable law or agreed to in writing, software
  440. + * distributed under the License is distributed on an "AS IS" BASIS,
  441. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  442. + * See the License for the specific language governing permissions and
  443. + * limitations under the License.
  444. + *
  445. + */
  446. +
  447. +#include "dkim.h"
  448. +#include "dkimbase.h"
  449. +#include <string.h>
  450. +#include <algorithm>
  451. +
  452. +CDKIMBase::CDKIMBase()
  453. +{
  454. + m_From = NULL;
  455. + m_Sender = NULL;
  456. + m_hTag = NULL;
  457. + m_hTagSize = 0;
  458. + m_hTagPos = 0;
  459. + m_Line = NULL;
  460. + m_LineSize = 0;
  461. + m_LinePos = 0;
  462. + m_InHeaders = true;
  463. +}
  464. +
  465. +CDKIMBase::~CDKIMBase()
  466. +{
  467. + Free(m_Line);
  468. + Free(m_From);
  469. + Free(m_Sender);
  470. + Free(m_hTag);
  471. +}
  472. +
  473. +int
  474. +CDKIMBase::Init(void)
  475. +{
  476. + return DKIM_SUCCESS;
  477. +}
  478. +
  479. +////////////////////////////////////////////////////////////////////////////////
  480. +//
  481. +// Alloc - allocate buffer
  482. +//
  483. +////////////////////////////////////////////////////////////////////////////////
  484. +int CDKIMBase::Alloc(char *&szBuffer, int nRequiredSize)
  485. +{
  486. + szBuffer = new char[nRequiredSize];
  487. +
  488. + return (szBuffer == NULL) ? DKIM_OUT_OF_MEMORY : DKIM_SUCCESS;
  489. +}
  490. +
  491. +
  492. +////////////////////////////////////////////////////////////////////////////////
  493. +//
  494. +// ReAlloc - extend buffer if necessary, leaving room for future expansion
  495. +//
  496. +////////////////////////////////////////////////////////////////////////////////
  497. +int CDKIMBase::ReAlloc(char *&szBuffer, int &nBufferSize, int nRequiredSize)
  498. +{
  499. + if (nRequiredSize > nBufferSize) {
  500. + char *
  501. + newp;
  502. + int
  503. + nNewSize = nRequiredSize + BUFFER_ALLOC_INCREMENT;
  504. +
  505. + if (Alloc(newp, nNewSize) == DKIM_SUCCESS) {
  506. + if (szBuffer != NULL && nBufferSize > 0) {
  507. + memcpy(newp, szBuffer, nBufferSize);
  508. + delete[]szBuffer;
  509. + }
  510. + szBuffer = newp;
  511. + nBufferSize = nNewSize;
  512. + } else {
  513. + return DKIM_OUT_OF_MEMORY; // memory alloc error!
  514. + }
  515. + }
  516. + return DKIM_SUCCESS;
  517. +}
  518. +
  519. +////////////////////////////////////////////////////////////////////////////////
  520. +//
  521. +// Process - split buffers into lines without any CRs or LFs at the end.
  522. +//
  523. +////////////////////////////////////////////////////////////////////////////////
  524. +void CDKIMBase::Free(char *szBuffer)
  525. +{
  526. + if (szBuffer)
  527. + delete[]szBuffer;
  528. +}
  529. +
  530. +////////////////////////////////////////////////////////////////////////////////
  531. +//
  532. +// Process - split buffers into lines without any CRs or LFs at the end.
  533. +//
  534. +////////////////////////////////////////////////////////////////////////////////
  535. +int CDKIMBase::Process(char *szBuffer, int nBufLength, bool bEOF)
  536. +{
  537. + char *p = szBuffer;
  538. + char *e = szBuffer + nBufLength;
  539. +
  540. + while (p < e) {
  541. + if (*p != '\n' && *p != '\r') {
  542. + if (m_LinePos >= m_LineSize) {
  543. + int nRet = ReAlloc(m_Line, m_LineSize, m_LinePos + 1);
  544. + if (nRet != DKIM_SUCCESS)
  545. + /*
  546. + * How to distinguish between
  547. + * DKIM_FINISHED_BODY & DKIM_OUT_OF_MEMORY
  548. + */
  549. + return nRet;
  550. + }
  551. + m_Line[m_LinePos++] = *p;
  552. + } else {
  553. + if (*p == '\r' && p + 1 < e && *(p + 1) == '\n')
  554. + p++;
  555. + if (m_InHeaders) {
  556. + // process header line
  557. + if (m_LinePos == 0) {
  558. + m_InHeaders = false;
  559. + int Result = ProcessHeaders();
  560. + if (Result != DKIM_SUCCESS)
  561. + return Result;
  562. + } else {
  563. + // append the header to the headers list
  564. + if (m_Line[0] != ' ' && m_Line[0] != '\t') {
  565. + HeaderList.push_back(string(m_Line, m_LinePos));
  566. + } else {
  567. + if (!HeaderList.empty()) {
  568. + HeaderList.back().append("\r\n", 2).append(m_Line, m_LinePos);
  569. + } else {
  570. + // no header to append to...
  571. + }
  572. + }
  573. + }
  574. + } else {
  575. + // process body line
  576. + int Result = ProcessBody(m_Line, m_LinePos, bEOF);
  577. + if (Result != DKIM_SUCCESS) {
  578. + m_LinePos = 0;
  579. + return Result;
  580. + }
  581. + }
  582. + m_LinePos = 0;
  583. + }
  584. + p++;
  585. + }
  586. + return DKIM_SUCCESS;
  587. +}
  588. +
  589. +
  590. +////////////////////////////////////////////////////////////////////////////////
  591. +//
  592. +// ProcessFinal - process leftovers if stopping before the body or mid-line
  593. +//
  594. +////////////////////////////////////////////////////////////////////////////////
  595. +int CDKIMBase::ProcessFinal(void)
  596. +{
  597. + if (m_LinePos > 0) {
  598. + Process((char *) "\r\n", 2, true);
  599. + }
  600. +
  601. + if (m_InHeaders) {
  602. + m_InHeaders = false;
  603. + ProcessHeaders();
  604. + ProcessBody((char *) "", 0, true);
  605. + }
  606. +
  607. + return DKIM_SUCCESS;
  608. +}
  609. +
  610. +
  611. +////////////////////////////////////////////////////////////////////////////////
  612. +//
  613. +// ProcessHeaders - process the headers (to be implemented by derived class)
  614. +//
  615. +////////////////////////////////////////////////////////////////////////////////
  616. +int CDKIMBase::ProcessHeaders()
  617. +{
  618. + return DKIM_SUCCESS;
  619. +}
  620. +
  621. +
  622. +////////////////////////////////////////////////////////////////////////////////
  623. +//
  624. +// ProcessBody - process body line (to be implemented by derived class)
  625. +//
  626. +////////////////////////////////////////////////////////////////////////////////
  627. +int CDKIMBase::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
  628. +{
  629. + return DKIM_SUCCESS;
  630. +}
  631. +
  632. +
  633. +////////////////////////////////////////////////////////////////////////////////
  634. +//
  635. +// RemoveSWSP - remove streaming white space from buffer/string inline
  636. +//
  637. +////////////////////////////////////////////////////////////////////////////////
  638. +
  639. +struct isswsp {
  640. + bool
  641. + operator() (char ch) {
  642. + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
  643. + }
  644. +};
  645. +
  646. +void CDKIMBase::RemoveSWSP(char *szBuffer)
  647. +{
  648. + *remove_if(szBuffer, szBuffer + strlen(szBuffer), isswsp()) = '\0';
  649. +}
  650. +
  651. +void CDKIMBase::RemoveSWSP(char *pBuffer, int &nBufLength)
  652. +{
  653. + nBufLength = remove_if(pBuffer, pBuffer + nBufLength, isswsp()) - pBuffer;
  654. +}
  655. +
  656. +void CDKIMBase::RemoveSWSP(string &sBuffer)
  657. +{
  658. + sBuffer.erase(remove_if(sBuffer.begin(), sBuffer.end(), isswsp()), sBuffer.end());
  659. +}
  660. +
  661. +
  662. +//////////////////////////////////////////////////////////////////////////////////////////
  663. +//
  664. +// CompressSWSP - compress streaming white space into single spaces from buffer/string inline
  665. +//
  666. +//////////////////////////////////////////////////////////////////////////////////////////
  667. +
  668. +void CDKIMBase::CompressSWSP(char *pBuffer, int &nBufLength)
  669. +{
  670. + char *pSrc = pBuffer;
  671. + char *pDst = pBuffer;
  672. + char *pEnd = pBuffer + nBufLength;
  673. +
  674. + while (pSrc != pEnd) {
  675. + if (isswsp()(*pSrc)) {
  676. + do {
  677. + ++pSrc;
  678. + } while (pSrc != pEnd && isswsp()(*pSrc));
  679. + if (pSrc == pEnd)
  680. + break;
  681. + *pDst++ = ' ';
  682. + }
  683. + *pDst++ = *pSrc++;
  684. + }
  685. + nBufLength = pDst - pBuffer;
  686. +}
  687. +
  688. +void CDKIMBase::CompressSWSP(string &sBuffer)
  689. +{
  690. + string::iterator iSrc = sBuffer.begin();
  691. + string::iterator iDst = sBuffer.begin();
  692. + string::iterator iEnd = sBuffer.end();
  693. +
  694. + while (iSrc != iEnd) {
  695. + if (isswsp()(*iSrc)) {
  696. + do {
  697. + ++iSrc;
  698. + } while (iSrc != iEnd && isswsp()(*iSrc));
  699. +
  700. + if (iSrc == iEnd)
  701. + break;
  702. + *iDst++ = ' ';
  703. + }
  704. + *iDst++ = *iSrc++;
  705. + }
  706. + sBuffer.erase(iDst, iEnd);
  707. +}
  708. +
  709. +//////////////////////////////////////////////////////////////////////////////////////////
  710. +//
  711. +// RelaxHeader - relax a header field (lower case the name, remove swsp before and after :)
  712. +//
  713. +// modified 4/21/06 STB to remove white space before colon
  714. +//
  715. +//////////////////////////////////////////////////////////////////////////////////////////
  716. +
  717. +string CDKIMBase::RelaxHeader(const string &sHeader)
  718. +{
  719. + string sTemp = sHeader;
  720. +
  721. + CompressSWSP(sTemp);
  722. +
  723. + unsigned cpos = sTemp.find(':');
  724. + if (cpos == -1) {
  725. + // no colon?!
  726. + } else {
  727. + // lower case the header field name
  728. + for (unsigned i = 0; i < cpos; i++) {
  729. + if (sTemp[i] >= 'A' && sTemp[i] <= 'Z')
  730. + sTemp[i] += 'a' - 'A';
  731. + }
  732. + // remove the space after the :
  733. + if (cpos + 1 < sTemp.length() && sTemp[cpos + 1] == ' ')
  734. + sTemp.erase(cpos + 1, 1);
  735. + // remove the space before the :
  736. + if (cpos > 0 && sTemp[cpos - 1] == ' ')
  737. + sTemp.erase(cpos - 1, 1);
  738. + }
  739. + return sTemp;
  740. +}
  741. +
  742. +void
  743. +getversion_dkimbase_cpp()
  744. +{
  745. + static char *x = (char *) "$Id: dkimbase.cpp,v 1.3 2009-03-26 15:10:32+05:30 Cprogrammer Exp mbhangui $";
  746. +
  747. + x++;
  748. +}
  749. diff -Naur qmail-1.03.org/dkimbase.h qmail-1.03/dkimbase.h
  750. --- qmail-1.03.org/dkimbase.h 1970-01-01 05:30:00.000000000 +0530
  751. +++ qmail-1.03/dkimbase.h 2009-04-21 11:19:07.000000000 +0530
  752. @@ -0,0 +1,72 @@
  753. +/*
  754. + * $Log: dkimbase.h,v $
  755. + * Revision 1.1 2009-03-21 08:50:18+05:30 Cprogrammer
  756. + * Initial revision
  757. + *
  758. + *
  759. + * Copyright 2005 Alt-N Technologies, Ltd.
  760. + *
  761. + * Licensed under the Apache License, Version 2.0 (the "License");
  762. + * you may not use this file except in compliance with the License.
  763. + * You may obtain a copy of the License at
  764. + *
  765. + * http://www.apache.org/licenses/LICENSE-2.0
  766. + *
  767. + * This code incorporates intellectual property owned by Yahoo! and licensed
  768. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  769. + *
  770. + * Unless required by applicable law or agreed to in writing, software
  771. + * distributed under the License is distributed on an "AS IS" BASIS,
  772. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  773. + * See the License for the specific language governing permissions and
  774. + * limitations under the License.
  775. + *
  776. + */
  777. +
  778. +#ifndef DKIMBASE_H
  779. +#define DKIMBASE_H
  780. +
  781. +#include <openssl/evp.h>
  782. +#include <openssl/pem.h>
  783. +#include <openssl/err.h>
  784. +
  785. +#define BUFFER_ALLOC_INCREMENT 256
  786. +
  787. +#include <string>
  788. +#include <list>
  789. +
  790. +using namespace std;
  791. +class CDKIMBase {
  792. +public:
  793. +
  794. + CDKIMBase();
  795. + ~CDKIMBase();
  796. +
  797. + int Init(void);
  798. + int Process(char *szBuffer, int nBufLength, bool bEOF);
  799. + int ProcessFinal(void);
  800. + int Alloc(char *&szBuffer, int nRequiredSize);
  801. + int ReAlloc(char *&szBuffer, int &nBufferLength, int nRequiredSize);
  802. + void Free(char *szBuffer);
  803. + static void RemoveSWSP(char *szBuffer);
  804. + static void RemoveSWSP(char *pBuffer, int &nBufLength);
  805. + static void RemoveSWSP(string & sBuffer);
  806. + static void CompressSWSP(char *pBuffer, int &nBufLength);
  807. + static void CompressSWSP(string & sBuffer);
  808. + static string RelaxHeader(const string & sHeader);
  809. + virtual int ProcessHeaders(void);
  810. + virtual int ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
  811. +
  812. +protected:
  813. + char *m_From;
  814. + char *m_Sender;
  815. + char *m_hTag;
  816. + int m_hTagSize;
  817. + int m_hTagPos;
  818. + char *m_Line;
  819. + int m_LineSize;
  820. + int m_LinePos;
  821. + bool m_InHeaders;
  822. + list < string > HeaderList;
  823. +};
  824. +#endif /*- DKIMBASE_H */
  825. diff -Naur qmail-1.03.org/dkimdns.cpp qmail-1.03/dkimdns.cpp
  826. --- qmail-1.03.org/dkimdns.cpp 1970-01-01 05:30:00.000000000 +0530
  827. +++ qmail-1.03/dkimdns.cpp 2009-04-21 11:19:07.000000000 +0530
  828. @@ -0,0 +1,127 @@
  829. +/*
  830. + * $Log: dns.cpp,v $
  831. + * Revision 1.3 2009-03-27 19:22:45+05:30 Cprogrammer
  832. + * dns functions
  833. + *
  834. + */
  835. +#include <netdb.h>
  836. +#include <stdlib.h>
  837. +#include <sys/types.h>
  838. +#include <netinet/in.h>
  839. +#include <arpa/nameser.h>
  840. +#include <resolv.h>
  841. +#include <string.h>
  842. +#include "dkimdns.h"
  843. +
  844. +static unsigned short
  845. +getshort(unsigned char *cp)
  846. +{
  847. + return (cp[0] << 8) | cp[1];
  848. +}
  849. +
  850. +/*
  851. + * we always return a null-terminated string which has been malloc'ed. The string
  852. + * is always in the tag=value form. If a temporary or permanent error occurs,
  853. + * the string will be exactly "e=perm;" or "e=temp;".
  854. + * Note that it never returns NULL.
  855. + */
  856. +char *
  857. +dns_text(char *dn)
  858. +{
  859. + u_char response[PACKETSZ + 1]; /* response */
  860. + int responselen; /* buffer length */
  861. + int rc; /* misc variables */
  862. + int ancount, qdcount; /* answer count and query count */
  863. + u_short type, rdlength; /* fields of records returned */
  864. + u_char *eom, *cp;
  865. + u_char buf[PACKETSZ + 1]; /* we're storing a TXT record here, not just a DNAME */
  866. + u_char *bufptr;
  867. +
  868. + responselen = res_query(dn, C_IN, T_TXT, response, sizeof (response));
  869. + if (responselen < 0) {
  870. + if (h_errno == TRY_AGAIN)
  871. + return strdup("e=temp;");
  872. + else
  873. + return strdup("e=perm;");
  874. + }
  875. + qdcount = getshort(response + 4); /* http://crynwr.com/rfc1035/rfc1035.html#4.1.1. */
  876. + ancount = getshort(response + 6);
  877. + eom = response + responselen;
  878. + cp = response + HFIXEDSZ;
  879. + while (qdcount-- > 0 && cp < eom)
  880. + {
  881. + rc = dn_expand(response, eom, cp, (char *) buf, MAXDNAME);
  882. + if (rc < 0)
  883. + return strdup("e=perm;");
  884. + cp += rc + QFIXEDSZ;
  885. + }
  886. + while (ancount-- > 0 && cp < eom)
  887. + {
  888. + if ((rc = dn_expand(response, eom, cp, (char *) buf, MAXDNAME)) < 0)
  889. + return strdup("e=perm;");
  890. + cp += rc;
  891. + if (cp + RRFIXEDSZ >= eom)
  892. + return strdup("e=perm;");
  893. + type = getshort(cp + 0); /* http://crynwr.com/rfc1035/rfc1035.html#4.1.3. */
  894. + rdlength = getshort(cp + 8);
  895. + cp += RRFIXEDSZ;
  896. + if (type != T_TXT)
  897. + {
  898. + cp += rdlength;
  899. + continue;
  900. + }
  901. + bufptr = buf;
  902. + while (rdlength && cp < eom)
  903. + {
  904. + unsigned int cnt;
  905. +
  906. + cnt = *cp++; /* http://crynwr.com/rfc1035/rfc1035.html#3.3.14. */
  907. + if (bufptr - buf + cnt + 1 >= PACKETSZ)
  908. + return strdup("e=perm;");
  909. + if (cp + cnt > eom)
  910. + return strdup("e=perm;");
  911. + memcpy((char *) bufptr, (char *) cp, cnt);
  912. + rdlength -= cnt + 1;
  913. + bufptr += cnt;
  914. + cp += cnt;
  915. + *bufptr = '\0';
  916. + }
  917. + return (char *) strdup((char *) buf);
  918. + }
  919. + return strdup("e=perm;");
  920. +}
  921. +
  922. +int
  923. +DNSGetTXT(const char *domain, char *buffer, int maxlen)
  924. +{
  925. + char *results;
  926. + int len;
  927. +
  928. + results = dns_text((char *) domain);
  929. + if (!strcmp(results, "e=perm;"))
  930. + {
  931. + free(results);
  932. + return DNSRESP_PERM_FAIL;
  933. + } else
  934. + if (!strcmp(results, "e=temp;"))
  935. + {
  936. + free(results);
  937. + return DNSRESP_TEMP_FAIL;
  938. + }
  939. + if (strlen(results) > maxlen - 1)
  940. + {
  941. + free(results);
  942. + return DNSRESP_DOMAIN_NAME_TOO_LONG;
  943. + }
  944. + strncpy(buffer, results, maxlen);
  945. + free(results);
  946. + return DNSRESP_SUCCESS;
  947. +}
  948. +
  949. +void
  950. +getversion_dkimdns_cpp()
  951. +{
  952. + static char *x = (char *) "$Id: dns.cpp,v 1.3 2009-03-27 19:22:45+05:30 Cprogrammer Exp mbhangui $";
  953. +
  954. + x++;
  955. +}
  956. diff -Naur qmail-1.03.org/dkimdns.h qmail-1.03/dkimdns.h
  957. --- qmail-1.03.org/dkimdns.h 1970-01-01 05:30:00.000000000 +0530
  958. +++ qmail-1.03/dkimdns.h 2009-04-21 11:19:07.000000000 +0530
  959. @@ -0,0 +1,47 @@
  960. +/*
  961. + * $Log: dns.h,v $
  962. + * Revision 1.3 2009-03-27 20:40:16+05:30 Cprogrammer
  963. + * removed windows definitions
  964. + *
  965. + * Revision 1.2 2009-03-27 19:23:01+05:30 Cprogrammer
  966. + * added dns_text()
  967. + *
  968. + * Revision 1.1 2009-03-21 08:50:24+05:30 Cprogrammer
  969. + * Initial revision
  970. + *
  971. + * Copyright 2005 Alt-N Technologies, Ltd.
  972. + *
  973. + * Licensed under the Apache License, Version 2.0 (the "License");
  974. + * you may not use this file except in compliance with the License.
  975. + * You may obtain a copy of the License at
  976. + *
  977. + * http://www.apache.org/licenses/LICENSE-2.0
  978. + *
  979. + * This code incorporates intellectual property owned by Yahoo! and licensed
  980. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  981. + *
  982. + * Unless required by applicable law or agreed to in writing, software
  983. + * distributed under the License is distributed on an "AS IS" BASIS,
  984. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  985. + * See the License for the specific language governing permissions and
  986. + * limitations under the License.
  987. + *
  988. + */
  989. +
  990. +// These DNS resolution routines are encapsulated by the API below
  991. +
  992. +// return values for DNS functions:
  993. +
  994. +
  995. +#define MAX_DOMAIN 254
  996. +
  997. +#define DNSRESP_SUCCESS 0 // DNS lookup returned sought after records
  998. +#define DNSRESP_TEMP_FAIL 1 // No response from DNS server
  999. +#define DNSRESP_PERM_FAIL 2 // DNS server returned error or no records
  1000. +#define DNSRESP_DOMAIN_NAME_TOO_LONG 3 // Domain name too long
  1001. +#define DNSRESP_NXDOMAIN 4 // DNS server returned Name Error
  1002. +#define DNSRESP_EMPTY 5 // DNS server returned successful response but no records
  1003. +
  1004. +// Pass in the FQDN to get the TXT record
  1005. +int DNSGetTXT(const char *szFQDN, char *Buffer, int nBufLen);
  1006. +char *dns_text(char *szFQDN);
  1007. diff -Naur qmail-1.03.org/dkimfuncs.cpp qmail-1.03/dkimfuncs.cpp
  1008. --- qmail-1.03.org/dkimfuncs.cpp 1970-01-01 05:30:00.000000000 +0530
  1009. +++ qmail-1.03/dkimfuncs.cpp 2009-04-21 11:19:07.000000000 +0530
  1010. @@ -0,0 +1,224 @@
  1011. +/*
  1012. + * $Log: dkimfuncs.cpp,v $
  1013. + * Revision 1.2 2009-03-26 15:11:12+05:30 Cprogrammer
  1014. + * added GetDomain(), ADSP
  1015. + *
  1016. + * Revision 1.1 2009-03-21 08:43:10+05:30 Cprogrammer
  1017. + * Initial revision
  1018. + *
  1019. + *
  1020. + * Copyright 2005 Alt-N Technologies, Ltd.
  1021. + *
  1022. + * Licensed under the Apache License, Version 2.0 (the "License");
  1023. + * you may not use this file except in compliance with the License.
  1024. + * You may obtain a copy of the License at
  1025. + *
  1026. + * http://www.apache.org/licenses/LICENSE-2.0
  1027. + *
  1028. + * This code incorporates intellectual property owned by Yahoo! and licensed
  1029. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  1030. + *
  1031. + * Unless required by applicable law or agreed to in writing, software
  1032. + * distributed under the License is distributed on an "AS IS" BASIS,
  1033. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1034. + * See the License for the specific language governing permissions and
  1035. + * limitations under the License.
  1036. + *
  1037. + */
  1038. +#ifdef HAVE_CONFIG_H
  1039. +#include "config.h"
  1040. +#endif
  1041. +#include "dkim.h"
  1042. +#include "dkimsign.h"
  1043. +#include "dkimverify.h"
  1044. +#include <string.h>
  1045. +
  1046. +#define DKIMID ('D' | 'K'<<8 | 'I'<<16 | 'M'<<24)
  1047. +
  1048. +static void
  1049. +InitContext(DKIMContext * pContext, bool bSign, void *pObject)
  1050. +{
  1051. + pContext->reserved1 = DKIMID;
  1052. + pContext->reserved2 = bSign ? 1 : 0;
  1053. + pContext->reserved3 = pObject;
  1054. +}
  1055. +
  1056. +static void *
  1057. +ValidateContext(DKIMContext * pContext, bool bSign)
  1058. +{
  1059. + if (pContext->reserved1 != DKIMID)
  1060. + return NULL;
  1061. + if (pContext->reserved2 != (unsigned int) (bSign ? 1 : 0))
  1062. + return NULL;
  1063. + return pContext->reserved3;
  1064. +}
  1065. +
  1066. +int DKIM_CALL
  1067. +DKIMSignInit(DKIMContext * pSignContext, DKIMSignOptions * pOptions)
  1068. +{
  1069. + int nRet = DKIM_OUT_OF_MEMORY;
  1070. + CDKIMSign *pSign = new CDKIMSign;
  1071. +
  1072. + if (pSign) {
  1073. + nRet = pSign->Init(pOptions);
  1074. + if (nRet != DKIM_SUCCESS)
  1075. + delete pSign;
  1076. + }
  1077. + if (nRet == DKIM_SUCCESS)
  1078. + InitContext(pSignContext, true, pSign);
  1079. + return nRet;
  1080. +}
  1081. +
  1082. +int DKIM_CALL
  1083. +DKIMSignProcess(DKIMContext * pSignContext, char *szBuffer, int nBufLength)
  1084. +{
  1085. + CDKIMSign *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
  1086. + if (pSign)
  1087. + return pSign->Process(szBuffer, nBufLength, false);
  1088. + return DKIM_INVALID_CONTEXT;
  1089. +}
  1090. +
  1091. +int DKIM_CALL
  1092. +DKIMSignGetSig(DKIMContext * pSignContext, char *szPrivKey, char *szSignature, int nSigLength)
  1093. +{
  1094. + CDKIMSign *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
  1095. + if (pSign)
  1096. + return pSign->GetSig(szPrivKey, szSignature, nSigLength);
  1097. + return DKIM_INVALID_CONTEXT;
  1098. +}
  1099. +
  1100. +int DKIM_CALL
  1101. +DKIMSignGetSig2(DKIMContext * pSignContext, char *szPrivKey, char **pszSignature)
  1102. +{
  1103. + CDKIMSign *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
  1104. + if (pSign)
  1105. + return pSign->GetSig2(szPrivKey, pszSignature);
  1106. + return DKIM_INVALID_CONTEXT;
  1107. +}
  1108. +
  1109. +char *DKIM_CALL
  1110. +DKIMSignGetDomain(DKIMContext *pSignContext)
  1111. +{
  1112. + CDKIMSign *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
  1113. + if (pSign)
  1114. + return pSign->GetDomain();
  1115. + return ((char *) 0);
  1116. +}
  1117. +
  1118. +void DKIM_CALL
  1119. +DKIMSignFree(DKIMContext * pSignContext)
  1120. +{
  1121. + CDKIMSign *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
  1122. + if (pSign) {
  1123. + delete pSign;
  1124. + pSignContext->reserved3 = NULL;
  1125. + }
  1126. +}
  1127. +
  1128. +int DKIM_CALL
  1129. +DKIMVerifyInit(DKIMContext * pVerifyContext, DKIMVerifyOptions * pOptions)
  1130. +{
  1131. + int nRet = DKIM_OUT_OF_MEMORY;
  1132. + CDKIMVerify *pVerify = new CDKIMVerify;
  1133. + if (pVerify) {
  1134. + nRet = pVerify->Init(pOptions);
  1135. + if (nRet != DKIM_SUCCESS)
  1136. + delete pVerify;
  1137. + }
  1138. + if (nRet == DKIM_SUCCESS)
  1139. + InitContext(pVerifyContext, false, pVerify);
  1140. + return nRet;
  1141. +}
  1142. +
  1143. +int DKIM_CALL
  1144. +DKIMVerifyProcess(DKIMContext * pVerifyContext, char *szBuffer, int nBufLength)
  1145. +{
  1146. + CDKIMVerify *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
  1147. + if (pVerify)
  1148. + return pVerify->Process(szBuffer, nBufLength, false);
  1149. + return DKIM_INVALID_CONTEXT;
  1150. +}
  1151. +
  1152. +int DKIM_CALL
  1153. +DKIMVerifyResults( DKIMContext *pVerifyContext , int *sCount, int *sSize)
  1154. +{
  1155. + CDKIMVerify *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
  1156. + if (pVerify)
  1157. + return pVerify->GetResults(sCount, sSize);
  1158. + return DKIM_INVALID_CONTEXT;
  1159. +}
  1160. +
  1161. +int DKIM_CALL
  1162. +DKIMVerifyGetDetails(DKIMContext * pVerifyContext, int *nSigCount, DKIMVerifyDetails ** pDetails, char *szPractices)
  1163. +{
  1164. + szPractices[0] = '\0';
  1165. + CDKIMVerify *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
  1166. + if (pVerify) {
  1167. + strcpy(szPractices, pVerify->GetPractices());
  1168. + return pVerify->GetDetails(nSigCount, pDetails);
  1169. + }
  1170. + return DKIM_INVALID_CONTEXT;
  1171. +}
  1172. +
  1173. +void DKIM_CALL
  1174. +DKIMVerifyFree(DKIMContext *pVerifyContext)
  1175. +{
  1176. + CDKIMVerify *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
  1177. + if (pVerify) {
  1178. + delete pVerify;
  1179. + pVerifyContext->reserved3 = NULL;
  1180. + }
  1181. +}
  1182. +
  1183. +char *DKIM_CALL
  1184. +DKIMVerifyGetDomain(DKIMContext *pVerifyContext)
  1185. +{
  1186. + CDKIMVerify *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
  1187. + if (pVerify)
  1188. + return pVerify->GetDomain();
  1189. + return ((char *) 0);
  1190. +}
  1191. +
  1192. +char *DKIM_CALL
  1193. +DKIMVersion()
  1194. +{
  1195. + return (char *) "1.1";
  1196. +}
  1197. +
  1198. +static char *DKIMErrorStrings[-1 - DKIM_MAX_ERROR] = {
  1199. + (char *) "DKIM_FAIL",
  1200. + (char *) "DKIM_BAD_SYNTAX",
  1201. + (char *) "DKIM_SIGNATURE_BAD",
  1202. + (char *) "DKIM_SIGNATURE_BAD_BUT_TESTING",
  1203. + (char *) "DKIM_SIGNATURE_EXPIRED",
  1204. + (char *) "DKIM_SELECTOR_INVALID",
  1205. + (char *) "DKIM_SELECTOR_GRANULARITY_MISMATCH",
  1206. + (char *) "DKIM_SELECTOR_KEY_REVOKED",
  1207. + (char *) "DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG",
  1208. + (char *) "DKIM_SELECTOR_DNS_TEMP_FAILURE",
  1209. + (char *) "DKIM_SELECTOR_DNS_PERM_FAILURE",
  1210. + (char *) "DKIM_SELECTOR_PUBLIC_KEY_INVALID",
  1211. + (char *) "DKIM_NO_SIGNATURES",
  1212. + (char *) "DKIM_NO_VALID_SIGNATURES",
  1213. + (char *) "DKIM_BODY_HASH_MISMATCH",
  1214. + (char *) "DKIM_SELECTOR_ALGORITHM_MISMATCH",
  1215. + (char *) "DKIM_STAT_INCOMPAT"
  1216. +};
  1217. +
  1218. +char *DKIM_CALL
  1219. +DKIMGetErrorString(int ErrorCode)
  1220. +{
  1221. + if (ErrorCode >= 0 || ErrorCode <= DKIM_MAX_ERROR)
  1222. + return (char *) "Unknown";
  1223. +
  1224. + else
  1225. + return DKIMErrorStrings[-1 - ErrorCode];
  1226. +}
  1227. +
  1228. +void
  1229. +getversion_dkimfuncs_cpp()
  1230. +{
  1231. + static char *x = (char *) "$Id: dkimfuncs.cpp,v 1.2 2009-03-26 15:11:12+05:30 Cprogrammer Exp mbhangui $";
  1232. +
  1233. + x++;
  1234. +}
  1235. diff -Naur qmail-1.03.org/dkim.h qmail-1.03/dkim.h
  1236. --- qmail-1.03.org/dkim.h 1970-01-01 05:30:00.000000000 +0530
  1237. +++ qmail-1.03/dkim.h 2009-04-21 11:19:07.000000000 +0530
  1238. @@ -0,0 +1,179 @@
  1239. +/*
  1240. + * $Log: dkim.h,v $
  1241. + * Revision 1.5 2009-03-27 20:19:05+05:30 Cprogrammer
  1242. + * major changes made for incorporating ADSP
  1243. + *
  1244. + * Revision 1.4 2009-03-26 19:28:15+05:30 Cprogrammer
  1245. + * removed DKIM_3PS_PARTIAL_SUCCESS
  1246. + *
  1247. + * Revision 1.3 2009-03-26 15:11:33+05:30 Cprogrammer
  1248. + * added ADSP
  1249. + *
  1250. + * Revision 1.2 2009-03-25 08:37:58+05:30 Cprogrammer
  1251. + * changed definitions of constants to avoid clash between error and success
  1252. + *
  1253. + * Revision 1.1 2009-03-21 08:50:19+05:30 Cprogrammer
  1254. + * Initial revision
  1255. + *
  1256. + *
  1257. + * Copyright 2005 Alt-N Technologies, Ltd.
  1258. + *
  1259. + * Licensed under the Apache License, Version 2.0 (the "License");
  1260. + * you may not use this file except in compliance with the License.
  1261. + * You may obtain a copy of the License at
  1262. + *
  1263. + * http://www.apache.org/licenses/LICENSE-2.0
  1264. + *
  1265. + * This code incorporates intellectual property owned by Yahoo! and licensed
  1266. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  1267. + *
  1268. + * Unless required by applicable law or agreed to in writing, software
  1269. + * distributed under the License is distributed on an "AS IS" BASIS,
  1270. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1271. + * See the License for the specific language governing permissions and
  1272. + * limitations under the License.
  1273. + *
  1274. + */
  1275. +
  1276. +#define DKIM_CALL
  1277. +#define MAKELONG(a,b) ((long)(((unsigned)(a) & 0xffff) | (((unsigned)(b) & 0xffff) << 16)))
  1278. +
  1279. +#ifdef __cplusplus
  1280. +extern "C" {
  1281. +#endif
  1282. +
  1283. +// DKIM Body hash versions
  1284. +#define DKIM_BODYHASH_ALLMAN_1 1
  1285. +#define DKIM_BODYHASH_IETF_1 2
  1286. +#define DKIM_BODYHASH_BOTH DKIM_BODYHASH_ALLMAN_1 | DKIM_BODYHASH_IETF_1
  1287. +
  1288. +// DKIM hash algorithms
  1289. +#define DKIM_HASH_SHA1 1
  1290. +#define DKIM_HASH_SHA256 2
  1291. +#define DKIM_HASH_SHA1_AND_256 DKIM_HASH_SHA1 | DKIM_HASH_SHA256
  1292. +
  1293. +// DKIM canonicalization methods
  1294. +#define DKIM_CANON_SIMPLE 1
  1295. +#define DKIM_CANON_NOWSP 2
  1296. +#define DKIM_CANON_RELAXED 3
  1297. +
  1298. +#define DKIM_SIGN_SIMPLE MAKELONG(DKIM_CANON_SIMPLE,DKIM_CANON_SIMPLE)
  1299. +#define DKIM_SIGN_SIMPLE_RELAXED MAKELONG(DKIM_CANON_RELAXED,DKIM_CANON_SIMPLE)
  1300. +#define DKIM_SIGN_RELAXED MAKELONG(DKIM_CANON_RELAXED,DKIM_CANON_RELAXED)
  1301. +#define DKIM_SIGN_RELAXED_SIMPLE MAKELONG(DKIM_CANON_SIMPLE,DKIM_CANON_RELAXED)
  1302. +
  1303. +// DKIM Error codes
  1304. +#define DKIM_OUT_OF_MEMORY 6 // memory allocation failed
  1305. +#define DKIM_INVALID_CONTEXT 7 // DKIMContext structure invalid for this operation
  1306. +#define DKIM_NO_SENDER 8 // Could not find From: or Sender: header in message
  1307. +#define DKIM_BAD_PRIVATE_KEY 9 // Could not parse private key
  1308. +#define DKIM_BUFFER_TOO_SMALL 10 // Buffer passed in is not large enough
  1309. +
  1310. +// DKIM_SUCCESS // verify result: all signatures verified
  1311. +// signature result: signature verified
  1312. +#define DKIM_SUCCESS 0 // operation successful
  1313. +#define DKIM_FINISHED_BODY 1 // process result: no more message body is needed
  1314. +#define DKIM_PARTIAL_SUCCESS 2 // verify result: at least one but not all signatures verified
  1315. +#define DKIM_NEUTRAL 3 // verify result: no signatures verified but message is not suspicous
  1316. +#define DKIM_SUCCESS_BUT_EXTRA 4 // signature result: signature verified but it did not include all of the body
  1317. +#define DKIM_3PS_SIGNATURE 5 // 3rd-party signature
  1318. +
  1319. +// DKIM Verification Error codes
  1320. +#define DKIM_FAIL -1 // verify error: message is suspicious
  1321. +#define DKIM_BAD_SYNTAX -2 // signature error: DKIM-Signature could not parse or has bad tags/values
  1322. +#define DKIM_SIGNATURE_BAD -3 // signature error: RSA verify failed
  1323. +#define DKIM_SIGNATURE_BAD_BUT_TESTING -4 // signature error: RSA verify failed but testing
  1324. +#define DKIM_SIGNATURE_EXPIRED -5 // signature error: x= is old
  1325. +#define DKIM_SELECTOR_INVALID -6 // signature error: selector doesn't parse or contains invalid values
  1326. +#define DKIM_SELECTOR_GRANULARITY_MISMATCH -7 // signature error: selector g= doesn't match i=
  1327. +#define DKIM_SELECTOR_KEY_REVOKED -8 // signature error: selector p= empty
  1328. +#define DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG -9 // signature error: selector domain name too long to request
  1329. +#define DKIM_SELECTOR_DNS_TEMP_FAILURE -10 // signature error: temporary dns failure requesting selector
  1330. +#define DKIM_SELECTOR_DNS_PERM_FAILURE -11 // signature error: permanent dns failure requesting selector
  1331. +#define DKIM_SELECTOR_PUBLIC_KEY_INVALID -12 // signature error: selector p= value invalid or wrong format
  1332. +#define DKIM_NO_SIGNATURES -13 // process error, no sigs
  1333. +#define DKIM_NO_VALID_SIGNATURES -14 // process error, no valid sigs
  1334. +#define DKIM_BODY_HASH_MISMATCH -15 // sigature verify error: message body does not hash to bh value
  1335. +#define DKIM_SELECTOR_ALGORITHM_MISMATCH -16 // signature error: selector h= doesn't match signature a=
  1336. +#define DKIM_STAT_INCOMPAT -17 // signature error: incompatible v=
  1337. +#define DKIM_MAX_ERROR -18 // set this to 1 greater than the highest error code (but negative)
  1338. +
  1339. +#define DKIM_SSP_UNKNOWN 1 /*- some messages may be signed */
  1340. +#define DKIM_SSP_ALL 2 /*- all messages are signed, 3rd party allowed */
  1341. +#define DKIM_SSP_STRICT 3 /*- all messages are signed, no 3rd party allowed */
  1342. +#define DKIM_SSP_SCOPE 4 /*- the domain should be considered invalid */
  1343. +#define DKIM_SSP_TEMPFAIL 5 /*- Temporary Error */
  1344. +
  1345. +#define DKIM_ADSP_UNKNOWN 1 /*- some messages may be signed */
  1346. +#define DKIM_ADSP_ALL 2 /*- All message are signed with author signature */
  1347. +#define DKIM_ADSP_DISCARDABLE 3 /*- messages which fail verification are Discardable */
  1348. +#define DKIM_ADSP_SCOPE 4 /*- domain is out of scope */
  1349. +#define DKIM_ADSP_TEMPFAIL 5 /*- Temporary Error */
  1350. +
  1351. +
  1352. +// This function is called once for each header in the message
  1353. +// return 1 to include this header in the signature and 0 to exclude.
  1354. +typedef int (DKIM_CALL * DKIMHEADERCALLBACK) (const char *szHeader);
  1355. +
  1356. +// This function is called to retrieve a TXT record from DNS
  1357. +typedef int (DKIM_CALL * DKIMDNSCALLBACK) (const char *szFQDN, char *szBuffer, int nBufLen);
  1358. +
  1359. +typedef struct DKIMContext_t {
  1360. + unsigned int reserved1;
  1361. + unsigned int reserved2;
  1362. + void *reserved3;
  1363. +} DKIMContext;
  1364. +
  1365. +typedef struct DKIMSignOptions_t {
  1366. + int nCanon; // canonization
  1367. + int nIncludeBodyLengthTag; // 0 = don't include l= tag, 1 = include l= tag
  1368. + int nIncludeTimeStamp; // 0 = don't include t= tag, 1 = include t= tag
  1369. + int nIncludeQueryMethod; // 0 = don't include q= tag, 1 = include q= tag
  1370. + char szSelector[80]; // selector - required
  1371. + char szDomain[256]; // domain - optional - if empty, domain is computed from sender
  1372. + char szIdentity[256]; // for i= tag, if empty tag will not be included in sig
  1373. + unsigned long expireTime; // for x= tag, if 0 tag will not be included in sig
  1374. + DKIMHEADERCALLBACK pfnHeaderCallback; // header callback
  1375. + char szRequiredHeaders[256]; // colon-separated list of headers that must be signed
  1376. + int nHash; // use one of the DKIM_HASH_xx constants here
  1377. + // even if not present in the message
  1378. + int nIncludeCopiedHeaders; // 0 = don't include z= tag, 1 = include z= tag
  1379. + int nIncludeBodyHash; // use one of the DKIM_BODYHASH_xx constants here
  1380. +} DKIMSignOptions;
  1381. +
  1382. +typedef struct DKIMVerifyOptions_t {
  1383. + DKIMDNSCALLBACK pfnSelectorCallback; // selector record callback
  1384. + DKIMDNSCALLBACK pfnPracticesCallback; // SSP record callback
  1385. + int nHonorBodyLengthTag; // 0 = ignore l= tag, 1 = use l= tag to limit the amount of body verified
  1386. + int nCheckPractices; // 0 = use default (unknown) practices, 1 = request and use sender's signing practices
  1387. + int nSubjectRequired; // 0 = subject is required to be signed, 1 = not required
  1388. + int nSaveCanonicalizedData; // 0 = canonicalized data is not saved, 1 = canonicalized data is saved
  1389. + int nAccept3ps; // 0 = don't check 3rd party signature(s), 1 = check 3rd party signature(s)
  1390. +} DKIMVerifyOptions;
  1391. +
  1392. +typedef struct DKIMVerifyDetails_t {
  1393. + char *szSignature;
  1394. + char *DNS;
  1395. + char *szCanonicalizedData;
  1396. + int nResult;
  1397. +} DKIMVerifyDetails;
  1398. +
  1399. +int DKIM_CALL DKIMSignInit(DKIMContext *pSignContext, DKIMSignOptions * pOptions);
  1400. +int DKIM_CALL DKIMSignProcess(DKIMContext *pSignContext, char *szBuffer, int nBufLength);
  1401. +int DKIM_CALL DKIMSignGetSig(DKIMContext *pSignContext, char *szPrivKey, char *szSignature, int nSigLength);
  1402. +int DKIM_CALL DKIMSignGetSig2(DKIMContext *pSignContext, char *szPrivKey, char **pszSignature);
  1403. +void DKIM_CALL DKIMSignFree(DKIMContext *pSignContext);
  1404. +char *DKIM_CALL DKIMSignGetDomain(DKIMContext *pSignContext);
  1405. +
  1406. +int DKIM_CALL DKIMVerifyInit(DKIMContext *pVerifyContext, DKIMVerifyOptions * pOptions);
  1407. +int DKIM_CALL DKIMVerifyProcess(DKIMContext *pVerifyContext, char *szBuffer, int nBufLength);
  1408. +int DKIM_CALL DKIMVerifyResults(DKIMContext *pVerifyContext , int *sCount, int *sSize);
  1409. +int DKIM_CALL DKIMVerifyGetDetails(DKIMContext *pVerifyContext, int *nSigCount, DKIMVerifyDetails **pDetails, char *szPractices);
  1410. +char *DKIM_CALL DKIMVerifyGetDomain(DKIMContext *pVerifyContext);
  1411. +void DKIM_CALL DKIMVerifyFree(DKIMContext *pVerifyContext);
  1412. +char *DKIM_CALL DKIMVersion();
  1413. +char *DKIM_CALL DKIMGetErrorString(int ErrorCode);
  1414. +#include "macros.h"
  1415. +#ifdef __cplusplus
  1416. +}
  1417. +#endif
  1418. diff -Naur qmail-1.03.org/dkimsign.cpp qmail-1.03/dkimsign.cpp
  1419. --- qmail-1.03.org/dkimsign.cpp 1970-01-01 05:30:00.000000000 +0530
  1420. +++ qmail-1.03/dkimsign.cpp 2009-04-21 11:19:07.000000000 +0530
  1421. @@ -0,0 +1,906 @@
  1422. +/*
  1423. + * $Log: dkimsign.cpp,v $
  1424. + * Revision 1.4 2009-04-15 21:32:12+05:30 Cprogrammer
  1425. + * added DKIM-Signature, Received to list of excluded headers
  1426. + *
  1427. + * Revision 1.3 2009-03-26 15:11:46+05:30 Cprogrammer
  1428. + * added GetDomain
  1429. + *
  1430. + * Revision 1.2 2009-03-21 11:57:19+05:30 Cprogrammer
  1431. + * fixed indentation
  1432. + *
  1433. + * Revision 1.1 2009-03-21 08:43:11+05:30 Cprogrammer
  1434. + * Initial revision
  1435. + *
  1436. + *
  1437. + * Copyright 2005 Alt-N Technologies, Ltd.
  1438. + *
  1439. + * Licensed under the Apache License, Version 2.0 (the "License");
  1440. + * you may not use this file except in compliance with the License.
  1441. + * You may obtain a copy of the License at
  1442. + *
  1443. + * http://www.apache.org/licenses/LICENSE-2.0
  1444. + *
  1445. + * This code incorporates intellectual property owned by Yahoo! and licensed
  1446. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  1447. + *
  1448. + * Unless required by applicable law or agreed to in writing, software
  1449. + * distributed under the License is distributed on an "AS IS" BASIS,
  1450. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1451. + * See the License for the specific language governing permissions and
  1452. + * limitations under the License.
  1453. + *
  1454. + */
  1455. +
  1456. +#ifdef HAVE_CONFIG_H
  1457. +#include "config.h"
  1458. +#endif
  1459. +#define _strnicmp strncasecmp
  1460. +#define _stricmp strcasecmp
  1461. +#define LOWORD(l) ((unsigned)(l) & 0xffff)
  1462. +#define HIWORD(l) ((unsigned)(l) >> 16)
  1463. +#define HAVE_EVP_SHA256
  1464. +
  1465. +#include <string.h>
  1466. +#include <map>
  1467. +#include "dkim.h"
  1468. +#include "dkimsign.h"
  1469. +
  1470. +CDKIMSign::CDKIMSign()
  1471. +{
  1472. + m_EmptyLineCount = 0;
  1473. + m_pfnHdrCallback = NULL;
  1474. + EVP_SignInit(&m_allman_sha1ctx, EVP_sha1());
  1475. + EVP_SignInit(&m_Hdr_ietf_sha1ctx, EVP_sha1());
  1476. + EVP_DigestInit(&m_Bdy_ietf_sha1ctx, EVP_sha1());
  1477. +#ifdef HAVE_EVP_SHA256
  1478. + EVP_SignInit(&m_Hdr_ietf_sha256ctx, EVP_sha256());
  1479. + EVP_DigestInit(&m_Bdy_ietf_sha256ctx, EVP_sha256());
  1480. +#endif
  1481. +}
  1482. +
  1483. +CDKIMSign::~CDKIMSign()
  1484. +{
  1485. + EVP_MD_CTX_cleanup(&m_allman_sha1ctx);
  1486. + EVP_MD_CTX_cleanup(&m_Hdr_ietf_sha1ctx);
  1487. + EVP_MD_CTX_cleanup(&m_Bdy_ietf_sha1ctx);
  1488. +#ifdef HAVE_EVP_SHA256
  1489. + EVP_MD_CTX_cleanup(&m_Hdr_ietf_sha256ctx);
  1490. + EVP_MD_CTX_cleanup(&m_Bdy_ietf_sha256ctx);
  1491. +#endif
  1492. +}
  1493. +
  1494. +
  1495. +////////////////////////////////////////////////////////////////////////////////
  1496. +//
  1497. +// Init - save the options
  1498. +//
  1499. +////////////////////////////////////////////////////////////////////////////////
  1500. +int
  1501. +CDKIMSign::Init(DKIMSignOptions * pOptions)
  1502. +{
  1503. + int nRet = CDKIMBase::Init();
  1504. + m_Canon = pOptions->nCanon;
  1505. +
  1506. +// as of draft 01, these are the only allowed signing types:
  1507. + if ((m_Canon != DKIM_SIGN_SIMPLE_RELAXED) && (m_Canon != DKIM_SIGN_RELAXED) && (m_Canon != DKIM_SIGN_RELAXED_SIMPLE)) {
  1508. + m_Canon = DKIM_SIGN_SIMPLE;
  1509. + }
  1510. + sSelector.assign(pOptions->szSelector);
  1511. + m_pfnHdrCallback = pOptions->pfnHeaderCallback;
  1512. + sDomain.assign(pOptions->szDomain);
  1513. + m_IncludeBodyLengthTag = (pOptions->nIncludeBodyLengthTag != 0);
  1514. + m_nBodyLength = 0;
  1515. + m_ExpireTime = pOptions->expireTime;
  1516. + sIdentity.assign(pOptions->szIdentity);
  1517. + m_nIncludeTimeStamp = pOptions->nIncludeTimeStamp;
  1518. + m_nIncludeQueryMethod = pOptions->nIncludeQueryMethod;
  1519. + m_nIncludeCopiedHeaders = pOptions->nIncludeCopiedHeaders;
  1520. + m_nIncludeBodyHash = pOptions->nIncludeBodyHash;
  1521. +
  1522. +// NOTE: the following line is not backwards compatible with MD 8.0.3
  1523. +// because the szRequiredHeaders member was added after the release
  1524. +//sRequiredHeaders.assign( pOptions->szRequiredHeaders );
  1525. +
  1526. +//make sure there is a colon after the last header in the list
  1527. + if ((sRequiredHeaders.size() > 0) && sRequiredHeaders.at(sRequiredHeaders.size() - 1) != ':')
  1528. + sRequiredHeaders.append(":");
  1529. + m_nHash = pOptions->nHash;
  1530. + m_bReturnedSigAssembled = false;
  1531. + m_sCopiedHeaders.erase();
  1532. + return nRet;
  1533. +}
  1534. +
  1535. +
  1536. +// Hash - update the hash
  1537. +void
  1538. +CDKIMSign::Hash(const char *szBuffer, int nBufLength, bool bHdr, bool bAllmanOnly)
  1539. +{
  1540. + if (bAllmanOnly) {
  1541. + if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1)
  1542. + EVP_SignUpdate(&m_allman_sha1ctx, szBuffer, nBufLength);
  1543. + } else {
  1544. + if (m_nIncludeBodyHash < DKIM_BODYHASH_IETF_1)
  1545. + EVP_SignUpdate(&m_allman_sha1ctx, szBuffer, nBufLength);
  1546. + else
  1547. + if (m_nIncludeBodyHash & DKIM_BODYHASH_IETF_1) {
  1548. + if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1)
  1549. + EVP_SignUpdate(&m_allman_sha1ctx, szBuffer, nBufLength);
  1550. +#ifdef HAVE_EVP_SHA256
  1551. + if (m_nHash & DKIM_HASH_SHA256) {
  1552. + if (bHdr)
  1553. + EVP_SignUpdate(&m_Hdr_ietf_sha256ctx, szBuffer, nBufLength);
  1554. + else
  1555. + EVP_DigestUpdate(&m_Bdy_ietf_sha256ctx, szBuffer, nBufLength);
  1556. + }
  1557. + if (m_nHash != DKIM_HASH_SHA256) {
  1558. + if (bHdr)
  1559. + EVP_SignUpdate(&m_Hdr_ietf_sha1ctx, szBuffer, nBufLength);
  1560. + else
  1561. + EVP_DigestUpdate(&m_Bdy_ietf_sha1ctx, szBuffer, nBufLength);
  1562. + }
  1563. +#else
  1564. + if (bHdr)
  1565. + EVP_SignUpdate(&m_Hdr_ietf_sha1ctx, szBuffer, nBufLength);
  1566. + else
  1567. + EVP_DigestUpdate(&m_Bdy_ietf_sha1ctx, szBuffer, nBufLength);
  1568. +#endif
  1569. + }
  1570. + }
  1571. +}
  1572. +
  1573. +
  1574. +////////////////////////////////////////////////////////////////////////////////
  1575. +//
  1576. +// SignThisTag - return boolean whether or not to sign this tag
  1577. +//
  1578. +////////////////////////////////////////////////////////////////////////////////
  1579. +bool CDKIMSign::SignThisTag(const string &sTag)
  1580. +{
  1581. + bool bRet = true;
  1582. +
  1583. + if (_strnicmp(sTag.c_str(), "X-", 2) == 0
  1584. + || _stricmp(sTag.c_str(), "Authentication-Results:") == 0
  1585. + || _stricmp(sTag.c_str(), "DKIM-Signature:") == 0
  1586. + || _stricmp(sTag.c_str(), "Received:") == 0
  1587. + || _stricmp(sTag.c_str(), "Return-Path:") == 0)
  1588. + {
  1589. + bRet = false;
  1590. + }
  1591. + return bRet;
  1592. +}
  1593. +
  1594. +bool
  1595. +ConvertHeaderToQuotedPrintable(const char *source, char *dest)
  1596. +{
  1597. + bool bConvert = false;
  1598. +
  1599. +// do quoted printable
  1600. + static unsigned char hexchars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  1601. + unsigned char *d = (unsigned char *) dest;
  1602. + for (const unsigned char *s = (const unsigned char *)source; *s != '\0'; s++) {
  1603. + if (*s >= 33 && *s <= 126 && *s != '=' && *s != ':' && *s != ';' && *s != '|') {
  1604. + *d++ = *s;
  1605. + }
  1606. +
  1607. + else {
  1608. + bConvert = true;
  1609. + *d++ = '=';
  1610. + *d++ = hexchars[*s >> 4];
  1611. + *d++ = hexchars[*s & 15];
  1612. + }
  1613. + }
  1614. + *d = '\0';
  1615. + return bConvert;
  1616. +}
  1617. +
  1618. +
  1619. +////////////////////////////////////////////////////////////////////////////////
  1620. +//
  1621. +// GetHeaderParams - Extract any needed header parameters
  1622. +//
  1623. +////////////////////////////////////////////////////////////////////////////////
  1624. +void
  1625. +CDKIMSign::GetHeaderParams(const string & sHdr)
  1626. +{
  1627. + if (_strnicmp(sHdr.c_str(), "X", 1) == 0)
  1628. + return;
  1629. + if (_strnicmp(sHdr.c_str(), "From:", 5) == 0)
  1630. + sFrom.assign(sHdr.c_str() + 5);
  1631. + if (_strnicmp(sHdr.c_str(), "Sender:", 7) == 0)
  1632. + sSender.assign(sHdr.c_str() + 7);
  1633. +#if 1
  1634. + if (_strnicmp(sHdr.c_str(), "Return-Path:", 12) == 0)
  1635. + sReturnPath.assign(sHdr.c_str() + 12);
  1636. +#endif
  1637. + if (m_nIncludeCopiedHeaders) {
  1638. + string::size_type pos = sHdr.find(':');
  1639. + if (pos != string::npos) {
  1640. + string sTag, sValue;
  1641. + char *workBuffer = new char[sHdr.size() * 3 + 1];
  1642. + sTag.assign(sHdr.substr(0, pos));
  1643. + sValue.assign(sHdr.substr(pos + 1, string::npos));
  1644. + ConvertHeaderToQuotedPrintable(sTag.c_str(), workBuffer);
  1645. + if (!m_sCopiedHeaders.empty()) {
  1646. + m_sCopiedHeaders.append("|");
  1647. + }
  1648. + m_sCopiedHeaders.append(workBuffer);
  1649. + m_sCopiedHeaders.append(":");
  1650. + ConvertHeaderToQuotedPrintable(sValue.c_str(), workBuffer);
  1651. + m_sCopiedHeaders.append(workBuffer);
  1652. + delete[]workBuffer;
  1653. + }
  1654. + }
  1655. +}
  1656. +
  1657. +// ProcessHeaders - sign headers and save needed parameters
  1658. +int
  1659. +CDKIMSign::ProcessHeaders(void)
  1660. +{
  1661. + map <string, list <string>::reverse_iterator> IterMap;
  1662. + map <string, list <string>::reverse_iterator>::iterator IterMapIter;
  1663. + list <string>::reverse_iterator riter;
  1664. + list <string>::iterator iter;
  1665. + string sTag;
  1666. + bool bFromHeaderFound = false;
  1667. +
  1668. + // walk the header list
  1669. + for (iter = HeaderList.begin(); iter != HeaderList.end(); iter++) {
  1670. + sTag.assign(*iter);
  1671. + // look for a colon
  1672. + string::size_type pos = sTag.find(':');
  1673. + if (pos != string::npos) {
  1674. + int nSignThisTag = 1;
  1675. + // hack off anything past the colon
  1676. + sTag.erase(pos + 1, string::npos);
  1677. + // is this the From: header?
  1678. + if (_stricmp(sTag.c_str(), "From:") == 0) {
  1679. + bFromHeaderFound = true;
  1680. + nSignThisTag = 1;
  1681. + IsRequiredHeader(sTag); // remove from required header list
  1682. + }
  1683. + // is this in the list of headers that must be signed?
  1684. + else
  1685. + if (IsRequiredHeader(sTag))
  1686. + nSignThisTag = 1;
  1687. + else {
  1688. + if (m_pfnHdrCallback)
  1689. + nSignThisTag = m_pfnHdrCallback(iter->c_str());
  1690. + else
  1691. + nSignThisTag = SignThisTag(sTag) ? 1 : 0;
  1692. + }
  1693. + // save header parameters
  1694. + GetHeaderParams(*iter);
  1695. + if (nSignThisTag > 0) {
  1696. + // add this tag to h=
  1697. + hParam.append(sTag);
  1698. + IterMapIter = IterMap.find(sTag);
  1699. + riter = (IterMapIter == IterMap.end())? HeaderList.rbegin() : IterMapIter->second;
  1700. + // walk the list in reverse looking for the last instance of this header
  1701. + while (riter != HeaderList.rend()) {
  1702. + if (_strnicmp(riter->c_str(), sTag.c_str(), sTag.size()) == 0) {
  1703. + ProcessHeader(*riter);
  1704. + // save the reverse iterator position for this tag
  1705. + riter++;
  1706. + IterMap[sTag] = riter;
  1707. + break;
  1708. + }
  1709. + riter++;
  1710. + }
  1711. + }
  1712. + }
  1713. + }
  1714. + Hash("\r\n", 2, true, true); // only for Allman sig
  1715. + if (!bFromHeaderFound) {
  1716. + string sFrom("From:");
  1717. + hParam.append(sFrom);
  1718. + IsRequiredHeader(sFrom); // remove from required header list
  1719. + }
  1720. + hParam.append(sRequiredHeaders);
  1721. + if (hParam.at(hParam.size() - 1) == ':')
  1722. + hParam.erase(hParam.size() - 1, string::npos);
  1723. + return DKIM_SUCCESS;
  1724. +}
  1725. +
  1726. +char *DKIM_CALL
  1727. +CDKIMSign::GetDomain(void)
  1728. +{
  1729. + if (ParseFromAddress() == false)
  1730. + return ((char *) 0);
  1731. + return ((char *) sDomain.c_str());
  1732. +}
  1733. +
  1734. +void
  1735. +CDKIMSign::ProcessHeader(const string & sHdr)
  1736. +{
  1737. + switch (HIWORD(m_Canon)) {
  1738. + case DKIM_CANON_SIMPLE:
  1739. + Hash(sHdr.c_str(), sHdr.size(), true);
  1740. + Hash("\r\n", 2, true);
  1741. + break;
  1742. + case DKIM_CANON_NOWSP:
  1743. + {
  1744. + string sTemp = sHdr;
  1745. + RemoveSWSP(sTemp);
  1746. + // convert characters before ':' to lower case
  1747. + for (char *s = (char *)sTemp.c_str(); *s != '\0' && *s != ':'; s++) {
  1748. + if (*s >= 'A' && *s <= 'Z')
  1749. + *s += 'a' - 'A';
  1750. + }
  1751. + Hash(sTemp.c_str(), sTemp.size(), true);
  1752. + Hash("\r\n", 2, true);
  1753. + }
  1754. + break;
  1755. + case DKIM_CANON_RELAXED:
  1756. + {
  1757. + string sTemp = RelaxHeader(sHdr);
  1758. + Hash(sTemp.c_str(), sTemp.length(), true);
  1759. + Hash("\r\n", 2, true);
  1760. + }
  1761. + break;
  1762. + }
  1763. +}
  1764. +
  1765. +int CDKIMSign::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
  1766. +{
  1767. + switch (LOWORD(m_Canon)) {
  1768. + case DKIM_CANON_SIMPLE:
  1769. + if (nBufLength > 0) {
  1770. + while (m_EmptyLineCount > 0) {
  1771. + Hash("\r\n", 2, false);
  1772. + m_nBodyLength += 2;
  1773. + m_EmptyLineCount--;
  1774. + }
  1775. + Hash(szBuffer, nBufLength, false);
  1776. + Hash("\r\n", 2, false);
  1777. + m_nBodyLength += nBufLength + 2;
  1778. + } else {
  1779. + m_EmptyLineCount++;
  1780. + if (bEOF) {
  1781. + Hash("\r\n", 2, false);
  1782. + m_nBodyLength += 2;
  1783. + }
  1784. + }
  1785. + break;
  1786. + case DKIM_CANON_NOWSP:
  1787. + RemoveSWSP(szBuffer, nBufLength);
  1788. + if (nBufLength > 0) {
  1789. + Hash(szBuffer, nBufLength, false);
  1790. + m_nBodyLength += nBufLength;
  1791. + }
  1792. + break;
  1793. + case DKIM_CANON_RELAXED:
  1794. + CompressSWSP(szBuffer, nBufLength);
  1795. + if (nBufLength > 0) {
  1796. + while (m_EmptyLineCount > 0) {
  1797. + Hash("\r\n", 2, false);
  1798. + m_nBodyLength += 2;
  1799. + m_EmptyLineCount--;
  1800. + }
  1801. + Hash(szBuffer, nBufLength, false);
  1802. + m_nBodyLength += nBufLength;
  1803. + if (!bEOF) {
  1804. + Hash("\r\n", 2, false);
  1805. + m_nBodyLength += 2;
  1806. + }
  1807. + } else
  1808. + m_EmptyLineCount++;
  1809. + break;
  1810. + }
  1811. + return DKIM_SUCCESS;
  1812. +}
  1813. +
  1814. +bool CDKIMSign::ParseFromAddress(void)
  1815. +{
  1816. + string::size_type pos;
  1817. + string sAddress;
  1818. + char *p, *at;
  1819. +
  1820. +#if 1
  1821. + /* thanks to fred */
  1822. + if (!sReturnPath.empty())
  1823. + sAddress.assign(sReturnPath);
  1824. + else
  1825. +#endif
  1826. + if (!sSender.empty())
  1827. + sAddress.assign(sSender);
  1828. + else
  1829. + if (!sFrom.empty())
  1830. + sAddress.assign(sFrom);
  1831. + else
  1832. + return false;
  1833. + // simple for now, beef it up later
  1834. + // remove '<' and anything before it
  1835. + pos = sAddress.find('<');
  1836. + if (pos != string::npos)
  1837. + sAddress.erase(0, pos);
  1838. + // remove '>' and anything after it
  1839. + pos = sAddress.find('>');
  1840. + if (pos != string::npos)
  1841. + sAddress.erase(pos, string::npos);
  1842. + // look for '@' symbol
  1843. + pos = sAddress.find('@');
  1844. + if (pos == string::npos)
  1845. + return false;
  1846. + if (sDomain.empty()) {
  1847. + p = getenv("DKIMDOMAIN");
  1848. + if (p && *p)
  1849. + {
  1850. + if (!(at = strchr(p, '@')))
  1851. + at = p;
  1852. + else
  1853. + at++;
  1854. + sDomain.assign(at);
  1855. + } else
  1856. + sDomain.assign(sAddress.c_str() + pos + 1);
  1857. + RemoveSWSP(sDomain);
  1858. + }
  1859. + return true;
  1860. +}
  1861. +
  1862. +
  1863. +////////////////////////////////////////////////////////////////////////////////
  1864. +//
  1865. +// InitSig - initialize signature folding algorithm
  1866. +//
  1867. +////////////////////////////////////////////////////////////////////////////////
  1868. +void
  1869. +CDKIMSign::InitSig(void)
  1870. +{
  1871. + m_sSig.reserve(1024);
  1872. + m_sSig.assign("DKIM-Signature:");
  1873. + m_nSigPos = m_sSig.size();
  1874. +}
  1875. +
  1876. +////////////////////////////////////////////////////////////////////////////////
  1877. +//
  1878. +// AddTagToSig - add tag and value to signature folding if necessary
  1879. +// if bFold, fold at cbrk char
  1880. +//
  1881. +////////////////////////////////////////////////////////////////////////////////
  1882. +void CDKIMSign::AddTagToSig(char *Tag, const string & sValue, char cbrk, bool bFold)
  1883. +{
  1884. + int
  1885. + nTagLen = strlen(Tag);
  1886. + AddInterTagSpace((!bFold) ? sValue.size() + nTagLen + 2 : nTagLen + 2);
  1887. + m_sSig.append(Tag);
  1888. + m_sSig.append("=");
  1889. + m_nSigPos += 1 + nTagLen;
  1890. + if (!bFold) {
  1891. + m_sSig.append(sValue);
  1892. + m_nSigPos += sValue.size();
  1893. + }
  1894. +
  1895. + else {
  1896. + AddFoldedValueToSig(sValue, cbrk);
  1897. + }
  1898. + m_sSig.append(";");
  1899. + m_nSigPos++;
  1900. +}
  1901. +
  1902. +
  1903. +////////////////////////////////////////////////////////////////////////////////
  1904. +//
  1905. +// AddTagToSig - add tag and numeric value to signature folding if necessary
  1906. +//
  1907. +////////////////////////////////////////////////////////////////////////////////
  1908. +void CDKIMSign::AddTagToSig(char *Tag, unsigned long nValue)
  1909. +{
  1910. + char szValue[64];
  1911. + sprintf(szValue, "%u", nValue);
  1912. + AddTagToSig(Tag, szValue, 0, false);
  1913. +}
  1914. +
  1915. +////////////////////////////////////////////////////////////////////////////////
  1916. +//
  1917. +// AddInterTagSpace - add space or fold here
  1918. +//
  1919. +////////////////////////////////////////////////////////////////////////////////
  1920. +void CDKIMSign::AddInterTagSpace(int nSizeOfNextTag)
  1921. +{
  1922. + if (m_nSigPos + nSizeOfNextTag + 1 > OptimalHeaderLineLength) {
  1923. + m_sSig.append("\n\t");
  1924. + m_nSigPos = 1;
  1925. + }
  1926. +
  1927. + else {
  1928. + m_sSig.append(" ");
  1929. + m_nSigPos++;
  1930. + }
  1931. +}
  1932. +
  1933. +
  1934. +////////////////////////////////////////////////////////////////////////////////
  1935. +//
  1936. +// AddTagToSig - add value to signature folding if necessary
  1937. +// if cbrk == 0 fold anywhere, otherwise fold only at cbrk
  1938. +//
  1939. +////////////////////////////////////////////////////////////////////////////////
  1940. +void CDKIMSign::AddFoldedValueToSig(const string & sValue, char cbrk)
  1941. +{
  1942. + string::size_type pos = 0;
  1943. + if (cbrk == 0) {
  1944. +
  1945. + // fold anywhere
  1946. + while (pos < sValue.size()) {
  1947. + string::size_type len = OptimalHeaderLineLength - m_nSigPos;
  1948. + if (len > sValue.size() - pos)
  1949. + len = sValue.size() - pos;
  1950. + m_sSig.append(sValue.substr(pos, len));
  1951. + m_nSigPos += len;
  1952. + pos += len;
  1953. + if (pos < sValue.size()) {
  1954. + m_sSig.append("\n\t");
  1955. + m_nSigPos = 1;
  1956. + }
  1957. + }
  1958. + }
  1959. +
  1960. + else {
  1961. +
  1962. + // fold only at cbrk
  1963. + while (pos < sValue.size()) {
  1964. + string::size_type len = OptimalHeaderLineLength - m_nSigPos;
  1965. + string::size_type brkpos;
  1966. + if (sValue.size() - pos < len) {
  1967. + brkpos = sValue.size() - 1;
  1968. + }
  1969. +
  1970. + else {
  1971. + brkpos = sValue.rfind(cbrk, pos + len);
  1972. + }
  1973. + if (brkpos == string::npos || brkpos < pos) {
  1974. + brkpos = sValue.find(cbrk, pos);
  1975. + if (brkpos == string::npos) {
  1976. + brkpos = sValue.size();
  1977. + }
  1978. + }
  1979. + len = brkpos - pos + 1;
  1980. + m_sSig.append(sValue.substr(pos, len));
  1981. + m_nSigPos += len;
  1982. + pos += len;
  1983. + if (pos < sValue.size()) {
  1984. +
  1985. + //m_sSig.append( "\r\n\t" );
  1986. + m_sSig.append("\n\t");
  1987. + m_nSigPos = 1;
  1988. + }
  1989. + }
  1990. + }
  1991. +}
  1992. +
  1993. +
  1994. +////////////////////////////////////////////////////////////////////////////////
  1995. +//
  1996. +// GetSig - compute hash and return signature header in szSignature
  1997. +//
  1998. +////////////////////////////////////////////////////////////////////////////////
  1999. +int CDKIMSign::GetSig(char *szPrivKey, char *szSignature, int nSigLength)
  2000. +{
  2001. + if (szPrivKey == NULL) {
  2002. + return DKIM_BAD_PRIVATE_KEY;
  2003. + }
  2004. + if (szSignature == NULL) {
  2005. + return DKIM_BUFFER_TOO_SMALL;
  2006. + }
  2007. + int nRet = AssembleReturnedSig(szPrivKey);
  2008. + if (nRet != DKIM_SUCCESS)
  2009. + return nRet;
  2010. + if (m_sReturnedSig.size() + 1 < nSigLength)
  2011. + strcpy(szSignature, m_sReturnedSig.c_str());
  2012. + else
  2013. + return DKIM_BUFFER_TOO_SMALL;
  2014. + return DKIM_SUCCESS;
  2015. +}
  2016. +
  2017. +
  2018. +////////////////////////////////////////////////////////////////////////////////
  2019. +//
  2020. +// GetSig - compute hash and return signature header in szSignature
  2021. +//
  2022. +////////////////////////////////////////////////////////////////////////////////
  2023. +int CDKIMSign::GetSig2(char *szPrivKey, char **pszSignature)
  2024. +{
  2025. + if (szPrivKey == NULL) {
  2026. + return DKIM_BAD_PRIVATE_KEY;
  2027. + }
  2028. + if (pszSignature == NULL) {
  2029. + return DKIM_BUFFER_TOO_SMALL;
  2030. + }
  2031. + int nRet = AssembleReturnedSig(szPrivKey);
  2032. + if (nRet != DKIM_SUCCESS)
  2033. + return nRet;
  2034. + *pszSignature = (char *) m_sReturnedSig.c_str();
  2035. + return DKIM_SUCCESS;
  2036. +}
  2037. +
  2038. +
  2039. +////////////////////////////////////////////////////////////////////////////////
  2040. +//
  2041. +// IsRequiredHeader - Check if header in required list. If so, delete
  2042. +// header from list.
  2043. +//
  2044. +////////////////////////////////////////////////////////////////////////////////
  2045. +bool CDKIMSign::IsRequiredHeader(const string & sTag)
  2046. +{
  2047. + string::size_type start = 0;
  2048. + string::size_type end = sRequiredHeaders.find(':');
  2049. + while (end != string::npos) {
  2050. +
  2051. + // check for a zero-length header
  2052. + if (start == end) {
  2053. + sRequiredHeaders.erase(start, 1);
  2054. + }
  2055. +
  2056. + else {
  2057. + if (_stricmp(sTag.c_str(), sRequiredHeaders.substr(start, end - start + 1).c_str()) == 0) {
  2058. + sRequiredHeaders.erase(start, end - start + 1);
  2059. + return true;
  2060. + }
  2061. +
  2062. + else {
  2063. + start = end + 1;
  2064. + }
  2065. + }
  2066. + end = sRequiredHeaders.find(':', start);
  2067. + }
  2068. + return false;
  2069. +}
  2070. +
  2071. +int CDKIMSign::ConstructSignature(char *szPrivKey, bool bUseIetfBodyHash, bool bUseSha256)
  2072. +{
  2073. + string sSignedSig;
  2074. + unsigned char *sig;
  2075. + EVP_PKEY *pkey;
  2076. + BIO *bio, *b64;
  2077. + unsigned int siglen;
  2078. + int size;
  2079. + int len;
  2080. + char *buf;
  2081. + int pos = 0;
  2082. +
  2083. +// construct the DKIM-Signature: header and add to hash
  2084. + InitSig();
  2085. + if (bUseIetfBodyHash) {
  2086. + AddTagToSig((char *) "v", (char *) "1", 0, false);
  2087. + }
  2088. +#ifdef HAVE_EVP_SHA256
  2089. + AddTagToSig((char *) "a", bUseSha256 ? "rsa-sha256" : "rsa-sha1", 0, false);
  2090. +#else
  2091. + AddTagToSig((char *) "a", "rsa-sha1", 0, false);
  2092. +#endif
  2093. + switch (m_Canon) {
  2094. + case DKIM_SIGN_SIMPLE:
  2095. + AddTagToSig((char *) "c", "simple", 0, false);
  2096. + break;
  2097. + case DKIM_SIGN_SIMPLE_RELAXED:
  2098. + AddTagToSig((char *) "c", "simple/relaxed", 0, false);
  2099. + break;
  2100. + case DKIM_SIGN_RELAXED:
  2101. + AddTagToSig((char *) "c", "relaxed/relaxed", 0, false);
  2102. + break;
  2103. + case DKIM_SIGN_RELAXED_SIMPLE:
  2104. + AddTagToSig((char *) "c", "relaxed", 0, false);
  2105. + break;
  2106. + }
  2107. + AddTagToSig((char *) "d", sDomain, 0, false);
  2108. + AddTagToSig((char *) "s", sSelector, 0, false);
  2109. + if (m_IncludeBodyLengthTag) {
  2110. + AddTagToSig((char *) "l", m_nBodyLength);
  2111. + }
  2112. + if (m_nIncludeTimeStamp != 0) {
  2113. + time_t t;
  2114. + time(&t);
  2115. + AddTagToSig((char *) "t", t);
  2116. + }
  2117. + if (m_ExpireTime != 0) {
  2118. + AddTagToSig((char *) "x", m_ExpireTime);
  2119. + }
  2120. + if (!sIdentity.empty()) {
  2121. + AddTagToSig((char *) "i", sIdentity, 0, false);
  2122. + }
  2123. + if (m_nIncludeQueryMethod) {
  2124. + AddTagToSig((char *) "q", bUseIetfBodyHash ? "dns/txt" : "dns", 0, false);
  2125. + }
  2126. + AddTagToSig((char *) "h", hParam, ':', true);
  2127. + if (m_nIncludeCopiedHeaders) {
  2128. + AddTagToSig((char *) "z", m_sCopiedHeaders, 0, true);
  2129. + }
  2130. + if (bUseIetfBodyHash) {
  2131. + unsigned char Hash[EVP_MAX_MD_SIZE];
  2132. + unsigned int nHashLen = 0;
  2133. +#ifdef HAVE_EVP_SHA256
  2134. + EVP_DigestFinal(bUseSha256 ? &m_Bdy_ietf_sha256ctx : &m_Bdy_ietf_sha1ctx, Hash, &nHashLen);
  2135. +#else
  2136. + EVP_DigestFinal(&m_Bdy_ietf_sha1ctx, Hash, &nHashLen);
  2137. +#endif
  2138. + bio = BIO_new(BIO_s_mem());
  2139. + if (!bio) {
  2140. + return DKIM_OUT_OF_MEMORY;
  2141. + }
  2142. + b64 = BIO_new(BIO_f_base64());
  2143. + if (!b64) {
  2144. + BIO_free(bio);
  2145. + return DKIM_OUT_OF_MEMORY;
  2146. + }
  2147. + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  2148. + BIO_push(b64, bio);
  2149. + if (BIO_write(b64, Hash, nHashLen) < nHashLen) {
  2150. + BIO_free_all(b64);
  2151. + return DKIM_OUT_OF_MEMORY;
  2152. + }
  2153. + BIO_flush(b64);
  2154. + len = nHashLen * 2;
  2155. + buf = new char[len];
  2156. + if (buf == NULL) {
  2157. + BIO_free_all(b64);
  2158. + return DKIM_OUT_OF_MEMORY;
  2159. + }
  2160. + size = BIO_read(bio, buf, len);
  2161. + BIO_free_all(b64);
  2162. + // this should never happen
  2163. + if (size >= len) {
  2164. + delete[]buf;
  2165. + return DKIM_OUT_OF_MEMORY;
  2166. + }
  2167. + buf[size] = '\0';
  2168. + AddTagToSig((char *) "bh", buf, 0, true);
  2169. + delete[]buf;
  2170. + }
  2171. + AddInterTagSpace(3);
  2172. + m_sSig.append("b=");
  2173. + m_nSigPos += 2;
  2174. + // Force a full copy - no reference copies please
  2175. + sSignedSig.assign(m_sSig.c_str());
  2176. + // note that since we're not calling hash here, need to dump this
  2177. + // to the debug file if you want the full canonical form
  2178. + string sTemp;
  2179. + if (HIWORD(m_Canon) == DKIM_CANON_RELAXED)
  2180. + sTemp = RelaxHeader(sSignedSig);
  2181. + else
  2182. + sTemp = sSignedSig.c_str();
  2183. + if (bUseIetfBodyHash) {
  2184. +#ifdef HAVE_EVP_SHA256
  2185. + EVP_SignUpdate(bUseSha256 ? &m_Hdr_ietf_sha256ctx : &m_Hdr_ietf_sha1ctx, sTemp.c_str(), sTemp.size());
  2186. +#else
  2187. + EVP_SignUpdate(&m_Hdr_ietf_sha1ctx, sTemp.c_str(), sTemp.size());
  2188. +#endif
  2189. + } else
  2190. + EVP_SignUpdate(&m_allman_sha1ctx, sTemp.c_str(), sTemp.size());
  2191. + if (!(bio = BIO_new_mem_buf(szPrivKey, -1)))
  2192. + return DKIM_OUT_OF_MEMORY;
  2193. + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
  2194. + BIO_free(bio);
  2195. + if (!pkey) {
  2196. + return DKIM_BAD_PRIVATE_KEY;
  2197. + }
  2198. + siglen = EVP_PKEY_size(pkey);
  2199. + int nSignRet;
  2200. + sig = (unsigned char *) OPENSSL_malloc(siglen);
  2201. + if (sig == NULL) {
  2202. + EVP_PKEY_free(pkey);
  2203. + return DKIM_OUT_OF_MEMORY;
  2204. + }
  2205. + if (bUseIetfBodyHash) {
  2206. +#ifdef HAVE_EVP_SHA256
  2207. + nSignRet = EVP_SignFinal(bUseSha256 ? &m_Hdr_ietf_sha256ctx : &m_Hdr_ietf_sha1ctx, sig, &siglen, pkey);
  2208. +#else
  2209. + nSignRet = EVP_SignFinal(&m_Hdr_ietf_sha1ctx, sig, &siglen, pkey);
  2210. +#endif
  2211. + } else
  2212. + nSignRet = EVP_SignFinal(&m_allman_sha1ctx, sig, &siglen, pkey);
  2213. + EVP_PKEY_free(pkey);
  2214. + if (!nSignRet) {
  2215. + OPENSSL_free(sig);
  2216. + return DKIM_BAD_PRIVATE_KEY; // key too small
  2217. + }
  2218. + bio = BIO_new(BIO_s_mem());
  2219. + if (!bio) {
  2220. + return DKIM_OUT_OF_MEMORY;
  2221. + }
  2222. + b64 = BIO_new(BIO_f_base64());
  2223. + if (!b64) {
  2224. + BIO_free(bio);
  2225. + return DKIM_OUT_OF_MEMORY;
  2226. + }
  2227. + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  2228. + BIO_push(b64, bio);
  2229. + if (BIO_write(b64, sig, siglen) < siglen) {
  2230. + OPENSSL_free(sig);
  2231. + BIO_free_all(b64);
  2232. + return DKIM_OUT_OF_MEMORY;
  2233. + }
  2234. + BIO_flush(b64);
  2235. + OPENSSL_free(sig);
  2236. + len = siglen * 2;
  2237. + buf = new char[len];
  2238. + if (buf == NULL) {
  2239. + BIO_free_all(b64);
  2240. + return DKIM_OUT_OF_MEMORY;
  2241. + }
  2242. + size = BIO_read(bio, buf, len);
  2243. + BIO_free_all(b64);
  2244. + // this should never happen
  2245. + if (size >= len) {
  2246. + delete[]buf;
  2247. + return DKIM_OUT_OF_MEMORY;
  2248. + }
  2249. + buf[size] = '\0';
  2250. + AddFoldedValueToSig(buf, 0);
  2251. + delete[]buf;
  2252. + return DKIM_SUCCESS;
  2253. +}
  2254. +
  2255. +int CDKIMSign::AssembleReturnedSig(char *szPrivKey)
  2256. +{
  2257. + int nRet;
  2258. + if (m_bReturnedSigAssembled)
  2259. + return DKIM_SUCCESS;
  2260. + ProcessFinal();
  2261. + if (ParseFromAddress() == false) {
  2262. + //return DKIM_NO_SENDER;
  2263. + }
  2264. + Hash("\r\n", 2, true, true); // only for Allman sig
  2265. + string allmansha1sig,
  2266. +#ifdef HAVE_EVP_SHA256
  2267. + ietfsha256Sig,
  2268. +#endif
  2269. + ietfsha1Sig;
  2270. + if (m_nIncludeBodyHash < DKIM_BODYHASH_IETF_1) {
  2271. + nRet = ConstructSignature(szPrivKey, false, false);
  2272. + if (nRet == DKIM_SUCCESS)
  2273. + allmansha1sig.assign(m_sSig);
  2274. + else
  2275. + return nRet;
  2276. + } else
  2277. + if (m_nIncludeBodyHash & DKIM_BODYHASH_IETF_1) {
  2278. + if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1) {
  2279. + if ((nRet = ConstructSignature(szPrivKey, false, false)) == DKIM_SUCCESS)
  2280. + allmansha1sig.assign(m_sSig);
  2281. + else
  2282. + return nRet;
  2283. + }
  2284. +#ifdef HAVE_EVP_SHA256
  2285. + if (m_nHash & DKIM_HASH_SHA256) {
  2286. + if ((nRet = ConstructSignature(szPrivKey, true, true)) == DKIM_SUCCESS)
  2287. + ietfsha256Sig.assign(m_sSig);
  2288. + else
  2289. + return nRet;
  2290. + }
  2291. + if (m_nHash != DKIM_HASH_SHA256) {
  2292. + if ((nRet = ConstructSignature(szPrivKey, true, false)) == DKIM_SUCCESS)
  2293. + ietfsha1Sig.assign(m_sSig);
  2294. + else
  2295. + return nRet;
  2296. + }
  2297. +#else
  2298. + if ((nRet = ConstructSignature(szPrivKey, true, false)) == DKIM_SUCESS)
  2299. + ietfsha1Sig.assign(m_sSig);
  2300. + else
  2301. + return nRet;
  2302. +#endif
  2303. + }
  2304. + m_sReturnedSig.assign(allmansha1sig);
  2305. + if (!ietfsha1Sig.empty()) {
  2306. + if (!m_sReturnedSig.empty())
  2307. + m_sReturnedSig.append("\n");
  2308. + m_sReturnedSig.append(ietfsha1Sig);
  2309. + }
  2310. +#ifdef HAVE_EVP_SHA256
  2311. + if (!ietfsha256Sig.empty()) {
  2312. + if (!m_sReturnedSig.empty())
  2313. + m_sReturnedSig.append("\n");
  2314. + m_sReturnedSig.append(ietfsha256Sig);
  2315. + }
  2316. +#endif
  2317. + m_bReturnedSigAssembled = true;
  2318. + return DKIM_SUCCESS;
  2319. +}
  2320. +
  2321. +void
  2322. +getversion_dkimsign_cpp()
  2323. +{
  2324. + static char *x = (char *) "$Id: dkimsign.cpp,v 1.4 2009-04-15 21:32:12+05:30 Cprogrammer Exp mbhangui $";
  2325. +
  2326. + x++;
  2327. +}
  2328. diff -Naur qmail-1.03.org/dkimsign.h qmail-1.03/dkimsign.h
  2329. --- qmail-1.03.org/dkimsign.h 1970-01-01 05:30:00.000000000 +0530
  2330. +++ qmail-1.03/dkimsign.h 2009-04-21 11:19:07.000000000 +0530
  2331. @@ -0,0 +1,93 @@
  2332. +/*
  2333. + * $Log: dkimsign.h,v $
  2334. + * Revision 1.2 2009-03-26 15:11:57+05:30 Cprogrammer
  2335. + * fixed indentation
  2336. + *
  2337. + * Revision 1.1 2009-03-21 08:50:21+05:30 Cprogrammer
  2338. + * Initial revision
  2339. + *
  2340. + *
  2341. + * Copyright 2005 Alt-N Technologies, Ltd.
  2342. + *
  2343. + * Licensed under the Apache License, Version 2.0 (the "License");
  2344. + * you may not use this file except in compliance with the License.
  2345. + * You may obtain a copy of the License at
  2346. + *
  2347. + * http://www.apache.org/licenses/LICENSE-2.0
  2348. + *
  2349. + * This code incorporates intellectual property owned by Yahoo! and licensed
  2350. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  2351. + *
  2352. + * Unless required by applicable law or agreed to in writing, software
  2353. + * distributed under the License is distributed on an "AS IS" BASIS,
  2354. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2355. + * See the License for the specific language governing permissions and
  2356. + * limitations under the License.
  2357. + *
  2358. + */
  2359. +
  2360. +#ifndef DKIMSIGN_H
  2361. +#define DKIMSIGN_H
  2362. +
  2363. +#include "dkimbase.h"
  2364. +
  2365. +class CDKIMSign:public CDKIMBase {
  2366. +public:
  2367. +
  2368. + CDKIMSign();
  2369. + ~CDKIMSign();
  2370. + int Init(DKIMSignOptions * pOptions);
  2371. + int GetSig(char *szPrivKey, char *szSignature, int nSigLength);
  2372. + int GetSig2(char *szPrivKey, char **pszSignature);
  2373. + virtual int ProcessHeaders(void);
  2374. + virtual int ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
  2375. + enum CKDKIMConstants { OptimalHeaderLineLength = 65 };
  2376. + char *DKIM_CALL GetDomain(void);
  2377. +
  2378. +protected:
  2379. + void Hash(const char *szBuffer, int nBufLength, bool bHdr, bool bAllmanOnly = false);
  2380. + bool SignThisTag(const string & sTag);
  2381. + void GetHeaderParams(const string & sHdr);
  2382. + void ProcessHeader(const string & sHdr);
  2383. + bool ParseFromAddress(void);
  2384. + void InitSig(void);
  2385. + void AddTagToSig(char *Tag, const string & sValue, char cbrk, bool bFold);
  2386. + void AddTagToSig(char *Tag, unsigned long nValue);
  2387. + void AddInterTagSpace(int nSizeOfNextTag);
  2388. + void AddFoldedValueToSig(const string & sValue, char cbrk);
  2389. + bool IsRequiredHeader(const string & sTag);
  2390. + int ConstructSignature(char *szPrivKey, bool bUseIetfBodyHash, bool bUseSha256);
  2391. + int AssembleReturnedSig(char *szPrivKey);
  2392. + EVP_MD_CTX m_Hdr_ietf_sha1ctx; /* the header hash for ietf sha1 */
  2393. + EVP_MD_CTX m_Hdr_ietf_sha256ctx; /* the header hash for ietf sha256 */
  2394. + EVP_MD_CTX m_Bdy_ietf_sha1ctx; /* the body hash for ietf sha1 */
  2395. + EVP_MD_CTX m_Bdy_ietf_sha256ctx; /* the body hash for ietf sha256 */
  2396. + EVP_MD_CTX m_allman_sha1ctx; /* the hash for allman sha1 */
  2397. + int m_Canon; // canonization method
  2398. + int m_EmptyLineCount;
  2399. + string hParam;
  2400. + string sFrom;
  2401. + string sSender;
  2402. + string sSelector;
  2403. + string sReturnPath;
  2404. + string sDomain;
  2405. + string sIdentity; // for i= tag, if empty tag will not be included in sig
  2406. + string sRequiredHeaders;
  2407. + bool m_IncludeBodyLengthTag;
  2408. + int m_nBodyLength;
  2409. + time_t m_ExpireTime;
  2410. + int m_nIncludeTimeStamp; // 0 = don't include t= tag, 1 = include t= tag
  2411. + int m_nIncludeQueryMethod; // 0 = don't include q= tag, 1 = include q= tag
  2412. + int m_nHash; // use one of the DKIM_HASH_xx constants here
  2413. + int m_nIncludeCopiedHeaders; // 0 = don't include z= tag, 1 = include z= tag
  2414. + int m_nIncludeBodyHash; // 0 = calculate sig using draft 0, 1 = include bh= tag and
  2415. + // use new signature computation algorithm
  2416. + DKIMHEADERCALLBACK m_pfnHdrCallback;
  2417. + string m_sSig;
  2418. + int m_nSigPos;
  2419. + string m_sReturnedSig;
  2420. + bool m_bReturnedSigAssembled;
  2421. + string m_sCopiedHeaders;
  2422. +};
  2423. +
  2424. +#endif // DKIMSIGN_H
  2425. diff -Naur qmail-1.03.org/dkimtest.c qmail-1.03/dkimtest.c
  2426. --- qmail-1.03.org/dkimtest.c 1970-01-01 05:30:00.000000000 +0530
  2427. +++ qmail-1.03/dkimtest.c 2009-04-21 11:19:07.000000000 +0530
  2428. @@ -0,0 +1,850 @@
  2429. +/*
  2430. + * $Log: dkim.c,v $
  2431. + * Revision 1.10 2009-04-15 21:30:32+05:30 Cprogrammer
  2432. + * added DKIM-Signature to list of excluded headers
  2433. + *
  2434. + * Revision 1.9 2009-04-15 20:45:04+05:30 Cprogrammer
  2435. + * corrected usage
  2436. + *
  2437. + * Revision 1.8 2009-04-05 19:04:44+05:30 Cprogrammer
  2438. + * improved formating of usage
  2439. + *
  2440. + * Revision 1.7 2009-04-03 12:05:25+05:30 Cprogrammer
  2441. + * minor changes on usage display
  2442. + *
  2443. + * Revision 1.6 2009-03-28 20:15:23+05:30 Cprogrammer
  2444. + * invoke DKIMVerifyGetDetails()
  2445. + *
  2446. + * Revision 1.5 2009-03-27 20:43:48+05:30 Cprogrammer
  2447. + * added HAVE_OPENSSL_EVP_H conditional
  2448. + *
  2449. + * Revision 1.4 2009-03-27 20:19:28+05:30 Cprogrammer
  2450. + * added ADSP
  2451. + *
  2452. + * Revision 1.3 2009-03-26 15:10:53+05:30 Cprogrammer
  2453. + * added ADSP
  2454. + *
  2455. + * Revision 1.2 2009-03-25 08:37:45+05:30 Cprogrammer
  2456. + * added dkim_error
  2457. + *
  2458. + * Revision 1.1 2009-03-21 08:24:47+05:30 Cprogrammer
  2459. + * Initial revision
  2460. + *
  2461. + *
  2462. + * This code incorporates intellectual property owned by Yahoo! and licensed
  2463. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  2464. + *
  2465. + * Unless required by applicable law or agreed to in writing, software
  2466. + * distributed under the License is distributed on an "AS IS" BASIS,
  2467. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2468. + * See the License for the specific language governing permissions and
  2469. + * limitations under the License.
  2470. + */
  2471. +/*
  2472. + * (cat /tmp/test.msg|./dkimtest -z 2 -b 1 -y private \
  2473. + * -s /var/indimail/control/domainkeys/private ;cat /tmp/test.msg )|./dkimtest -v
  2474. + */
  2475. +#ifndef __cplusplus
  2476. +#error A C++ compiler is required!
  2477. +#endif
  2478. +#ifdef HAVE_CONFIG_H
  2479. +#include "config.h"
  2480. +#else
  2481. +#define HAVE_EVP_SHA256
  2482. +#endif
  2483. +
  2484. +#include <stdio.h>
  2485. +#include <fcntl.h>
  2486. +#include <errno.h>
  2487. +#include <unistd.h>
  2488. +#include <string.h>
  2489. +#include <time.h>
  2490. +#include <stdlib.h>
  2491. +#include <sys/types.h>
  2492. +#include <sys/stat.h>
  2493. +#include "dkim.h"
  2494. +#include "dkimdns.h"
  2495. +
  2496. +#ifdef HAVE_OPENSSL_EVP_H
  2497. +#include <openssl/evp.h>
  2498. +#define DKIM_MALLOC(s) OPENSSL_malloc(s)
  2499. +#define DKIM_MFREE(s) OPENSSL_free(s); s = NULL;
  2500. +#else
  2501. +#define DKIM_MALLOC(s) malloc(s)
  2502. +#define DKIM_MFREE(s) free(s); s = NULL;
  2503. +#endif
  2504. +
  2505. +int DKIM_CALL
  2506. +SignThisHeader(const char *szHeader)
  2507. +{
  2508. + if (!strncasecmp(szHeader, "X-", 2)
  2509. + || !strncasecmp(szHeader, "Received:", 9)
  2510. + || !strncasecmp(szHeader, "DKIM-Signature:", 15)
  2511. + || !strncasecmp(szHeader, "Authentication-Results:", 23)
  2512. + || !strncasecmp(szHeader, "DomainKey-Signature", 19)
  2513. + || !strncasecmp(szHeader, "Return-Path:", 12))
  2514. + {
  2515. + return 0;
  2516. + }
  2517. + return 1;
  2518. +}
  2519. +
  2520. +char *program;
  2521. +
  2522. +void
  2523. +usage()
  2524. +{
  2525. +#ifdef HAVE_EVP_SHA256
  2526. + fprintf(stderr, "usage: %s [-lqthvH] [-b <1|2|3>] [-c <r|s|t|u>] [-p <1|2>]\n\t[-d domain] [-i you@domain] [-x expire_time] [-z hash] [-y selector] -s privkeyfile\n", program);
  2527. +#else
  2528. + fprintf(stderr, "usage: %s [-lqthvH] [-b <1|2|3>] [-c <r|s|t|u>] [-p <1|2>]\n\t[-d domain] [-i you@domain] [-x expire_time] [-y selector] -s privkeyfile\n", program);
  2529. +#endif
  2530. + fprintf(stderr, "p <ssp|adsp> 0 - disable practice, 1- SSP, or 2 - ADSP verification\n");
  2531. + fprintf(stderr, "l include body length tag\n");
  2532. + fprintf(stderr, "q include query method tag\n");
  2533. + fprintf(stderr, "t include a timestamp tag\n");
  2534. + fprintf(stderr, "h include Copied Headers\n");
  2535. + fprintf(stderr, "v verify the message\n");
  2536. + fprintf(stderr, "b <standard> 1 - allman, 2 - ietf or 3 - both\n");
  2537. + fprintf(stderr, "c <canonicalization> r for relaxed [DEFAULT], s - simple, t relaxed/simple, u - simple/relaxed\n");
  2538. + fprintf(stderr, "d <domain> the domain tag, if not provided, determined from the sender/from header\n");
  2539. + fprintf(stderr, "i <identity> the identity, if not provided it will not be included\n");
  2540. + fprintf(stderr, "x <expire_time> the expire time in seconds since epoch ( DEFAULT = current time + 604800)\n");
  2541. + fprintf(stderr, " if set to - then it will not be included\n");
  2542. +#ifdef HAVE_EVP_SHA256
  2543. + fprintf(stderr, "z <hash> 1 for sha1, 2 for sha256, 3 for both\n");
  2544. +#endif
  2545. + fprintf(stderr, "y <selector> the selector tag DEFAULT=private\n");
  2546. + fprintf(stderr, "s <privkeyfile> sign the message using the private key in privkeyfile\n");
  2547. + fprintf(stderr, "H this help\n");
  2548. + exit(1);
  2549. +}
  2550. +
  2551. +unsigned int str_chr(char *s, int c)
  2552. +{
  2553. + register char ch;
  2554. + register char *t;
  2555. +
  2556. + ch = c;
  2557. + t = s;
  2558. + for (;;)
  2559. + {
  2560. + if (!*t)
  2561. + break;
  2562. + if (*t == ch)
  2563. + break;
  2564. + ++t;
  2565. + if (!*t)
  2566. + break;
  2567. + if (*t == ch)
  2568. + break;
  2569. + ++t;
  2570. + if (!*t)
  2571. + break;
  2572. + if (*t == ch)
  2573. + break;
  2574. + ++t;
  2575. + if (!*t)
  2576. + break;
  2577. + if (*t == ch)
  2578. + break;
  2579. + ++t;
  2580. + }
  2581. + return t - s;
  2582. +}
  2583. +
  2584. +void
  2585. +dkim_error(int e)
  2586. +{
  2587. + switch (e)
  2588. + {
  2589. + case DKIM_OUT_OF_MEMORY:
  2590. + fprintf(stderr, "memory allocation failed\n");
  2591. + break;
  2592. + case DKIM_INVALID_CONTEXT:
  2593. + fprintf(stderr, "DKIMContext structure invalid for this operation\n");
  2594. + break;
  2595. + case DKIM_NO_SENDER:
  2596. + fprintf(stderr, "Could not find From: or Sender: header in message\n");
  2597. + break;
  2598. + case DKIM_BAD_PRIVATE_KEY:
  2599. + fprintf(stderr, "Could not parse private key\n");
  2600. + break;
  2601. + case DKIM_BUFFER_TOO_SMALL:
  2602. + fprintf(stderr, "Buffer passed in is not large enough");
  2603. + break;
  2604. + }
  2605. +}
  2606. +
  2607. +/*
  2608. + * Allows you to add the headers contain the results and DKIM ADSP
  2609. + */
  2610. +int writeHeader(int ret, int resDKIMSSP, int resDKIMADSP, int useSSP, int useADSP )
  2611. +{
  2612. + char *dkimStatus, *sspStatus, *adspStatus;
  2613. +
  2614. + dkimStatus = sspStatus = adspStatus = (char *) "";
  2615. + switch (ret)
  2616. + {
  2617. + case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
  2618. + dkimStatus = (char *) "signature result: signature verified but it did not include all of the body";
  2619. + break;
  2620. + case DKIM_NEUTRAL: /*- 3 verify result: no signatures verified but message is not suspicious */
  2621. + dkimStatus = (char *) "verify result: no signatures verified but message is not suspicious";
  2622. + break;
  2623. + case DKIM_PARTIAL_SUCCESS: /*- 2 verify result: at least one but not all signatures verified */
  2624. + dkimStatus = (char *) "verify result: at least none but not all signatures verified";
  2625. + break;
  2626. + case DKIM_FINISHED_BODY: /*- 1 process result: no more message body is needed */
  2627. + dkimStatus = (char *) "process result: no more message body is needed";
  2628. + break;
  2629. + case DKIM_SUCCESS:
  2630. + dkimStatus = (char *) "good ";
  2631. + break;
  2632. + case DKIM_FAIL:
  2633. + dkimStatus = (char *) "failed ";
  2634. + break;
  2635. + case DKIM_BAD_SYNTAX:
  2636. + dkimStatus = (char *) "signature error: DKIM-Signature could not parse or has bad tags/values";
  2637. + break;
  2638. + case DKIM_SIGNATURE_BAD:
  2639. + dkimStatus = (char *) "signature error: RSA verify failed";
  2640. + break;
  2641. + case DKIM_SIGNATURE_BAD_BUT_TESTING:
  2642. + dkimStatus = (char *) "signature error: RSA verify failed but testing";
  2643. + break;
  2644. + case DKIM_SIGNATURE_EXPIRED:
  2645. + dkimStatus = (char *) "signature error: x= is old";
  2646. + break;
  2647. + case DKIM_SELECTOR_INVALID:
  2648. + dkimStatus = (char *) "signature error: selector doesn't parse or contains invalid values";
  2649. + break;
  2650. + case DKIM_SELECTOR_GRANULARITY_MISMATCH:
  2651. + dkimStatus = (char *) "signature error: selector g= doesn't match i=";
  2652. + break;
  2653. + case DKIM_SELECTOR_KEY_REVOKED:
  2654. + dkimStatus = (char *) "signature error: selector p= empty";
  2655. + break;
  2656. + case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
  2657. + dkimStatus = (char *) "signature error: selector domain name too long to request";
  2658. + break;
  2659. + case DKIM_SELECTOR_DNS_TEMP_FAILURE:
  2660. + dkimStatus = (char *) "signature error: temporary dns failure requesting selector";
  2661. + break;
  2662. + case DKIM_SELECTOR_DNS_PERM_FAILURE:
  2663. + dkimStatus = (char *) "signature error: permanent dns failure requesting selector";
  2664. + break;
  2665. + case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
  2666. + dkimStatus = (char *) "signature error: selector p= value invalid or wrong format";
  2667. + break;
  2668. + case DKIM_NO_SIGNATURES:
  2669. + dkimStatus = (char *) "process error, no sigs";
  2670. + break;
  2671. + case DKIM_NO_VALID_SIGNATURES:
  2672. + dkimStatus = (char *) "process error, no valid sigs";
  2673. + break;
  2674. + case DKIM_BODY_HASH_MISMATCH:
  2675. + dkimStatus = (char *) "sigature verify error: message body does not hash to bh value";
  2676. + break;
  2677. + case DKIM_SELECTOR_ALGORITHM_MISMATCH:
  2678. + dkimStatus = (char *) "signature error: selector h= doesn't match signature a=";
  2679. + break;
  2680. + case DKIM_STAT_INCOMPAT:
  2681. + dkimStatus = (char *) "signature error: incompatible v=";
  2682. + break;
  2683. + default:
  2684. + dkimStatus = (char *) "error";
  2685. + break;
  2686. + }
  2687. + if (useSSP && resDKIMSSP != -1)
  2688. + {
  2689. + switch(resDKIMSSP)
  2690. + {
  2691. + case DKIM_SSP_ALL:
  2692. + sspStatus = (char *) "all;";
  2693. + break;
  2694. + case DKIM_SSP_STRICT:
  2695. + sspStatus = (char *) "strict;";
  2696. + break;
  2697. + case DKIM_SSP_SCOPE:
  2698. + sspStatus = (char *) "out of scope;";
  2699. + break;
  2700. + case DKIM_SSP_TEMPFAIL:
  2701. + sspStatus = (char *) "temporary failure;";
  2702. + break;
  2703. + case DKIM_SSP_UNKNOWN:
  2704. + default:
  2705. + sspStatus = (char *) "unknown;";
  2706. + break;
  2707. + }
  2708. + }
  2709. + if (useADSP && resDKIMADSP != -1)
  2710. + {
  2711. + switch(resDKIMADSP)
  2712. + {
  2713. + case DKIM_ADSP_ALL:
  2714. + adspStatus = (char *) "all;";
  2715. + break;
  2716. + case DKIM_ADSP_DISCARDABLE:
  2717. + adspStatus = (char *) "discardable;";
  2718. + break;
  2719. + case DKIM_ADSP_SCOPE:
  2720. + adspStatus = (char *) "out of scope;";
  2721. + break;
  2722. + case DKIM_ADSP_TEMPFAIL:
  2723. + adspStatus = (char *) "temporary failure;";
  2724. + break;
  2725. + case DKIM_ADSP_UNKNOWN:
  2726. + default:
  2727. + adspStatus = (char *) "unknown ;";
  2728. + break;
  2729. + }
  2730. + }
  2731. + printf("DKIM-Status: %s\n", dkimStatus);
  2732. + if (useSSP && *sspStatus)
  2733. + printf("X-DKIM-SSP: %s\n", sspStatus);
  2734. + if (useADSP && *adspStatus)
  2735. + printf("X-DKIM-ADSP: %s\n", adspStatus);
  2736. +}
  2737. +
  2738. +int
  2739. +ParseTagValues(char *list, char *letters[], char *values[])
  2740. +{
  2741. + char *tmp, *ptr, *key;
  2742. + int i;
  2743. +
  2744. + /*- start with all args unset */
  2745. + for (i = 0; letters[i]; i++)
  2746. + values[i] = 0;
  2747. + key = 0;
  2748. + for(ptr = list;*ptr;)
  2749. + {
  2750. + if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')) /*- FWS */
  2751. + *ptr++ = 0;
  2752. + if (!key)
  2753. + key = ptr;
  2754. + if (*ptr == '=')
  2755. + {
  2756. + *ptr = 0;
  2757. + for (i = 0;letters[i];i++)
  2758. + {
  2759. + if (!strcmp(letters[i], key))
  2760. + {
  2761. + ptr++;
  2762. + for (;*ptr;)
  2763. + {
  2764. + if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n'))
  2765. + {
  2766. + ptr++;
  2767. + continue;
  2768. + }
  2769. + break;
  2770. + }
  2771. + values[i] = ptr;
  2772. + for(;*ptr && *ptr != ';';ptr++);
  2773. + tmp = ptr;
  2774. + if (*ptr)
  2775. + *ptr++ = 0;
  2776. + for(;tmp != values[i];tmp--) /*- RFC 4871 3.2 */
  2777. + {
  2778. + if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\r') || (*tmp == '\n'))
  2779. + {
  2780. + *tmp = 0;
  2781. + continue;
  2782. + }
  2783. + break;
  2784. + }
  2785. + key = 0;
  2786. + break;
  2787. + }
  2788. + }
  2789. + } else
  2790. + ptr++;
  2791. + }
  2792. + return (0);
  2793. +}
  2794. +
  2795. +int
  2796. +GetSSP(char *domain, int *bTesting)
  2797. +{
  2798. + char *query, *results;
  2799. + char *tags[] = { (char *) "dkim", (char *) "t", (char *) 0};
  2800. + char *values[2];
  2801. + int bIsParentSSP = 0, iSSP = DKIM_SSP_UNKNOWN;
  2802. +
  2803. + *bTesting = 0;
  2804. + if (!(query = (char *) DKIM_MALLOC(strlen("_ssp._domainkey.") + strlen(domain) + 1)))
  2805. + {
  2806. + fprintf(stderr, "malloc: %d: %s\n", strlen("_ssp._domainkey.") + strlen(domain) + 1,
  2807. + strerror(errno));
  2808. + exit(1);
  2809. + }
  2810. + sprintf(query, "_ssp._domainkey.%s", domain);
  2811. + results = dns_text(query);
  2812. + DKIM_MFREE(query);
  2813. + if (!strcmp(results, "e=temp;"))
  2814. + {
  2815. + DKIM_MFREE(results);
  2816. + return DKIM_SSP_TEMPFAIL;
  2817. + } else
  2818. + if (!strcmp(results, "e=perm;"))
  2819. + {
  2820. + DKIM_MFREE(results);
  2821. + results = dns_text(domain);
  2822. + if (!strcmp(results, "e=temp;"))
  2823. + {
  2824. + DKIM_MFREE(results);
  2825. + return DKIM_SSP_TEMPFAIL;
  2826. + } else
  2827. + if (!strcmp(results, "e=perm;"))
  2828. + {
  2829. + DKIM_MFREE(results);
  2830. + return DKIM_SSP_SCOPE;
  2831. + }
  2832. + bIsParentSSP = 1;
  2833. + }
  2834. + if (!ParseTagValues(results, tags, values))
  2835. + {
  2836. + DKIM_MFREE(results);
  2837. + return DKIM_SSP_UNKNOWN;
  2838. + }
  2839. + DKIM_MFREE(results);
  2840. + if (values[0] != NULL) {
  2841. + if (strcasecmp(values[0], "all") == 0)
  2842. + iSSP = DKIM_SSP_ALL;
  2843. + else
  2844. + if (strcasecmp(values[0], "strict") == 0)
  2845. + iSSP = DKIM_SSP_STRICT;
  2846. + }
  2847. + // flags
  2848. + if (values[1] != NULL) {
  2849. + char *s, *p;
  2850. + for (p = values[1], s = values[1]; *p; p++)
  2851. + {
  2852. + if (*p == '|')
  2853. + *p = 0;
  2854. + else
  2855. + continue;
  2856. + if (!strcmp(s, "y"))
  2857. + *bTesting = 1;
  2858. + else
  2859. + if (!strcmp(s, "s")) {
  2860. + if (bIsParentSSP) {
  2861. + /*
  2862. + * this is a parent's SSP record that should not apply to subdomains
  2863. + * the message is non-suspicious
  2864. + */
  2865. + *bTesting = 0;
  2866. + return (DKIM_SSP_UNKNOWN);
  2867. + }
  2868. + }
  2869. + s = p + 1;
  2870. + }
  2871. + }
  2872. + return iSSP; /*- No ADSP Record */
  2873. +}
  2874. +
  2875. +int
  2876. +GetADSP(char *domain)
  2877. +{
  2878. + char *query, *results;
  2879. + char *tags[] = {(char *) "dkim", (char *) 0};
  2880. + char *values[1];
  2881. +
  2882. + results = dns_text(domain);
  2883. + if (!strcmp(results, "e=perm;"))
  2884. + {
  2885. + DKIM_MFREE(results);
  2886. + return DKIM_ADSP_SCOPE;
  2887. + } else
  2888. + if (!strcmp(results, "e=temp;"))
  2889. + {
  2890. + DKIM_MFREE(results);
  2891. + return DKIM_ADSP_TEMPFAIL;
  2892. + }
  2893. + if (!(query = (char *) DKIM_MALLOC(strlen((char *) "_adsp._domainkey.") + strlen(domain) + 1)))
  2894. + {
  2895. + fprintf(stderr, "malloc: %d: %s\n", strlen("_adsp._domainkey.") + strlen(domain) + 1,
  2896. + strerror(errno));
  2897. + exit(1);
  2898. + }
  2899. + sprintf(query, "_adsp._domainkey.%s", domain);
  2900. + results = dns_text(query);
  2901. + DKIM_MFREE(query);
  2902. + if (!strcmp(results, "e=perm;"))
  2903. + {
  2904. + DKIM_MFREE(results);
  2905. + return DKIM_ADSP_SCOPE;
  2906. + } else
  2907. + if (!strcmp(results, "e=temp;"))
  2908. + {
  2909. + DKIM_MFREE(results);
  2910. + return DKIM_ADSP_TEMPFAIL;
  2911. + }
  2912. + if (!ParseTagValues(results, tags, values))
  2913. + {
  2914. + DKIM_MFREE(results);
  2915. + return DKIM_ADSP_UNKNOWN;
  2916. + }
  2917. + DKIM_MFREE(results);
  2918. + if (values[0] != NULL) {
  2919. + if (strcasecmp(values[0], "all") == 0)
  2920. + return (DKIM_ADSP_ALL);
  2921. + else
  2922. + if (strcasecmp(values[0], "discardable") == 0)
  2923. + return (DKIM_ADSP_DISCARDABLE);
  2924. + }
  2925. + return DKIM_ADSP_UNKNOWN; /*- No ADSP Record */
  2926. +}
  2927. +
  2928. +int
  2929. +main(int argc, char **argv)
  2930. +{
  2931. + char *PrivKey, *PrivKeyFile = NULL, *pSig = NULL, *dkimverify;
  2932. + int i, ret, ch, nPrivKeyLen, PrivKeyFD, verbose = 0;
  2933. + int bSign = 1, nSigCount = 0, useSSP = 0, useADSP = 0, accept3ps = 0;
  2934. + int sCount = 0, sSize = 0, resDKIMSSP = -1, resDKIMADSP = -1;
  2935. + char Buffer[1024], szPolicy[512];
  2936. + time_t t;
  2937. + struct stat statbuf;
  2938. + DKIMContext ctxt;
  2939. + DKIMSignOptions opts = { 0 };
  2940. + DKIMVerifyDetails *pDetails;
  2941. + DKIMVerifyOptions vopts = { 0 };
  2942. +
  2943. + if (!(program = strrchr(argv[0], '/')))
  2944. + program = argv[0];
  2945. + else
  2946. + program++;
  2947. + t = time(0);
  2948. +#ifdef HAVE_EVP_SHA256
  2949. + opts.nHash = DKIM_HASH_SHA1_AND_256;
  2950. +#else
  2951. + opts.nHash = DKIM_HASH_SHA1;
  2952. +#endif
  2953. + opts.nCanon = DKIM_SIGN_RELAXED;
  2954. + opts.nIncludeBodyLengthTag = 0;
  2955. + opts.nIncludeQueryMethod = 0;
  2956. + opts.nIncludeTimeStamp = 0;
  2957. + opts.expireTime = t + 604800; // expires in 1 week
  2958. + opts.nIncludeCopiedHeaders = 0;
  2959. + opts.nIncludeBodyHash = DKIM_BODYHASH_BOTH;
  2960. + strcpy(opts.szSelector, "private");
  2961. + strcpy(opts.szRequiredHeaders, "NonExistent");
  2962. + opts.pfnHeaderCallback = SignThisHeader;
  2963. + while (1)
  2964. + {
  2965. +#ifdef HAVE_EVP_SHA256
  2966. + if ((ch = getopt(argc, argv, "lqthHvVp:b:c:d:i:s:x:y:z:")) == -1)
  2967. +#else
  2968. + if ((ch = getopt(argc, argv, "lqthHvVp:b:c:d:i:s:x:y:")) == -1)
  2969. +#endif
  2970. + break;
  2971. + switch (ch)
  2972. + {
  2973. + case 'l': /*- body length tag */
  2974. + opts.nIncludeBodyLengthTag = 1;
  2975. + break;
  2976. + case 'q': /*- query method tag */
  2977. + opts.nIncludeQueryMethod = 1;
  2978. + break;
  2979. + case 't': /*- timestamp tag */
  2980. + opts.nIncludeTimeStamp = 1;
  2981. + break;
  2982. + case 'h':
  2983. + opts.nIncludeCopiedHeaders = 1;
  2984. + break;
  2985. + case 'H':
  2986. + usage();
  2987. + break;
  2988. + case 'v': /*- verify */
  2989. + bSign = 0;
  2990. + break;
  2991. + case 'V': /*- verbose */
  2992. + verbose = 1;
  2993. + break;
  2994. + case 'p':
  2995. + switch(*optarg)
  2996. + {
  2997. + case '0':
  2998. + accept3ps = 0;
  2999. + useSSP = 0;
  3000. + useADSP = 0;
  3001. + break;
  3002. + case '1':
  3003. + accept3ps = 1;
  3004. + useSSP = 1;
  3005. + useADSP = 0;
  3006. + break;
  3007. + case '2':
  3008. + accept3ps = 1;
  3009. + useSSP = 0;
  3010. + useADSP = 1;
  3011. + break;
  3012. + }
  3013. + break;
  3014. + case 'b': /*- allman or ietf draft 1 or both */
  3015. + switch (*optarg)
  3016. + {
  3017. + case '1':
  3018. + opts.nIncludeBodyHash = DKIM_BODYHASH_ALLMAN_1;
  3019. + break;
  3020. + case '2':
  3021. + opts.nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
  3022. + break;
  3023. + case '3':
  3024. + opts.nIncludeBodyHash = DKIM_BODYHASH_BOTH;
  3025. + break;
  3026. + default:
  3027. + fprintf(stderr, "%s: unrecognized standard.\n", program);
  3028. + return (1);
  3029. + }
  3030. + break;
  3031. + case 'c':
  3032. + switch (*optarg)
  3033. + {
  3034. + case 'r':
  3035. + opts.nCanon = DKIM_SIGN_RELAXED;
  3036. + break;
  3037. + case 's':
  3038. + opts.nCanon = DKIM_SIGN_SIMPLE;
  3039. + break;
  3040. + case 't':
  3041. + opts.nCanon = DKIM_SIGN_RELAXED_SIMPLE;
  3042. + break;
  3043. + case 'u':
  3044. + opts.nCanon = DKIM_SIGN_SIMPLE_RELAXED;
  3045. + break;
  3046. + default:
  3047. + fprintf(stderr, "%s: unrecognized canonicalization.\n", program);
  3048. + return (1);
  3049. + }
  3050. + break;
  3051. + case 'd':
  3052. + strncpy(opts.szDomain, optarg, sizeof (opts.szDomain) - 1);
  3053. + break;
  3054. + case 'i': /*- identity */
  3055. + if (*optarg == '-')
  3056. + opts.szIdentity[0] = '\0';
  3057. + else
  3058. + strncpy(opts.szIdentity, optarg, sizeof (opts.szIdentity) - 1);
  3059. + break;
  3060. + case 's': /*- sign */
  3061. + bSign = 1;
  3062. + PrivKeyFile = optarg;
  3063. + break;
  3064. + case 'x': /*- expire time */
  3065. + if (*optarg == '-')
  3066. + opts.expireTime = 0;
  3067. + else
  3068. + opts.expireTime = t + atoi(optarg);
  3069. + break;
  3070. + case 'y':
  3071. + strncpy(opts.szSelector, optarg, sizeof (opts.szSelector) - 1);
  3072. + break;
  3073. +#ifdef HAVE_EVP_SHA256
  3074. + case 'z': /*- sign w/ sha1, sha256 or both */
  3075. + switch (*optarg)
  3076. + {
  3077. + case '1':
  3078. + opts.nHash = DKIM_HASH_SHA1;
  3079. + break;
  3080. + case '2':
  3081. + opts.nHash = DKIM_HASH_SHA256;
  3082. + break;
  3083. + case '3':
  3084. + opts.nHash = DKIM_HASH_SHA1_AND_256;
  3085. + break;
  3086. + default:
  3087. + fprintf(stderr, "%s: unrecognized hash.\n", program);
  3088. + return (1);
  3089. + }
  3090. + break;
  3091. +#endif
  3092. + } /*- switch (ch) */
  3093. + }
  3094. + if (bSign) { /*- sign */
  3095. + if (!PrivKeyFile)
  3096. + {
  3097. + fprintf(stderr, "Private Key not provided\n");
  3098. + usage();
  3099. + return (1);
  3100. + }
  3101. + if ((PrivKeyFD = open(PrivKeyFile, O_RDONLY)) == -1) {
  3102. + fprintf(stderr, "%s: %s\n", PrivKeyFile, strerror(errno));
  3103. + return (1);
  3104. + }
  3105. + if (fstat(PrivKeyFD, &statbuf) == -1)
  3106. + {
  3107. + fprintf(stderr, "fstat: %s: %s\n", PrivKeyFile, strerror(errno));
  3108. + return (1);
  3109. + }
  3110. + if (!(PrivKey = (char *) DKIM_MALLOC(sizeof(char) * ((nPrivKeyLen = statbuf.st_size) + 1))))
  3111. + {
  3112. + fprintf(stderr, "malloc: %ld bytes: %s\n", statbuf.st_size + 1, strerror(errno));
  3113. + return (1);
  3114. + }
  3115. + if (read(PrivKeyFD, PrivKey, nPrivKeyLen) != nPrivKeyLen)
  3116. + {
  3117. + fprintf(stderr, "%s: read: %s\n", strerror(errno), program);
  3118. + return (1);
  3119. + }
  3120. + close(PrivKeyFD);
  3121. + PrivKey[nPrivKeyLen] = '\0';
  3122. + if (DKIMSignInit(&ctxt, &opts) != DKIM_SUCCESS)
  3123. + {
  3124. + fprintf(stderr, "DKIMSignInit: failed to initialize signature %s\n", PrivKeyFile);
  3125. + return (1);
  3126. + }
  3127. + for (;;)
  3128. + {
  3129. + if ((ret = read(0, Buffer, sizeof(Buffer) - 1)) == -1)
  3130. + {
  3131. + fprintf(stderr, "read: %s\n", strerror(errno));
  3132. + DKIMSignFree(&ctxt);
  3133. + return (1);
  3134. + } else
  3135. + if (!ret)
  3136. + break;
  3137. + if (DKIMSignProcess(&ctxt, Buffer, ret) == DKIM_INVALID_CONTEXT)
  3138. + {
  3139. + fprintf(stderr, "DKIMSignProcess: DKIMContext structure invalid for this operation\n");
  3140. + DKIMSignFree(&ctxt);
  3141. + return (1);
  3142. + }
  3143. + }
  3144. + if (DKIMSignGetSig2(&ctxt, PrivKey, &pSig) == DKIM_INVALID_CONTEXT)
  3145. + {
  3146. + fprintf(stderr, "DKIMSignProcess: DKIMContext structure invalid for this operation\n");
  3147. + DKIMSignFree(&ctxt);
  3148. + return (1);
  3149. + }
  3150. + if (pSig)
  3151. + {
  3152. + fwrite(pSig, 1, strlen(pSig), stdout);
  3153. + fwrite("\n", 1, 1, stdout);
  3154. + }
  3155. + DKIMSignFree(&ctxt);
  3156. + return 0;
  3157. + } else { /*- verify */
  3158. + if (useADSP)
  3159. + vopts.nCheckPractices = useADSP;
  3160. + else
  3161. + if (useSSP)
  3162. + vopts.nCheckPractices = useSSP;
  3163. + else
  3164. + vopts.nCheckPractices = 0;
  3165. + vopts.nAccept3ps = accept3ps;
  3166. + vopts.pfnSelectorCallback = NULL; /*- SelectorCallback; */
  3167. + DKIMVerifyInit(&ctxt, &vopts); /*- this is always successful */
  3168. + for (;;)
  3169. + {
  3170. + if ((i = read(0, Buffer, sizeof(Buffer) - 1)) == -1)
  3171. + {
  3172. + fprintf(stderr, "read: %s\n", strerror(errno));
  3173. + DKIMVerifyFree(&ctxt);
  3174. + return (1);
  3175. + } else
  3176. + if (!i)
  3177. + break;
  3178. + ret = DKIMVerifyProcess(&ctxt, Buffer, i);
  3179. + dkim_error(ret);
  3180. + if (ret > 0 && ret < DKIM_FINISHED_BODY)
  3181. + ret = DKIM_FAIL;
  3182. + if (ret)
  3183. + break;
  3184. + }
  3185. + if (!ret)
  3186. + {
  3187. + if ((ret = DKIMVerifyResults(&ctxt, &sCount, &sSize)) != DKIM_SUCCESS)
  3188. + dkim_error(ret);
  3189. + if ((ret = DKIMVerifyGetDetails(&ctxt, &nSigCount, &pDetails, szPolicy)) != DKIM_SUCCESS)
  3190. + dkim_error(ret);
  3191. + else
  3192. + {
  3193. + for (ret = 0,i = 0; i < nSigCount; i++) {
  3194. + if (verbose)
  3195. + printf("Signature # %02d: ", i + 1);
  3196. + if (pDetails[i].nResult >= 0)
  3197. + {
  3198. + if (verbose)
  3199. + printf("Success\n");
  3200. + continue;
  3201. + } else
  3202. + {
  3203. + ret = pDetails[i].nResult;
  3204. + if (verbose)
  3205. + printf("Failure %d\n", ret);
  3206. + }
  3207. + }
  3208. + if (!nSigCount)
  3209. + ret = DKIM_NO_SIGNATURES;
  3210. + }
  3211. + }
  3212. + if (ret < 0 || ret == DKIM_3PS_SIGNATURE) {
  3213. + if (useADSP)
  3214. + {
  3215. + char *domain;
  3216. +
  3217. + if ((domain = DKIMVerifyGetDomain(&ctxt)))
  3218. + resDKIMADSP = GetADSP(domain);
  3219. + if (sCount > 0) {
  3220. + if (resDKIMADSP == DKIM_ADSP_UNKNOWN || resDKIMADSP == DKIM_ADSP_ALL)
  3221. + ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
  3222. + }
  3223. + /* if the message should be signed, return fail */
  3224. + if (resDKIMADSP == DKIM_ADSP_DISCARDABLE)
  3225. + ret = DKIM_FAIL;
  3226. + ret = DKIM_NEUTRAL;
  3227. + } else
  3228. + if (useSSP)
  3229. + {
  3230. + int bTestingPractices = 0;
  3231. + char *domain;
  3232. +
  3233. + if ((domain = DKIMVerifyGetDomain(&ctxt)))
  3234. + resDKIMSSP = GetSSP(domain, &bTestingPractices);
  3235. + if (sCount > 0) {
  3236. + if ((resDKIMSSP == DKIM_SSP_UNKNOWN || resDKIMSSP == DKIM_SSP_ALL))
  3237. + ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
  3238. + }
  3239. + // if the SSP is testing, return neutral
  3240. + if (bTestingPractices)
  3241. + return(DKIM_NEUTRAL);
  3242. + /* if the message should be signed, return fail */
  3243. + if (resDKIMSSP == DKIM_SSP_ALL || resDKIMSSP == DKIM_SSP_STRICT)
  3244. + return(DKIM_FAIL);
  3245. + ret = DKIM_NEUTRAL;
  3246. + }
  3247. + }
  3248. + DKIMVerifyFree(&ctxt);
  3249. + writeHeader(ret, resDKIMSSP, resDKIMADSP, useSSP, useADSP);
  3250. + if ((dkimverify = getenv("DKIMVERIFY")))
  3251. + {
  3252. + if (ret < 0)
  3253. + {
  3254. + if (dkimverify[str_chr(dkimverify, 'E' - ret)])
  3255. + ret = 14; /*- return permanent error */
  3256. + if (dkimverify[str_chr(dkimverify, 'e' - ret)])
  3257. + ret = 88; /*- return temporary error */
  3258. + } else
  3259. + {
  3260. + if (dkimverify[str_chr(dkimverify, 'A' + ret)])
  3261. + ret = 14; /*- return permanent error */
  3262. + if (dkimverify[str_chr(dkimverify, 'a' + ret)])
  3263. + ret = 88; /*- return temporary error */
  3264. + }
  3265. + }
  3266. + return (ret);
  3267. + }
  3268. + /*- Not Reached */
  3269. + _exit(0);
  3270. +}
  3271. +
  3272. +void
  3273. +getversion_dkim_c()
  3274. +{
  3275. + static char *x = (char *) "$Id: dkim.c,v 1.10 2009-04-15 21:30:32+05:30 Cprogrammer Exp mbhangui $";
  3276. +
  3277. + x++;
  3278. +}
  3279. diff -Naur qmail-1.03.org/dkimverify.cpp qmail-1.03/dkimverify.cpp
  3280. --- qmail-1.03.org/dkimverify.cpp 1970-01-01 05:30:00.000000000 +0530
  3281. +++ qmail-1.03/dkimverify.cpp 2009-04-21 11:19:07.000000000 +0530
  3282. @@ -0,0 +1,1155 @@
  3283. +/*
  3284. + * $Log: dkimverify.cpp,v $
  3285. + * Revision 1.5 2009-03-27 20:19:58+05:30 Cprogrammer
  3286. + * added ADSP code
  3287. + *
  3288. + * Revision 1.4 2009-03-26 15:12:05+05:30 Cprogrammer
  3289. + * added ADSP code
  3290. + *
  3291. + * Revision 1.3 2009-03-25 08:38:20+05:30 Cprogrammer
  3292. + * fixed indentation
  3293. + *
  3294. + * Revision 1.2 2009-03-21 11:57:40+05:30 Cprogrammer
  3295. + * fixed indentation
  3296. + *
  3297. + * Revision 1.1 2009-03-21 08:43:13+05:30 Cprogrammer
  3298. + * Initial revision
  3299. + *
  3300. + *
  3301. + * Copyright 2005 Alt-N Technologies, Ltd.
  3302. + *
  3303. + * Licensed under the Apache License, Version 2.0 (the "License");
  3304. + * you may not use this file except in compliance with the License.
  3305. + * You may obtain a copy of the License at
  3306. + *
  3307. + * http://www.apache.org/licenses/LICENSE-2.0
  3308. + *
  3309. + * This code incorporates intellectual property owned by Yahoo! and licensed
  3310. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  3311. + *
  3312. + * Unless required by applicable law or agreed to in writing, software
  3313. + * distributed under the License is distributed on an "AS IS" BASIS,
  3314. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3315. + * See the License for the specific language governing permissions and
  3316. + * limitations under the License.
  3317. + *
  3318. + */
  3319. +#ifdef HAVE_CONFIG_H
  3320. +#include "config.h"
  3321. +#else
  3322. +#define HAVE_EVP_SHA256
  3323. +#endif
  3324. +#define _strnicmp strncasecmp
  3325. +#define _stricmp strcasecmp
  3326. +#include <string.h>
  3327. +#include <ctype.h>
  3328. +#include <assert.h>
  3329. +#include <vector>
  3330. +#include <algorithm>
  3331. +#include "dkim.h"
  3332. +#include "dkimverify.h"
  3333. +#include "dkimdns.h"
  3334. +
  3335. +#define MAX_SIGNATURES 10 // maximum number of DKIM signatures to process in a message
  3336. +
  3337. +SignatureInfo::SignatureInfo(bool s)
  3338. +{
  3339. + VerifiedBodyCount = 0;
  3340. + UnverifiedBodyCount = 0;
  3341. + EVP_MD_CTX_init(&m_Hdr_ctx);
  3342. + EVP_MD_CTX_init(&m_Bdy_ctx);
  3343. + m_pSelector = NULL;
  3344. + Status = DKIM_SUCCESS;
  3345. + m_nHash = 0;
  3346. + EmptyLineCount = 0;
  3347. + m_SaveCanonicalizedData = s;
  3348. +}
  3349. +
  3350. +SignatureInfo::~SignatureInfo()
  3351. +{
  3352. + EVP_MD_CTX_cleanup(&m_Hdr_ctx);
  3353. + EVP_MD_CTX_cleanup(&m_Bdy_ctx);
  3354. +}
  3355. +
  3356. +inline bool
  3357. +isswsp(char ch)
  3358. +{
  3359. + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
  3360. +}
  3361. +
  3362. +
  3363. +////////////////////////////////////////////////////////////////////////////////
  3364. +//
  3365. +// Parse a DKIM tag-list. Returns true for success
  3366. +//
  3367. +////////////////////////////////////////////////////////////////////////////////
  3368. +bool
  3369. +ParseTagValueList(char *tagvaluelist, const char *wanted[], char *values[])
  3370. +{
  3371. + char *s = tagvaluelist;
  3372. +
  3373. + for (;;) {
  3374. + // skip whitespace
  3375. + while (isswsp(*s))
  3376. + s++;
  3377. + // if at the end of the string, return success. note: this allows a list with no entries
  3378. + if (*s == '\0')
  3379. + return true;
  3380. + // get tag name
  3381. + if (!isalpha(*s))
  3382. + return false;
  3383. + char *tag = s;
  3384. + do {
  3385. + s++;
  3386. + } while (isalnum(*s) || *s == '-');
  3387. + char *endtag = s;
  3388. + // skip whitespace before equals
  3389. + while (isswsp(*s))
  3390. + s++;
  3391. + // next character must be equals
  3392. + if (*s != '=')
  3393. + return false;
  3394. + s++;
  3395. + // null-terminate tag name
  3396. + *endtag = '\0';
  3397. + // skip whitespace after equals
  3398. + while (isswsp(*s))
  3399. + s++;
  3400. + // get tag value
  3401. + char *value = s;
  3402. + while (*s != ';' && ((*s == '\t' || *s == '\r' || *s == '\n') || (*s >= ' ' && *s <= '~')))
  3403. + s++;
  3404. + char *e = s;
  3405. + // make sure the next character is the null terminator (which means we're done) or a semicolon (not done)
  3406. + bool done = false;
  3407. + if (*s == '\0')
  3408. + done = true;
  3409. + else {
  3410. + if (*s != ';')
  3411. + return false;
  3412. + s++;
  3413. + }
  3414. + // skip backwards past any trailing whitespace
  3415. + while (e > value && isswsp(e[-1]))
  3416. + e--;
  3417. + // null-terminate tag value
  3418. + *e = '\0';
  3419. + // check to see if we want this tag
  3420. + for (unsigned i = 0; wanted[i] != NULL; i++) {
  3421. + if (strcmp(wanted[i], tag) == 0) {
  3422. + // return failure if we already have a value for this tag (duplicates not allowed)
  3423. + if (values[i] != NULL)
  3424. + return false;
  3425. + values[i] = value;
  3426. + break;
  3427. + }
  3428. + }
  3429. + if (done)
  3430. + return true;
  3431. + }
  3432. +}
  3433. +
  3434. +// Convert hex char to value (0-15)
  3435. +char
  3436. +tohex(char ch)
  3437. +{
  3438. + if (ch >= '0' && ch <= '9')
  3439. + return (ch - '0');
  3440. + else
  3441. + if (ch >= 'A' && ch <= 'F')
  3442. + return (ch - 'A' + 10);
  3443. + else
  3444. + if (ch >= 'a' && ch <= 'f')
  3445. + return (ch - 'a' + 10);
  3446. + else {
  3447. + assert(0);
  3448. + return 0;
  3449. + }
  3450. +}
  3451. +
  3452. +
  3453. +////////////////////////////////////////////////////////////////////////////////
  3454. +//
  3455. +// Decode quoted printable string in-place
  3456. +//
  3457. +////////////////////////////////////////////////////////////////////////////////
  3458. +void
  3459. +DecodeQuotedPrintable(char *ptr)
  3460. +{
  3461. + char *s = ptr;
  3462. + while (*s != '\0' && *s != '=')
  3463. + s++;
  3464. + if (*s == '\0')
  3465. + return;
  3466. + char *d = s;
  3467. + do {
  3468. + if (*s == '=' && isxdigit(s[1]) && isxdigit(s[2])) {
  3469. + *d++ = (tohex(s[1]) << 4) | tohex(s[2]);
  3470. + s += 3;
  3471. + } else {
  3472. + *d++ = *s++;
  3473. + }
  3474. + } while (*s != '\0');
  3475. + *d = '\0';
  3476. +}
  3477. +
  3478. +
  3479. +////////////////////////////////////////////////////////////////////////////////
  3480. +//
  3481. +// Decode base64 string in-place, returns number of bytes output
  3482. +//
  3483. +////////////////////////////////////////////////////////////////////////////////
  3484. +unsigned
  3485. +DecodeBase64(char *ptr)
  3486. +{
  3487. + static const char base64_table[256] =
  3488. + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3489. + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
  3490. + -1, -1,
  3491. + -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
  3492. + -1, -1,
  3493. + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  3494. + -1, -1,
  3495. + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3496. + -1, -1,
  3497. + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3498. + -1, -1,
  3499. + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3500. + -1, -1,
  3501. + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
  3502. + };
  3503. + unsigned char *s = (unsigned char *) ptr;
  3504. + unsigned char *d = (unsigned char *) ptr;
  3505. + unsigned b64accum = 0;
  3506. + unsigned char b64shift = 0;
  3507. + while (*s != '\0') {
  3508. + unsigned char value = base64_table[*s++];
  3509. + if ((signed char) value >= 0) {
  3510. + b64accum = (b64accum << 6) | value;
  3511. + b64shift += 6;
  3512. + if (b64shift >= 8) {
  3513. + b64shift -= 8;
  3514. + *d++ = (b64accum >> b64shift);
  3515. + }
  3516. + }
  3517. + }
  3518. + return (char *) d - ptr;
  3519. +}
  3520. +
  3521. +////////////////////////////////////////////////////////////////////////////////
  3522. +//
  3523. +// Match a string with a pattern (used for g= value)
  3524. +// Supports a single, optional "*" wildcard character.
  3525. +//
  3526. +////////////////////////////////////////////////////////////////////////////////
  3527. +bool
  3528. +WildcardMatch(const char *p, const char *s)
  3529. +{
  3530. + // special case: An empty "g=" value never matches any addresses
  3531. + if (*p == '\0')
  3532. + return false;
  3533. + const char *wildcard = strchr(p, '*');
  3534. + if (wildcard == NULL)
  3535. + return strcmp(s, p) == 0;
  3536. + else {
  3537. + unsigned beforewildcardlen = wildcard - p;
  3538. + unsigned afterwildcardlen = strlen(wildcard + 1);
  3539. + unsigned slen = strlen(s);
  3540. + return (slen >= beforewildcardlen + afterwildcardlen) && (strncmp(s, p, beforewildcardlen) == 0)
  3541. + && strcmp(s + slen - afterwildcardlen, wildcard + 1) == 0;
  3542. + }
  3543. +}
  3544. +
  3545. +
  3546. +////////////////////////////////////////////////////////////////////////////////
  3547. +//
  3548. +// Parse addresses from a string. Returns true if at least one address found
  3549. +//
  3550. +////////////////////////////////////////////////////////////////////////////////
  3551. +bool
  3552. +ParseAddresses(string str, vector < string > &Addresses)
  3553. +{
  3554. + char *s = (char *) str.c_str();
  3555. + while (*s != '\0') {
  3556. + char *start = s;
  3557. + char *from = s;
  3558. + char *to = s;
  3559. + char *lt = NULL; // pointer to less than character (<) which starts the address if found
  3560. + while (*from != '\0') {
  3561. + if (*from == '(') {
  3562. + // skip over comment
  3563. + from++;
  3564. + for (int depth = 1; depth != 0; from++) {
  3565. + if (*from == '\0')
  3566. + break;
  3567. + else
  3568. + if (*from == '(')
  3569. + depth++;
  3570. + else
  3571. + if (*from == ')')
  3572. + depth--;
  3573. + else
  3574. + if (*from == '\\' && from[1] != '\0')
  3575. + from++;
  3576. + }
  3577. + }
  3578. + else
  3579. + if (*from == ')') {
  3580. + // ignore closing parenthesis outside of comment
  3581. + from++;
  3582. + }
  3583. +
  3584. + else
  3585. + if (*from == ',' || *from == ';') {
  3586. + // comma/selicolon ends the address
  3587. + from++;
  3588. + break;
  3589. + }
  3590. + else
  3591. + if (*from == ' ' || *from == '\t' || *from == '\r' || *from == '\n') {
  3592. + // ignore whitespace
  3593. + from++;
  3594. + }
  3595. + else
  3596. + if (*from == '"') {
  3597. + // copy the contents of a quoted string
  3598. + from++;
  3599. + while (*from != '\0') {
  3600. + if (*from == '"') {
  3601. + from++;
  3602. + break;
  3603. + }
  3604. + else
  3605. + if (*from == '\\' && from[1] != '\0')
  3606. + *to++ = *from++;
  3607. + *to++ = *from++;
  3608. + }
  3609. + }
  3610. + else
  3611. + if (*from == '\\' && from[1] != '\0') {
  3612. + // copy quoted-pair
  3613. + *to++ = *from++;
  3614. + *to++ = *from++;
  3615. + } else {
  3616. + // copy any other char
  3617. + *to = *from++;
  3618. + // save pointer to '<' for later...
  3619. + if (*to == '<')
  3620. + lt = to;
  3621. + to++;
  3622. + }
  3623. + }
  3624. + *to = '\0';
  3625. + // if there's < > get what's inside
  3626. + if (lt != NULL) {
  3627. + start = lt + 1;
  3628. + char *gt = strchr(start, '>');
  3629. + if (gt != NULL)
  3630. + *gt = '\0';
  3631. + } else {
  3632. + // look for and strip group name
  3633. + char *colon = strchr(start, ':');
  3634. + if (colon != NULL) {
  3635. + char *at = strchr(start, '@');
  3636. + if (at == NULL || colon < at)
  3637. + start = colon + 1;
  3638. + }
  3639. + }
  3640. + if (*start != '\0' && strchr(start, '@') != NULL)
  3641. + Addresses.push_back(start);
  3642. + s = from;
  3643. + }
  3644. + return !Addresses.empty();
  3645. +}
  3646. +
  3647. +CDKIMVerify::CDKIMVerify()
  3648. +{
  3649. + m_pfnSelectorCallback = NULL;
  3650. + m_pfnPracticesCallback = NULL;
  3651. + m_HonorBodyLengthTag = false;
  3652. + m_CheckPractices = false;
  3653. + m_Accept3ps = false;
  3654. + m_SubjectIsRequired = true;
  3655. + m_SaveCanonicalizedData = false;
  3656. +}
  3657. +
  3658. +CDKIMVerify::~CDKIMVerify()
  3659. +{
  3660. +}
  3661. +
  3662. +// Init - save the options
  3663. +int
  3664. +CDKIMVerify::Init(DKIMVerifyOptions *pOptions)
  3665. +{
  3666. + int nRet = CDKIMBase::Init();
  3667. + m_pfnSelectorCallback = pOptions->pfnSelectorCallback;
  3668. + m_pfnPracticesCallback = pOptions->pfnPracticesCallback;
  3669. +
  3670. + m_HonorBodyLengthTag = pOptions->nHonorBodyLengthTag != 0;
  3671. + m_CheckPractices = pOptions->nCheckPractices != 0;
  3672. + m_SubjectIsRequired = pOptions->nSubjectRequired == 0;
  3673. + m_Accept3ps = pOptions->nAccept3ps != 0; //TBS(Luc)
  3674. + m_SaveCanonicalizedData = pOptions->nSaveCanonicalizedData != 0;
  3675. + return nRet;
  3676. +}
  3677. +
  3678. +// GetResults - return the pass/fail/neutral verification result
  3679. +int
  3680. +CDKIMVerify::GetResults(int *sCount, int *sSize)
  3681. +{
  3682. + ProcessFinal();
  3683. + int SuccessCount = 0;
  3684. + int TestingFailures = 0;
  3685. + int RealFailures = 0;
  3686. + list <string> SuccessfulDomains; // can contain duplicates
  3687. + /* get the From address's domain if we might need it */
  3688. + string sFromDomain;
  3689. +
  3690. + for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
  3691. + if (i->Status == DKIM_SUCCESS) {
  3692. + if (!i->BodyHashData.empty()) {
  3693. + // check the body hash
  3694. + unsigned char md[EVP_MAX_MD_SIZE];
  3695. + unsigned len = 0;
  3696. + int res = EVP_DigestFinal(&i->m_Bdy_ctx, md, &len);
  3697. + if (!res || len != i->BodyHashData.length() || memcmp(i->BodyHashData.data(), md, len) != 0) {
  3698. + // body hash mismatch
  3699. + // if the selector is in testing mode...
  3700. + if (i->m_pSelector->Testing) {
  3701. + i->Status = DKIM_SIGNATURE_BAD_BUT_TESTING; // todo: make a new error code for this?
  3702. + TestingFailures++;
  3703. + } else {
  3704. + i->Status = DKIM_BODY_HASH_MISMATCH;
  3705. + RealFailures++;
  3706. + }
  3707. + continue;
  3708. + }
  3709. + } else {
  3710. + // hash CRLF separating the body from the signature
  3711. + i->Hash("\r\n", 2);
  3712. + }
  3713. + // check the header hash
  3714. + string sSignedSig = i->Header;
  3715. + string sSigValue = sSignedSig.substr(sSignedSig.find(':') + 1);
  3716. + static const char *tags[] = { "b", NULL };
  3717. + char *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
  3718. + char *pSigValue = (char *) sSigValue.c_str();
  3719. + if (ParseTagValueList(pSigValue, tags, values) && values[0] != NULL) {
  3720. + sSignedSig.erase(15 + values[0] - pSigValue, strlen(values[0]));
  3721. + }
  3722. + if (i->HeaderCanonicalization == DKIM_CANON_RELAXED) {
  3723. + sSignedSig = RelaxHeader(sSignedSig);
  3724. + } else
  3725. + if (i->HeaderCanonicalization == DKIM_CANON_NOWSP) {
  3726. + RemoveSWSP(sSignedSig);
  3727. + // convert "DKIM-Signature" to lower case
  3728. + sSignedSig.replace(0, 14, "dkim-signature", 14);
  3729. + }
  3730. + i->Hash(sSignedSig.c_str(), sSignedSig.length());
  3731. + assert(i->m_pSelector != NULL);
  3732. + int res = EVP_VerifyFinal(&i->m_Hdr_ctx, (unsigned char *) i->SignatureData.data(),
  3733. + i->SignatureData.length(), i->m_pSelector->PublicKey);
  3734. + if (res == 1) {
  3735. + if (i->UnverifiedBodyCount == 0)
  3736. + i->Status = DKIM_SUCCESS;
  3737. + else
  3738. + i->Status = DKIM_SUCCESS_BUT_EXTRA;
  3739. + SuccessCount++;
  3740. + SuccessfulDomains.push_back(i->Domain);
  3741. + } else {
  3742. + // if the selector is in testing mode...
  3743. + if (i->m_pSelector->Testing) {
  3744. + i->Status = DKIM_SIGNATURE_BAD_BUT_TESTING;
  3745. + TestingFailures++;
  3746. + } else {
  3747. + i->Status = DKIM_SIGNATURE_BAD;
  3748. + RealFailures++;
  3749. + }
  3750. + }
  3751. + } else
  3752. + if (i->Status == DKIM_SELECTOR_GRANULARITY_MISMATCH
  3753. + || i->Status == DKIM_SELECTOR_ALGORITHM_MISMATCH
  3754. + || i->Status == DKIM_SELECTOR_KEY_REVOKED) {
  3755. + // treat these as failures
  3756. + // todo: maybe see if the selector is in testing mode?
  3757. + RealFailures++;
  3758. + }
  3759. + }
  3760. + if (SuccessCount > 0 || m_CheckPractices) {
  3761. + for (list < string >::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
  3762. + if (_strnicmp(i->c_str(), "From", 4) == 0) {
  3763. + // skip over whitespace between the header name and :
  3764. + const char *s = i->c_str() + 4;
  3765. + while (*s == ' ' || *s == '\t')
  3766. + s++;
  3767. + if (*s == ':') {
  3768. + vector <string> Addresses;
  3769. + if (ParseAddresses(s + 1, Addresses)) {
  3770. + unsigned atpos = Addresses[0].find('@');
  3771. + sFromDomain = Addresses[0].substr(atpos + 1);
  3772. + break;
  3773. + }
  3774. + }
  3775. + }
  3776. + }
  3777. + }
  3778. + // if a signature from the From domain verified successfully, return success now
  3779. + // without checking the sender signing practices
  3780. + if (SuccessCount > 0 && !sFromDomain.empty()) {
  3781. + for (list < string >::iterator i = SuccessfulDomains.begin(); i != SuccessfulDomains.end(); ++i) {
  3782. + // see if the successful domain is the same as or a parent of the From domain
  3783. + if (i->length() > sFromDomain.length())
  3784. + continue;
  3785. + if (_stricmp(i->c_str(), sFromDomain.c_str() + sFromDomain.length() - i->length()) != 0)
  3786. + continue;
  3787. + if (i->length() == sFromDomain.length() || sFromDomain.c_str()[sFromDomain.length() - i->length() - 1] == '.')
  3788. + return ((SuccessCount == Signatures.size()) ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
  3789. + }
  3790. + }
  3791. + if (!m_Accept3ps)
  3792. + return DKIM_NEUTRAL;
  3793. + *sCount = SuccessCount;
  3794. + *sSize = Signatures.size();
  3795. + return DKIM_3PS_SIGNATURE;
  3796. +}
  3797. +
  3798. +////////////////////////////////////////////////////////////////////////////////
  3799. +//
  3800. +// Hash - update the hash
  3801. +//
  3802. +////////////////////////////////////////////////////////////////////////////////
  3803. +void
  3804. +SignatureInfo::Hash(const char *szBuffer, unsigned nBufLength, bool IsBody)
  3805. +{
  3806. +
  3807. + if (IsBody && BodyLength != -1) {
  3808. + VerifiedBodyCount += nBufLength;
  3809. + if (VerifiedBodyCount > BodyLength) {
  3810. + nBufLength = BodyLength - (VerifiedBodyCount - nBufLength);
  3811. + UnverifiedBodyCount += VerifiedBodyCount - BodyLength;
  3812. + VerifiedBodyCount = BodyLength;
  3813. + if (nBufLength == 0)
  3814. + return;
  3815. + }
  3816. + }
  3817. + if (IsBody && !BodyHashData.empty()) {
  3818. + EVP_DigestUpdate(&m_Bdy_ctx, szBuffer, nBufLength);
  3819. + } else {
  3820. + EVP_VerifyUpdate(&m_Hdr_ctx, szBuffer, nBufLength);
  3821. + }
  3822. + if (m_SaveCanonicalizedData) {
  3823. + CanonicalizedData.append(szBuffer, nBufLength);
  3824. + }
  3825. +}
  3826. +
  3827. +
  3828. +// ProcessHeaders - Look for DKIM-Signatures and start processing them
  3829. +int
  3830. +CDKIMVerify::ProcessHeaders(void)
  3831. +{
  3832. +
  3833. + // look for DKIM-Signature header(s)
  3834. + for (list < string >::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
  3835. + if (_strnicmp(i->c_str(), "DKIM-Signature", 14) == 0) {
  3836. + // skip over whitespace between the header name and :
  3837. + const char *s = i->c_str() + 14;
  3838. + while (*s == ' ' || *s == '\t')
  3839. + s++;
  3840. + if (*s == ':') {
  3841. + // found
  3842. + SignatureInfo sig(m_SaveCanonicalizedData);
  3843. + sig.Status = ParseDKIMSignature(*i, sig);
  3844. + Signatures.push_back(sig);
  3845. + if (Signatures.size() >= MAX_SIGNATURES)
  3846. + break;
  3847. + }
  3848. + }
  3849. + }
  3850. + if (Signatures.empty())
  3851. + return DKIM_NO_SIGNATURES;
  3852. + bool ValidSigFound = false;
  3853. + for (list < SignatureInfo >::iterator s = Signatures.begin(); s != Signatures.end(); ++s) {
  3854. + SignatureInfo & sig = *s;
  3855. + if (sig.Status != DKIM_SUCCESS)
  3856. + continue;
  3857. + SelectorInfo & sel = GetSelector(sig.Selector, sig.Domain);
  3858. + sig.m_pSelector = &sel;
  3859. + if (sel.Status != DKIM_SUCCESS) {
  3860. + sig.Status = sel.Status;
  3861. + return (sig.Status);
  3862. + } else {
  3863. + // check the granularity
  3864. + if (!WildcardMatch(sel.Granularity.c_str(), sig.IdentityLocalPart.c_str()))
  3865. + sig.Status = DKIM_SELECTOR_GRANULARITY_MISMATCH; // this error causes the signature to fail
  3866. + // check the hash algorithm
  3867. +#ifdef HAVE_EVP_SHA256
  3868. + if ((sig.m_nHash == DKIM_HASH_SHA1 && !sel.AllowSHA1) || (sig.m_nHash == DKIM_HASH_SHA256 && !sel.AllowSHA256))
  3869. +#else
  3870. + if ((sig.m_nHash == DKIM_HASH_SHA1 && !sel.AllowSHA1))
  3871. +#endif
  3872. + sig.Status = DKIM_SELECTOR_ALGORITHM_MISMATCH; // causes signature to fail
  3873. + // check for same domain
  3874. + if (sel.SameDomain && _stricmp(sig.Domain.c_str(), sig.IdentityDomain.c_str()) != 0)
  3875. + sig.Status = DKIM_BAD_SYNTAX;
  3876. + }
  3877. + if (sig.Status != DKIM_SUCCESS)
  3878. + continue;
  3879. + // initialize the hashes
  3880. +#ifdef HAVE_EVP_SHA256
  3881. + if (sig.m_nHash == DKIM_HASH_SHA256) {
  3882. + EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha256());
  3883. + EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha256());
  3884. + } else {
  3885. + EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha1());
  3886. + EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha1());
  3887. + }
  3888. +#else
  3889. + EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha1());
  3890. + EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha1());
  3891. +#endif
  3892. + // compute the hash of the header
  3893. + vector < list < string >::reverse_iterator > used;
  3894. + for (vector < string >::iterator x = sig.SignedHeaders.begin(); x != sig.SignedHeaders.end(); ++x) {
  3895. + list < string >::reverse_iterator i;
  3896. + for (i = HeaderList.rbegin(); i != HeaderList.rend(); ++i) {
  3897. + if (_strnicmp(i->c_str(), x->c_str(), x->length()) == 0) {
  3898. + // skip over whitespace between the header name and :
  3899. + const char *s = i->c_str() + x->length();
  3900. + while (*s == ' ' || *s == '\t')
  3901. + s++;
  3902. + if (*s == ':' && find(used.begin(), used.end(), i) == used.end())
  3903. + break;
  3904. + }
  3905. + }
  3906. + if (i != HeaderList.rend()) {
  3907. + used.push_back(i);
  3908. + // hash this header
  3909. + if (sig.HeaderCanonicalization == DKIM_CANON_SIMPLE) {
  3910. + sig.Hash(i->c_str(), i->length());
  3911. + }
  3912. + else
  3913. + if (sig.HeaderCanonicalization == DKIM_CANON_RELAXED) {
  3914. + string sTemp = RelaxHeader(*i);
  3915. + sig.Hash(sTemp.c_str(), sTemp.length());
  3916. + }
  3917. + else
  3918. + if (sig.HeaderCanonicalization == DKIM_CANON_NOWSP) {
  3919. + string sTemp = *i;
  3920. + RemoveSWSP(sTemp);
  3921. + // convert characters before ':' to lower case
  3922. + for (char *s = (char *)sTemp.c_str(); *s != '\0' && *s != ':'; s++) {
  3923. + if (*s >= 'A' && *s <= 'Z')
  3924. + *s += 'a' - 'A';
  3925. + }
  3926. + sig.Hash(sTemp.c_str(), sTemp.length());
  3927. + }
  3928. + sig.Hash("\r\n", 2);
  3929. + }
  3930. + }
  3931. + if (sig.BodyHashData.empty()) {
  3932. + // hash CRLF separating headers from body
  3933. + sig.Hash("\r\n", 2);
  3934. + }
  3935. + ValidSigFound = true;
  3936. + } /*- for (list < SignatureInfo >::iterator s = Signatures.begin(); s != Signatures.end(); ++s) { */
  3937. + if (!ValidSigFound)
  3938. + return DKIM_NO_VALID_SIGNATURES;
  3939. + return DKIM_SUCCESS;
  3940. +}
  3941. +
  3942. +
  3943. +////////////////////////////////////////////////////////////////////////////////
  3944. +//
  3945. +// Strictly parse an unsigned integer. Don't allow spaces, negative sign,
  3946. +// 0x prefix, etc. Values greater than 2^32-1 are capped at 2^32-1
  3947. +//
  3948. +////////////////////////////////////////////////////////////////////////////////
  3949. +bool
  3950. +ParseUnsigned(const char *s, int *result)
  3951. +{
  3952. + unsigned temp = 0, last = 0;
  3953. + bool overflowed = false;
  3954. +
  3955. + do {
  3956. + if (*s < '0' || *s > '9')
  3957. + return false; // returns false for an initial '\0'
  3958. + temp = temp * 10 + (*s - '0');
  3959. + if (temp < last)
  3960. + overflowed = true;
  3961. + last = temp;
  3962. + s++;
  3963. + } while (*s != '\0');
  3964. + if (overflowed)
  3965. + *result = -1;
  3966. + else
  3967. + *result = temp;
  3968. + return true;
  3969. +}
  3970. +
  3971. +
  3972. +// ParseDKIMSignature - Parse a DKIM-Signature header field
  3973. +int
  3974. +CDKIMVerify::ParseDKIMSignature(const string & sHeader, SignatureInfo & sig)
  3975. +{
  3976. +
  3977. + // save header for later
  3978. + sig.Header = sHeader;
  3979. + string sValue = sHeader.substr(sHeader.find(':') + 1);
  3980. + static const char *tags[] = { "v", "a", "b", "d", "h", "s", "c", "i", "l", "q", "t", "x", "bh", NULL };
  3981. + char *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
  3982. +
  3983. + if (!ParseTagValueList((char *) sValue.c_str(), tags, values))
  3984. + return DKIM_BAD_SYNTAX;
  3985. + // check signature version
  3986. + if (values[0] != NULL) {
  3987. + if (strcmp(values[0], "1") == 0 || strcmp(values[0], "0.5") == 0 || strcmp(values[0], "0.4") == 0
  3988. + || strcmp(values[0], "0.3") == 0 || strcmp(values[0], "0.2") == 0) {
  3989. + sig.Version = DKIM_SIG_VERSION_02_PLUS;
  3990. + } else {
  3991. + // unknown version
  3992. + return DKIM_STAT_INCOMPAT;
  3993. + }
  3994. + } else {
  3995. + // Note: DKIM Interop 1 pointed out that v= is now required, but we do
  3996. + // not enforce that in order to verify signatures made by older drafts.
  3997. +
  3998. + // prior to 0.2, there MUST NOT have been a v=
  3999. + // (optionally) support these signatures, for backwards compatibility
  4000. + if (true) {
  4001. + sig.Version = DKIM_SIG_VERSION_PRE_02;
  4002. + } else {
  4003. + return DKIM_BAD_SYNTAX;
  4004. + }
  4005. + }
  4006. + // signature MUST have a=, b=, d=, h=, s=
  4007. + if (values[1] == NULL || values[2] == NULL || values[3] == NULL || values[4] == NULL || values[5] == NULL)
  4008. + return DKIM_BAD_SYNTAX;
  4009. + // algorithm can be "rsa-sha1" or "rsa-sha256"
  4010. + if (strcmp(values[1], "rsa-sha1") == 0) {
  4011. + sig.m_nHash = DKIM_HASH_SHA1;
  4012. + }
  4013. +#ifdef HAVE_EVP_SHA256
  4014. + else if (strcmp(values[1], "rsa-sha256") == 0) {
  4015. + sig.m_nHash = DKIM_HASH_SHA256;
  4016. + }
  4017. +#endif
  4018. + else {
  4019. + return DKIM_BAD_SYNTAX; // todo: maybe create a new error code for unknown algorithm
  4020. + }
  4021. + // make sure the signature data is not empty
  4022. + unsigned SigDataLen = DecodeBase64(values[2]);
  4023. + if (SigDataLen == 0)
  4024. + return DKIM_BAD_SYNTAX;
  4025. + sig.SignatureData.assign(values[2], SigDataLen);
  4026. + // check for body hash
  4027. + if (values[12] == NULL) {
  4028. + // use the old single hash way for backwards compatibility
  4029. + if (sig.Version != DKIM_SIG_VERSION_PRE_02)
  4030. + return DKIM_BAD_SYNTAX;
  4031. + } else {
  4032. + unsigned BodyHashLen = DecodeBase64(values[12]);
  4033. + if (BodyHashLen == 0)
  4034. + return DKIM_BAD_SYNTAX;
  4035. + sig.BodyHashData.assign(values[12], BodyHashLen);
  4036. + }
  4037. + // domain must not be empty
  4038. + if (*values[3] == '\0')
  4039. + return DKIM_BAD_SYNTAX;
  4040. + sig.Domain = values[3];
  4041. + // signed headers must not be empty (more verification is done later)
  4042. + if (*values[4] == '\0')
  4043. + return DKIM_BAD_SYNTAX;
  4044. + // selector must not be empty
  4045. + if (*values[5] == '\0')
  4046. + return DKIM_BAD_SYNTAX;
  4047. + sig.Selector = values[5];
  4048. + // canonicalization
  4049. + if (values[6] == NULL) {
  4050. + sig.HeaderCanonicalization = sig.BodyCanonicalization = DKIM_CANON_SIMPLE;
  4051. + }
  4052. + else
  4053. + if (sig.Version == DKIM_SIG_VERSION_PRE_02 && strcmp(values[6], "nowsp") == 0) {
  4054. + // for backwards compatibility
  4055. + sig.HeaderCanonicalization = sig.BodyCanonicalization = DKIM_CANON_NOWSP;
  4056. + } else {
  4057. + char *slash = strchr(values[6], '/');
  4058. + if (slash != NULL)
  4059. + *slash = '\0';
  4060. + if (strcmp(values[6], "simple") == 0)
  4061. + sig.HeaderCanonicalization = DKIM_CANON_SIMPLE;
  4062. + else
  4063. + if (strcmp(values[6], "relaxed") == 0)
  4064. + sig.HeaderCanonicalization = DKIM_CANON_RELAXED;
  4065. + else
  4066. + return DKIM_BAD_SYNTAX;
  4067. + if (slash == NULL || strcmp(slash + 1, "simple") == 0)
  4068. + sig.BodyCanonicalization = DKIM_CANON_SIMPLE;
  4069. + else
  4070. + if (strcmp(slash + 1, "relaxed") == 0)
  4071. + sig.BodyCanonicalization = DKIM_CANON_RELAXED;
  4072. + else
  4073. + return DKIM_BAD_SYNTAX;
  4074. + }
  4075. + // identity
  4076. + if (values[7] == NULL) {
  4077. + sig.IdentityLocalPart.erase();
  4078. + sig.IdentityDomain = sig.Domain;
  4079. + } else {
  4080. + // quoted-printable decode the value
  4081. + DecodeQuotedPrintable(values[7]);
  4082. + // must have a '@' separating the local part from the domain
  4083. + char *at = strchr(values[7], '@');
  4084. + if (at == NULL)
  4085. + return DKIM_BAD_SYNTAX;
  4086. + *at = '\0';
  4087. + char *ilocalpart = values[7];
  4088. + char *idomain = at + 1;
  4089. + // i= domain must be the same as or a subdomain of the d= domain
  4090. + int idomainlen = strlen(idomain);
  4091. + int ddomainlen = strlen(values[3]);
  4092. +
  4093. + // todo: maybe create a new error code for invalid identity domain
  4094. + if (idomainlen < ddomainlen)
  4095. + return DKIM_BAD_SYNTAX;
  4096. + if (_stricmp(idomain + idomainlen - ddomainlen, values[3]) != 0)
  4097. + return DKIM_BAD_SYNTAX;
  4098. + if (idomainlen > ddomainlen && idomain[idomainlen - ddomainlen - 1] != '.')
  4099. + return DKIM_BAD_SYNTAX;
  4100. + sig.IdentityLocalPart = ilocalpart;
  4101. + sig.IdentityDomain = idomain;
  4102. + }
  4103. + // body count
  4104. + if (values[8] == NULL || !m_HonorBodyLengthTag) {
  4105. + sig.BodyLength = -1;
  4106. + } else {
  4107. + if (!ParseUnsigned(values[8], &sig.BodyLength))
  4108. + return DKIM_BAD_SYNTAX;
  4109. + }
  4110. + // query methods
  4111. + if (values[9] != NULL) {
  4112. +
  4113. + // make sure "dns" is in the list
  4114. + bool HasDNS = false;
  4115. + char *s = strtok(values[9], ":");
  4116. + while (s != NULL) {
  4117. + if (strncmp(s, "dns", 3) == 0 && (s[3] == '\0' || s[3] == '/')) {
  4118. + HasDNS = true;
  4119. + break;
  4120. + }
  4121. + s = strtok(NULL, ": \t");
  4122. + }
  4123. + if (!HasDNS)
  4124. + return DKIM_BAD_SYNTAX; // todo: maybe create a new error code for unknown query method
  4125. + }
  4126. + // signature time
  4127. + int SignedTime = -1;
  4128. + if (values[10] != NULL) {
  4129. + if (!ParseUnsigned(values[10], &SignedTime))
  4130. + return DKIM_BAD_SYNTAX;
  4131. + }
  4132. + // expiration time
  4133. + if (values[11] == NULL) {
  4134. + sig.ExpireTime = -1;
  4135. + } else {
  4136. + if (!ParseUnsigned(values[11], &sig.ExpireTime))
  4137. + return DKIM_BAD_SYNTAX;
  4138. + if (sig.ExpireTime != -1) {
  4139. + // the value of x= MUST be greater than the value of t= if both are present
  4140. + if (SignedTime != -1 && sig.ExpireTime <= SignedTime)
  4141. + return DKIM_BAD_SYNTAX;
  4142. + // todo: if possible, use the received date/time instead of the current time
  4143. + unsigned curtime = time(NULL);
  4144. + if (curtime > sig.ExpireTime)
  4145. + return DKIM_SIGNATURE_EXPIRED;
  4146. + }
  4147. + }
  4148. + // parse the signed headers list
  4149. + bool HasFrom = false, HasSubject = false;
  4150. + RemoveSWSP(values[4]); // header names shouldn't have spaces in them so this should be ok...
  4151. + char *s = strtok(values[4], ":");
  4152. + while (s != NULL) {
  4153. + if (_stricmp(s, "From") == 0)
  4154. + HasFrom = true;
  4155. + else
  4156. + if (_stricmp(s, "Subject") == 0)
  4157. + HasSubject = true;
  4158. + sig.SignedHeaders.push_back(s);
  4159. + s = strtok(NULL, ":");
  4160. + }
  4161. + if (!HasFrom)
  4162. + return DKIM_BAD_SYNTAX; // todo: maybe create a new error code for h= missing From
  4163. + if (m_SubjectIsRequired && !HasSubject)
  4164. + return DKIM_BAD_SYNTAX; // todo: maybe create a new error code for h= missing Subject
  4165. + return DKIM_SUCCESS;
  4166. +}
  4167. +
  4168. +
  4169. +// ProcessBody - Process message body data
  4170. +int
  4171. +CDKIMVerify::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
  4172. +{
  4173. + bool MoreBodyNeeded = false;
  4174. +
  4175. + for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
  4176. + if (i->Status == DKIM_SUCCESS) {
  4177. + if (i->BodyCanonicalization == DKIM_CANON_SIMPLE) {
  4178. + if (nBufLength > 0) {
  4179. + while (i->EmptyLineCount > 0) {
  4180. + i->Hash("\r\n", 2, true);
  4181. + i->EmptyLineCount--;
  4182. + }
  4183. + i->Hash(szBuffer, nBufLength, true);
  4184. + i->Hash("\r\n", 2, true);
  4185. + } else {
  4186. + i->EmptyLineCount++;
  4187. + if (bEOF)
  4188. + i->Hash("\r\n", 2, true);
  4189. + }
  4190. + } else
  4191. + if (i->BodyCanonicalization == DKIM_CANON_RELAXED) {
  4192. + CompressSWSP(szBuffer, nBufLength);
  4193. + if (nBufLength > 0) {
  4194. + while (i->EmptyLineCount > 0) {
  4195. + i->Hash("\r\n", 2, true);
  4196. + i->EmptyLineCount--;
  4197. + }
  4198. + i->Hash(szBuffer, nBufLength, true);
  4199. + if (!bEOF)
  4200. + i->Hash("\r\n", 2, true);
  4201. + } else
  4202. + i->EmptyLineCount++;
  4203. + } else
  4204. + if (i->BodyCanonicalization == DKIM_CANON_NOWSP) {
  4205. + RemoveSWSP(szBuffer, nBufLength);
  4206. + i->Hash(szBuffer, nBufLength, true);
  4207. + }
  4208. + if (i->UnverifiedBodyCount == 0)
  4209. + MoreBodyNeeded = true;
  4210. + }
  4211. + }
  4212. + if (!MoreBodyNeeded)
  4213. + return DKIM_FINISHED_BODY;
  4214. + return DKIM_SUCCESS;
  4215. +}
  4216. +
  4217. +SelectorInfo::SelectorInfo(const string & sSelector, const string & sDomain):Selector(sSelector), Domain(sDomain)
  4218. +{
  4219. + AllowSHA1 = true;
  4220. +#ifdef HAVE_EVP_SHA256
  4221. + AllowSHA256 = true;
  4222. +#else
  4223. + AllowSHA256 = false;
  4224. +#endif
  4225. + PublicKey = NULL;
  4226. + Testing = false;
  4227. + SameDomain = false;
  4228. + Status = DKIM_SUCCESS;
  4229. +} SelectorInfo::~SelectorInfo()
  4230. +{
  4231. + if (PublicKey != NULL) {
  4232. + EVP_PKEY_free(PublicKey);
  4233. + }
  4234. +}
  4235. +
  4236. +
  4237. +////////////////////////////////////////////////////////////////////////////////
  4238. +//
  4239. +// Parse - Parse a DKIM selector
  4240. +//
  4241. +////////////////////////////////////////////////////////////////////////////////
  4242. +int
  4243. +SelectorInfo::Parse(char *Buffer)
  4244. +{
  4245. + static const char *tags[] = { "v", "g", "h", "k", "p", "s", "t", "n", NULL };
  4246. + char *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
  4247. + if (!ParseTagValueList(Buffer, tags, values))
  4248. + return DKIM_SELECTOR_INVALID;
  4249. + if (values[0] != NULL) {
  4250. +
  4251. + // make sure the version is "DKIM1"
  4252. + if (strcmp(values[0], "DKIM1") != 0)
  4253. + return DKIM_SELECTOR_INVALID; // todo: maybe create a new error code for unsupported selector version
  4254. + // make sure v= is the first tag in the response // todo: maybe don't enforce this, it seems unnecessary
  4255. + for (int j = 1; j < sizeof (values) / sizeof (values[0]); j++) {
  4256. + if (values[j] != NULL && values[j] < values[0]) {
  4257. + return DKIM_SELECTOR_INVALID;
  4258. + }
  4259. + }
  4260. + }
  4261. + // selector MUST have p= tag
  4262. + if (values[4] == NULL)
  4263. + return DKIM_SELECTOR_INVALID;
  4264. + // granularity
  4265. + if (values[1] == NULL)
  4266. + Granularity = "*";
  4267. +
  4268. + else
  4269. + Granularity = values[1];
  4270. + // hash algorithm
  4271. + if (values[2] == NULL) {
  4272. + AllowSHA1 = true;
  4273. +#ifdef HAVE_EVP_SHA256
  4274. + AllowSHA256 = true;
  4275. +#else
  4276. + AllowSHA256 = false;
  4277. +#endif
  4278. + } else {
  4279. + // MUST include "sha1" or "sha256"
  4280. + char *s = strtok(values[2], ":");
  4281. + while (s != NULL) {
  4282. + if (strcmp(s, "sha1") == 0)
  4283. + AllowSHA1 = true;
  4284. +#ifdef HAVE_EVP_SHA256
  4285. + else if (strcmp(s, "sha256") == 0)
  4286. + AllowSHA256 = true;
  4287. +#endif
  4288. + s = strtok(NULL, ":");
  4289. + }
  4290. +#ifdef HAVE_EVP_SHA256
  4291. + if (!(AllowSHA1 || AllowSHA256))
  4292. +#else
  4293. + if (!AllowSHA1)
  4294. +#endif
  4295. + return DKIM_SELECTOR_INVALID; // todo: maybe create a new error code for unsupported hash algorithm
  4296. + }
  4297. + // key type
  4298. + if (values[3] != NULL) {
  4299. + // key type MUST be "rsa"
  4300. + if (strcmp(values[3], "rsa") != 0)
  4301. + return DKIM_SELECTOR_INVALID;
  4302. + }
  4303. + // service type
  4304. + if (values[5] != NULL) {
  4305. + // make sure "*" or "email" is in the list
  4306. + bool ServiceTypeMatch = false;
  4307. + char *s = strtok(values[5], ":");
  4308. + while (s != NULL) {
  4309. + if (strcmp(s, "*") == 0 || strcmp(s, "email") == 0) {
  4310. + ServiceTypeMatch = true;
  4311. + break;
  4312. + }
  4313. + s = strtok(NULL, ":");
  4314. + }
  4315. + if (!ServiceTypeMatch)
  4316. + return DKIM_SELECTOR_INVALID;
  4317. + }
  4318. + // flags
  4319. + if (values[6] != NULL) {
  4320. + char *s = strtok(values[6], ":");
  4321. + while (s != NULL) {
  4322. + if (strcmp(s, "y") == 0) {
  4323. + Testing = true;
  4324. + } else
  4325. + if (strcmp(s, "s") == 0) {
  4326. + SameDomain = true;
  4327. + }
  4328. + s = strtok(NULL, ":");
  4329. + }
  4330. + }
  4331. + // public key data
  4332. + unsigned
  4333. + PublicKeyLen = DecodeBase64(values[4]);
  4334. + if (PublicKeyLen == 0) {
  4335. + return DKIM_SELECTOR_KEY_REVOKED; // this error causes the signature to fail
  4336. + } else {
  4337. + const unsigned char *PublicKeyData = (unsigned char *) values[4];
  4338. + EVP_PKEY *pkey = d2i_PUBKEY(NULL, (const unsigned char **) &PublicKeyData, PublicKeyLen);
  4339. + if (pkey == NULL)
  4340. + return DKIM_SELECTOR_PUBLIC_KEY_INVALID;
  4341. + // make sure public key is the correct type (we only support rsa)
  4342. + if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2) {
  4343. + PublicKey = pkey;
  4344. + } else {
  4345. + EVP_PKEY_free(pkey);
  4346. + return DKIM_SELECTOR_PUBLIC_KEY_INVALID;
  4347. + }
  4348. + }
  4349. + return DKIM_SUCCESS;
  4350. +}
  4351. +
  4352. +// GetSelector - Get a DKIM selector for a domain
  4353. +SelectorInfo & CDKIMVerify::GetSelector(const string & sSelector, const string & sDomain)
  4354. +{
  4355. +
  4356. + // see if we already have this selector
  4357. + for (list < SelectorInfo >::iterator i = Selectors.begin(); i != Selectors.end(); ++i) {
  4358. + if (_stricmp(i->Selector.c_str(), sSelector.c_str()) == 0 && _stricmp(i->Domain.c_str(), sDomain.c_str()) == 0) {
  4359. + return *i;
  4360. + }
  4361. + }
  4362. + Selectors.push_back(SelectorInfo(sSelector, sDomain));
  4363. + SelectorInfo & sel = Selectors.back();
  4364. + string sFQDN = sSelector;
  4365. + sFQDN += "._domainkey.";
  4366. + sFQDN += sDomain;
  4367. + char Buffer[1024];
  4368. + int DNSResult;
  4369. +
  4370. + if (m_pfnSelectorCallback)
  4371. + DNSResult = m_pfnSelectorCallback(sFQDN.c_str(), Buffer, sizeof(Buffer));
  4372. + else
  4373. + DNSResult = DNSGetTXT(sFQDN.c_str(), Buffer, sizeof(Buffer));
  4374. + switch (DNSResult) {
  4375. + case DNSRESP_SUCCESS:
  4376. + sel.Status = sel.Parse(Buffer);
  4377. + break;
  4378. + case DNSRESP_TEMP_FAIL:
  4379. + sel.Status = DKIM_SELECTOR_DNS_TEMP_FAILURE;
  4380. + break;
  4381. + case DNSRESP_PERM_FAIL:
  4382. + default:
  4383. + sel.Status = DKIM_SELECTOR_DNS_PERM_FAILURE;
  4384. + break;
  4385. + case DNSRESP_DOMAIN_NAME_TOO_LONG:
  4386. + sel.Status = DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG;
  4387. + break;
  4388. + }
  4389. + return sel;
  4390. +}
  4391. +
  4392. +// GetDetails - Get DKIM verification details (per signature)
  4393. +int
  4394. +CDKIMVerify::GetDetails(int *nSigCount, DKIMVerifyDetails ** pDetails)
  4395. +{
  4396. + Details.clear();
  4397. + for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
  4398. + DKIMVerifyDetails d;
  4399. + d.szSignature = (char *) i->Header.c_str();
  4400. + d.nResult = i->Status;
  4401. + d.szCanonicalizedData = (char *) i->CanonicalizedData.c_str();
  4402. + Details.push_back(d);
  4403. + } *nSigCount = Details.size();
  4404. + *pDetails = (*nSigCount != 0) ? &Details[0] : NULL;
  4405. + return DKIM_SUCCESS;
  4406. +}
  4407. +
  4408. +char *DKIM_CALL
  4409. +CDKIMVerify::GetDomain(void)
  4410. +{
  4411. + string sFromDomain;
  4412. + for (list <string>::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
  4413. + if (_strnicmp(i->c_str(), "From", 4) == 0) {
  4414. + // skip over whitespace between the header name and :
  4415. + const char *s = i->c_str() + 4;
  4416. + while (*s == ' ' || *s == '\t')
  4417. + s++;
  4418. + if (*s == ':') {
  4419. + vector <string> Addresses;
  4420. + if (ParseAddresses(s + 1, Addresses)) {
  4421. + unsigned atpos = Addresses[0].find('@');
  4422. + sFromDomain = Addresses[0].substr(atpos + 1);
  4423. + break;
  4424. + }
  4425. + }
  4426. + }
  4427. + }
  4428. + return ((char *) sFromDomain.c_str());
  4429. +}
  4430. +
  4431. +void
  4432. +getversion_dkimverify_cpp()
  4433. +{
  4434. + static char *x = (char *) "$Id: dkimverify.cpp,v 1.5 2009-03-27 20:19:58+05:30 Cprogrammer Exp mbhangui $";
  4435. +
  4436. + x++;
  4437. +}
  4438. diff -Naur qmail-1.03.org/dkimverify.h qmail-1.03/dkimverify.h
  4439. --- qmail-1.03.org/dkimverify.h 1970-01-01 05:30:00.000000000 +0530
  4440. +++ qmail-1.03/dkimverify.h 2009-04-21 11:19:07.000000000 +0530
  4441. @@ -0,0 +1,118 @@
  4442. +/*
  4443. + * $Log: dkimverify.h,v $
  4444. + * Revision 1.2 2009-03-26 15:12:15+05:30 Cprogrammer
  4445. + * changes for ADSP
  4446. + *
  4447. + * Revision 1.1 2009-03-21 08:50:22+05:30 Cprogrammer
  4448. + * Initial revision
  4449. + *
  4450. + *
  4451. + * Copyright 2005 Alt-N Technologies, Ltd.
  4452. + *
  4453. + * Licensed under the Apache License, Version 2.0 (the "License");
  4454. + * you may not use this file except in compliance with the License.
  4455. + * You may obtain a copy of the License at
  4456. + *
  4457. + * http://www.apache.org/licenses/LICENSE-2.0
  4458. + *
  4459. + * This code incorporates intellectual property owned by Yahoo! and licensed
  4460. + * pursuant to the Yahoo! DomainKeys Patent License Agreement.
  4461. + *
  4462. + * Unless required by applicable law or agreed to in writing, software
  4463. + * distributed under the License is distributed on an "AS IS" BASIS,
  4464. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4465. + * See the License for the specific language governing permissions and
  4466. + * limitations under the License.
  4467. + *
  4468. + */
  4469. +
  4470. +#ifndef DKIMVERIFY_H
  4471. +#define DKIMVERIFY_H
  4472. +
  4473. +#include "dkimbase.h"
  4474. +#include <vector>
  4475. +
  4476. +#define DKIM_SIG_VERSION_PRE_02 0
  4477. +#define DKIM_SIG_VERSION_02_PLUS 1
  4478. +
  4479. +class SelectorInfo {
  4480. + public:
  4481. + SelectorInfo(const string & sSelector, const string & sDomain);
  4482. + ~SelectorInfo();
  4483. +
  4484. + string Domain;
  4485. + string Selector;
  4486. + string Granularity;
  4487. + bool AllowSHA1;
  4488. + bool AllowSHA256;
  4489. + EVP_PKEY *PublicKey; /* the public key */
  4490. + bool Testing;
  4491. + bool SameDomain;
  4492. + int Status;
  4493. + int Parse(char *Buffer);
  4494. +};
  4495. +
  4496. +class SignatureInfo {
  4497. +public:
  4498. + SignatureInfo(bool SaveCanonicalizedData);
  4499. + ~SignatureInfo();
  4500. +
  4501. + void Hash(const char *szBuffer, unsigned nBufLength, bool IsBody = false);
  4502. + string Header;
  4503. + unsigned Version;
  4504. + string Domain;
  4505. + string Selector;
  4506. + string SignatureData;
  4507. + string BodyHashData;
  4508. + string IdentityLocalPart;
  4509. + string IdentityDomain;
  4510. + string CanonicalizedData;
  4511. + vector <string> SignedHeaders;
  4512. + int BodyLength;
  4513. + unsigned HeaderCanonicalization;
  4514. + unsigned BodyCanonicalization;
  4515. + int ExpireTime;
  4516. + unsigned VerifiedBodyCount;
  4517. + unsigned UnverifiedBodyCount;
  4518. + EVP_MD_CTX m_Hdr_ctx;
  4519. + EVP_MD_CTX m_Bdy_ctx;
  4520. + SelectorInfo *m_pSelector;
  4521. + int Status;
  4522. + int m_nHash; // use one of the DKIM_HASH_xxx constants here
  4523. + unsigned EmptyLineCount;
  4524. + bool m_SaveCanonicalizedData;
  4525. +};
  4526. +
  4527. +class CDKIMVerify:public CDKIMBase {
  4528. +public:
  4529. +
  4530. + CDKIMVerify();
  4531. + ~CDKIMVerify();
  4532. +
  4533. + int Init(DKIMVerifyOptions * pOptions);
  4534. + int GetResults(int *sCount, int *sSize);
  4535. + int GetDetails(int *nSigCount, DKIMVerifyDetails ** pDetails);
  4536. + virtual int ProcessHeaders(void);
  4537. + virtual int ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
  4538. + const char *GetPractices() {return Practices.c_str();}
  4539. + char *DKIM_CALL GetDomain(void);
  4540. +
  4541. +protected:
  4542. + int ParseDKIMSignature(const string & sHeader, SignatureInfo & sig);
  4543. + SelectorInfo &GetSelector(const string & sSelector, const string & sDomain);
  4544. + int GetADSP(const string &sDomain, int &iADSP);
  4545. + int GetSSP(const string &sDomain, int &iSSP, bool & bTesting);
  4546. + list <SignatureInfo> Signatures;
  4547. + list <SelectorInfo> Selectors;
  4548. + DKIMDNSCALLBACK m_pfnSelectorCallback; // selector record callback
  4549. + DKIMDNSCALLBACK m_pfnPracticesCallback; // SSP record callback
  4550. + bool m_HonorBodyLengthTag;
  4551. + bool m_CheckPractices;
  4552. + bool m_Accept3ps; //TBS(Luc) : accept 3rd party signature(s)
  4553. + bool m_SubjectIsRequired;
  4554. + bool m_SaveCanonicalizedData;
  4555. + vector <DKIMVerifyDetails> Details;
  4556. + string Practices;
  4557. +};
  4558. +
  4559. +#endif /*- DKIMVERIFY_H */
  4560. diff -Naur qmail-1.03.org/dktrace.h qmail-1.03/dktrace.h
  4561. --- qmail-1.03.org/dktrace.h 1970-01-01 05:30:00.000000000 +0530
  4562. +++ qmail-1.03/dktrace.h 2009-04-21 11:19:07.000000000 +0530
  4563. @@ -0,0 +1,26 @@
  4564. +/* $Id: dktrace.h,v 1.3 2005/06/27 18:47:57 ted46045 Exp $ */
  4565. +
  4566. +#ifndef _DK_TRACE_H
  4567. +#define _DK_TRACE_H
  4568. +
  4569. +typedef struct {
  4570. + int ccounts_h[256];
  4571. + int ccounts_H[256];
  4572. + int ccounts_b[256];
  4573. + int ccounts_B[256];
  4574. +} DK_TRACE;
  4575. +
  4576. +typedef enum { DKT_RAW_HEADER='h', DKT_CANON_HEADER='H',
  4577. + DKT_RAW_BODY='b', DKT_CANON_BODY='B' } DK_TRACE_TYPE;
  4578. +
  4579. +#define dkt_init(s) memset(s,0,sizeof(DK_TRACE))
  4580. +
  4581. +//extern void dkt_init(DK_TRACE *dkp);
  4582. +extern void dkt_add(DK_TRACE *dkp, DK_TRACE_TYPE type, const unsigned char *data, int dataLength);
  4583. +extern int dkt_diff(DK_TRACE *dka, DK_TRACE *dkb, DK_TRACE_TYPE type, DK_TRACE *table);
  4584. +extern void dkt_quickadd(DK_TRACE *dkp, DK_TRACE_TYPE type, int index, int count);
  4585. +extern int dkt_getcount(DK_TRACE *dkp, DK_TRACE_TYPE type, int index, int count);
  4586. +extern int dkt_generate(DK_TRACE *dkp, DK_TRACE_TYPE type, char *buffer, int maxBufferSize);
  4587. +extern int dkt_hdrtotrace(char *ptr, DK_TRACE *store);
  4588. +
  4589. +#endif
  4590. diff -Naur qmail-1.03.org/domainkeys.h qmail-1.03/domainkeys.h
  4591. --- qmail-1.03.org/domainkeys.h 1970-01-01 05:30:00.000000000 +0530
  4592. +++ qmail-1.03/domainkeys.h 2009-04-21 11:19:07.000000000 +0530
  4593. @@ -0,0 +1,377 @@
  4594. +/* This file is automatically created from the corresponding .c file */
  4595. +/* Do not change this file; change the .c file instead. */
  4596. +/* This is libdomainkeys. It's Copyright (c) 2004 Yahoo, Inc.
  4597. + * This code incorporates intellectual property owned by
  4598. + * Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License
  4599. + * Agreement: http://domainkeys.sourceforge.net/license/softwarelicense1-0.html
  4600. + */
  4601. +#include <openssl/evp.h>
  4602. +#include <openssl/pem.h>
  4603. +#include <openssl/err.h>
  4604. +
  4605. +#ifdef SWIG
  4606. +%module domainkeys
  4607. +%{
  4608. +#include "domainkeys.h"
  4609. +%}
  4610. +#endif
  4611. +
  4612. +#include "dktrace.h"
  4613. +
  4614. +/* Performance/Debug options.
  4615. + * Uncomment below or use -D switch in gcc
  4616. + * DK_DEBUG Dumps whatever dkhash() hashes in to stderr and turns on
  4617. + * some debug warnings that should never happen
  4618. + * DK_HASH_BUFF Enables code that uses a buffer when processing the
  4619. + * canocalized message, reducing calls to the crypto library (from dkhash()),
  4620. + * but can use up slightly more memory
  4621. +*/
  4622. +//#define DK_DEBUG 1
  4623. +#define DK_HASH_BUFF 1
  4624. +
  4625. +
  4626. +#define DKMARK ('D' | 'K'<<8 | 'E'<<16 | 'Y'<<24)
  4627. +#define DK_SIGNING_SIGN 0
  4628. +#define DK_SIGNING_VERIFY 1
  4629. +#define DK_SIGNING_NOSIGN 2
  4630. +#define DK_SIGNING_NOVERIFY 3
  4631. +#define DK_MALLOC(s) OPENSSL_malloc(s)
  4632. +#define DK_MFREE(s) OPENSSL_free(s); s = NULL;
  4633. +#define DKERR(x) ((dk->errline=__LINE__),(dk->errfile=__FILE__),(x))
  4634. +#define DK_BLOCK 1024 //default size of malloc'd block
  4635. +
  4636. +/*
  4637. + * Option Flags for dk_setopts
  4638. + * OR together or run dk_setopts several times
  4639. + * All option flags are OFF by default
  4640. +*/
  4641. +#define DKOPT_TRACE_h 0x01 //enables tracking character count in pre-canon header
  4642. +#define DKOPT_TRACE_H 0x02 //enables tracking character count in post-canon header
  4643. +#define DKOPT_TRACE_b 0x04 //enables tracking character count in pre-canon body
  4644. +#define DKOPT_TRACE_B 0x08 //enables tracking character count in post-canon header
  4645. +#define DKOPT_RDUPE 0x10 //enables skipping duplicate headers when generateing a signature
  4646. +
  4647. +typedef enum
  4648. +{
  4649. + DK_STAT_OK, /* Function completed successfully */
  4650. + DK_STAT_BADSIG, /* Signature was available but failed to verify against domain specified key */
  4651. + DK_STAT_NOSIG, /* No signature available in message */
  4652. + DK_STAT_NOKEY, /* No public key available (permanent failure) */
  4653. + DK_STAT_BADKEY, /* Unusable key, public if verifying, private if signing */
  4654. + DK_STAT_CANTVRFY, /* Cannot get domain key to verify signature (temporary failure) */
  4655. + DK_STAT_SYNTAX, /* Message is not valid syntax. Signature could not be created/checked */
  4656. + DK_STAT_NORESOURCE, /* Could not get critical resource (temporary failure) */
  4657. + DK_STAT_ARGS, /* Arguments are not usable. */
  4658. + DK_STAT_REVOKED, /* Key has been revoked. */
  4659. + DK_STAT_INTERNAL, /* cannot call this routine in this context. Internal error. */
  4660. + DK_STAT_GRANULARITY, /* Granularity mismatch: sender doesn't match g= option. */
  4661. +} DK_STAT;
  4662. +
  4663. +typedef enum
  4664. +{
  4665. + DK_FLAG_TESTING = 1, /* set when in testing mode. */
  4666. + DK_FLAG_SIGNSALL = 2, /* domain signs all outgoing email. */
  4667. + DK_FLAG_SET = 4, /* flags set from a successful DNS query */
  4668. + DK_FLAG_G = 8, /* g tag was present in the selector. */
  4669. +} DK_FLAGS;
  4670. +typedef enum
  4671. +{
  4672. + DK_TXT_KEY = 0,
  4673. + DK_TXT_POLICY
  4674. +} DK_TXT;
  4675. +
  4676. +typedef enum
  4677. +{
  4678. + DK_CANON_SIMPLE = 0,
  4679. + DK_CANON_NOFWS = 1,
  4680. +} DK_CANON;
  4681. +/* STARTSTRUCT */
  4682. +typedef struct
  4683. +{
  4684. +
  4685. +} DK_LIB;
  4686. +/* STOPSTRUCT */
  4687. +
  4688. +//UnixWare Fix -Tim
  4689. +/* STARTSTRUCT */
  4690. +typedef struct
  4691. +{
  4692. +} DK;
  4693. +/* STOPSTRUCT */
  4694. +
  4695. +
  4696. +/* returns the source file from which an error was returned. */
  4697. +char * dk_errfile(DK *dk)
  4698. +;
  4699. +
  4700. +
  4701. +/* returns the source line number from which an error was returned. */
  4702. +int dk_errline(DK *dk)
  4703. +;
  4704. +
  4705. +
  4706. +/* Per-process, one-time initialization
  4707. + * Returns library structure for subsequent dk_sign or dk_verify calls.
  4708. + * Consult statp before using.
  4709. + *
  4710. + * When terminating the PROCESS its a good idea to call dk_shutdown()
  4711. + * When terminating a THREAD it's a good idea to call ERR_remove_state(0); defined in <openssl/err.h>
  4712. + * NOTE: DK_LIB pointers are safe to use over multiple threads
  4713. + * DK pointers are NOT safe to use over multiple threads
  4714. + */
  4715. +DK_LIB *dk_init(DK_STAT *statp)
  4716. +;
  4717. +
  4718. +
  4719. +/* Per-process, one-time cleanup
  4720. + * Should be called just before the application ends.
  4721. + * the dklib pointer is not valid anymore after this call
  4722. + * This function should be called even if dk_init failed.
  4723. + * It's safe to call dk_shutdown with a NULL pointer
  4724. + */
  4725. +void dk_shutdown(DK_LIB * dklib)
  4726. +;
  4727. +
  4728. +
  4729. +/* Set dk options, use instead of dk_remdupe and dk_enable_trace
  4730. + * Can be called multiple times.
  4731. + * use after dk_sign()/dk_verify()
  4732. + *
  4733. + * the bits field can be an OR of any of the following
  4734. + *DKOPT_TRACE_h Trace pre-canon header
  4735. + *DKOPT_TRACE_H Trace post-canon header
  4736. + *DKOPT_TRACE_b Trace pre-canon body
  4737. + *DKOPT_TRACE_B Trace post-canon body
  4738. + *DKOPT_RDUPE Exclude duplicate headers from hash (Signing only)
  4739. + */
  4740. +DK_STAT dk_setopts(DK *dk, int bits)
  4741. +;
  4742. +
  4743. +
  4744. +/* returns the int holding the options set
  4745. + * See dk_setopts for bit flags
  4746. + */
  4747. +int dk_getopts(DK *dk)
  4748. +;
  4749. +
  4750. +
  4751. +/* DEPRECATED in favor of calling dk_setopts().
  4752. + * Enables character trace tracking
  4753. + *
  4754. + * use after dk_sign()/dk_verify()
  4755. + */
  4756. +DK_STAT dk_enable_trace(DK *dk)
  4757. +;
  4758. +
  4759. +
  4760. +/* Prints trace table to *store variable (char string)
  4761. + * *dk is the container for the table
  4762. + * *store is a pointer to a character array to output to
  4763. + * store_size is the size of the character array *store
  4764. + *
  4765. + */
  4766. +DK_STAT dk_get_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
  4767. +;
  4768. +
  4769. +
  4770. +/* Prints difference trace table to *store variable (char string)
  4771. + * *dk is the container for the table
  4772. + * *store is a pointer to a character array to output to
  4773. + * store_size is the size of the character array *store
  4774. + * return DK_STAT_NOSIG if no DK-Trace header was found
  4775. + */
  4776. +DK_STAT dk_compare_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
  4777. +;
  4778. +
  4779. +
  4780. +/* Sets the DNS key/policy record manually (no DNS lookup)
  4781. + * txtrecord needs to be set to "e=perm;" to force a permanent DNS failure
  4782. + * txtrecord needs to be set to "e=temp;" to force a temporary DNS failure
  4783. + * Valid DK_TXT types are:
  4784. + * DK_TXT_KEY (normal selector record; for <selctor>._domainkey.<domain>)
  4785. + * DK_TXT_POLICY (domain policy record; for _domainkey.<domain>)
  4786. + */
  4787. +DK_STAT dk_settxt(DK *dk, DK_TXT recordtype, const char *txtrecord)
  4788. +;
  4789. +
  4790. +
  4791. +/* Per-message, may be threaded.
  4792. + * canon is one of DK_CANON_*.
  4793. + * Returns state structure for operation. Consult statp before using.
  4794. + */
  4795. +DK *dk_sign(DK_LIB *dklib, DK_STAT *statp, int canon)
  4796. +;
  4797. +
  4798. +
  4799. +/* Per-message, may be threaded.
  4800. + * Returns state structure for operation. Consult statp before using.
  4801. + */
  4802. +DK *dk_verify(DK_LIB *dklib, DK_STAT *statp)
  4803. +;
  4804. +
  4805. +
  4806. +/* DEPRECATED in favor of calling dk_setopts()
  4807. + * set option to remove dupe headers
  4808. + * should be called after dk_sign();
  4809. + * any int NOT 0 turns dupe removal on
  4810. + */
  4811. +DK_STAT dk_remdupe(DK *dk,int i)
  4812. +;
  4813. +
  4814. +
  4815. +/* Returns the policy flags belonging to the signing domain.
  4816. + * Sender: overrides From:, and the d= entry in the DK-Sig overrides both.
  4817. + * If the policy flags were not successfully fetched, DK_FLAG_SET will not
  4818. + * be set.
  4819. + */
  4820. +DK_FLAGS dk_policy(DK *dk)
  4821. +;
  4822. +
  4823. +
  4824. +/* Copies the header names that were signed into the pointer.
  4825. + * Returns the number of bytes copied.
  4826. + * ptr may be NULL, in which case the bytes are just counted, not copied.
  4827. + * Feel free to call this twice; once to get the length, and again to
  4828. + * copy the data.
  4829. + * NOTE: If the return value is 0 then an error occured.
  4830. + * It's a good idea to check for this
  4831. + */
  4832. +int dk_headers(DK *dk, char *ptr)
  4833. +;
  4834. +
  4835. +
  4836. +/* Must NOT include dots inserted for SMTP encapsulation.
  4837. + * Must NOT include CRLF.CRLF which terminates the message.
  4838. + * Otherwise must be exactly that which is sent or received over the SMTP session.
  4839. + * May be called multiple times (not necessary to read an entire message into memory).
  4840. + */
  4841. +DK_STAT dk_message(DK *dk, const unsigned char *ptr, size_t len)
  4842. +;
  4843. +
  4844. +
  4845. +/* DEPRECATED in favor of calling dk_address().
  4846. + * Returns a pointer to a null-terminated domain name portion of an RFC 2822 address.
  4847. + * If a Sender: was encountered, it returns that domain. Otherwise,
  4848. + * if a From: was encountered, it returns that domain. Otherwise,
  4849. + * return NULL.
  4850. + * return NULL if no domain name found in the address.
  4851. + * return NULL if the dk is unusable for any reason.
  4852. + * return NULL if the address is unusable for any reason.
  4853. + */
  4854. +char *dk_from(DK *dk)
  4855. +;
  4856. +
  4857. +
  4858. +/* Returns a pointer to the selector name used or NULL if there isn't one
  4859. + * Added by rjp
  4860. + */
  4861. +const char *dk_selector(DK *dk)
  4862. +;
  4863. +
  4864. +
  4865. +/* Returns a pointer to the domain name used or NULL if there isn't one
  4866. + */
  4867. +const char *dk_domain(DK *dk)
  4868. +;
  4869. +
  4870. +
  4871. +/*
  4872. + * Returns a pointer to a string which begins with "N", "S", or "F",
  4873. + * corresponding to None, Sender: and From:, respectively.
  4874. + * This single character is followed by a null-terminated RFC 2822 address.
  4875. + * The first character is "N" if no valid address has been seen yet,
  4876. + * "S" if the address came from the Sender: field, and "F" if the
  4877. + * address came from the From: field.
  4878. + */
  4879. +char *dk_address(DK *dk)
  4880. +;
  4881. +
  4882. +
  4883. +/*
  4884. + * Returns a pointer to a null-terminated string containing the granularity
  4885. + * value found in the selector DNS record, if any, but only after dk_end
  4886. + * has been called. Otherwise returns NULL.
  4887. + */
  4888. +char *dk_granularity(DK *dk)
  4889. +;
  4890. +
  4891. +
  4892. +/*
  4893. + * Called at end-of-message (before response to DATA-dot, if synchronous with SMTP session).
  4894. + * If verifying, returns signature validity.
  4895. + * This does not calculate the signature. Call dk_getsig() for that.
  4896. + * Flags are returned indirectly through dkf.
  4897. + * If you pass in NULL for dkf, the flags will not be fetched.
  4898. + * If there is a DK-Sig line, the d= entry will be used to fetch the flags.
  4899. + * Otherwise the Sender: domain will be used to fetch the flags.
  4900. + * Otherwise the From: domain will be used to fetch the flags.
  4901. + *
  4902. + * NOTE: If for some reason dk_end() returns an error (!DK_STAT_OK) dk_policy() should be called
  4903. + * to get the domain signing policy (o=) and handle accordingly.
  4904. + * dkf (selector flags) wont be set if dk_end() returns
  4905. + * DK_STAT_NOSIG
  4906. + * DK_STAT_NOKEY
  4907. + * DK_STAT_SYNTAX
  4908. + * DK_STAT_NORESOURCE
  4909. + * DK_STAT_BADKEY
  4910. + * DK_STAT_CANTVERIFY
  4911. + */
  4912. +DK_STAT dk_end(DK *dk, DK_FLAGS *dkf)
  4913. +;
  4914. +
  4915. +
  4916. +/*
  4917. + * DEPRECATED in favor of calling dk_end and dk_policy() directly.
  4918. + * If you pass in NULL for dkf, the policy flags will not be fetched.
  4919. + * If the message verified okay, the policy flags will not be fetched.
  4920. + */
  4921. +DK_STAT dk_eom(DK *dk, DK_FLAGS *dkf)
  4922. +;
  4923. +
  4924. +
  4925. +/*
  4926. + *
  4927. + * privatekey is the private key used to create the signature; It should contain
  4928. + * the entire contents of a PEM-format private key file, thusly it will begin with
  4929. + * -----BEGIN RSA PRIVATE KEY-----. It should be null-terminated.
  4930. + */
  4931. +size_t dk_siglen(void *privatekey)
  4932. +;
  4933. +
  4934. +
  4935. +/*
  4936. + * Sets buf to a null-terminated string.
  4937. + * If the message is being signed, signature is stored in the buffer.
  4938. + * If the message is being verified, returns DK_STAT_INTERNAL.
  4939. + * privatekey is the private key used to create the signature; It should contain
  4940. + * the entire contents of a PEM-format private key file, thus it will begin with
  4941. + * -----BEGIN RSA PRIVATE KEY-----. It should be null-terminated.
  4942. + * If you pass in NULL for buf, you'll get back DK_STAT_NORESOURCE.
  4943. + * If len is not big enough, you'll get back DK_STAT_NORESOURCE.
  4944. + */
  4945. +DK_STAT dk_getsig(DK *dk, void *privatekey, unsigned char buf[], size_t len)
  4946. +;
  4947. +
  4948. +
  4949. +/*
  4950. + * Free all resources associated with this message.
  4951. + * dk is no longer usable.
  4952. + * if doClearErrState != 0, the OpenSSL ErrorState is freed.
  4953. + * Set clearErrState=0 if you use other openssl functions and
  4954. + * want to call openssl's ERR_remove_state(0) by yourself
  4955. + * ERR_remove_state(0) is declared in <openssl/err.h>
  4956. + */
  4957. +DK_STAT dk_free(DK *dk, int doClearErrState)
  4958. +;
  4959. +
  4960. +
  4961. +/*
  4962. + * return a pointer to a string which describes st.
  4963. + * The string is structured. All the characters up to the first colon
  4964. + * contain the name of the DK_STAT constant. From there to the end of
  4965. + * string is a human-readable description of the error.
  4966. + */
  4967. +const char *DK_STAT_to_string(DK_STAT st)
  4968. +;
  4969. +
  4970. +
  4971. diff -Naur qmail-1.03.org/macros.h qmail-1.03/macros.h
  4972. --- qmail-1.03.org/macros.h 1970-01-01 05:30:00.000000000 +0530
  4973. +++ qmail-1.03/macros.h 2009-04-21 11:19:07.000000000 +0530
  4974. @@ -0,0 +1,25 @@
  4975. +/*
  4976. + * $Log: macros.h,v $
  4977. + * Revision 1.1 2009-03-21 08:50:25+05:30 Cprogrammer
  4978. + * Initial revision
  4979. + *
  4980. + *
  4981. + * macros.h: Useful macros
  4982. + *
  4983. + * Author:
  4984. + * Dick Porter (dick@ximian.com)
  4985. + *
  4986. + * (C) 2002 Ximian, Inc.
  4987. + */
  4988. +
  4989. +#ifndef _WAPI_MACROS_H_
  4990. +#define _WAPI_MACROS_H_
  4991. +
  4992. +#include <sys/types.h>
  4993. +
  4994. +#define MAKEWORD(low, high) ((__uint16_t)(((__uint8_t)(low)) | \
  4995. + ((__uint16_t)((__uint8_t)(high))) << 8))
  4996. +#define LOBYTE(i16) ((__uint8_t)((i16) & 0xFF))
  4997. +#define HIBYTE(i16) ((__uint8_t)(((__uint16_t)(i16) >> 8) & 0xFF))
  4998. +
  4999. +#endif /* _WAPI_MACROS_H_ */
  5000. diff -Naur qmail-1.03.org/MakeArgs.c qmail-1.03/MakeArgs.c
  5001. --- qmail-1.03.org/MakeArgs.c 1970-01-01 05:30:00.000000000 +0530
  5002. +++ qmail-1.03/MakeArgs.c 2009-04-21 11:19:07.000000000 +0530
  5003. @@ -0,0 +1,144 @@
  5004. +/*
  5005. + * $Log: MakeArgs.c,v $
  5006. + * Revision 2.8 2007-12-21 14:35:42+05:30 Cprogrammer
  5007. + * included env.h to prevent compiler warning
  5008. + *
  5009. + * Revision 2.7 2007-12-20 12:45:28+05:30 Cprogrammer
  5010. + * expand environment variables with '$' sign
  5011. + *
  5012. + * Revision 2.6 2005-08-23 17:31:28+05:30 Cprogrammer
  5013. + * removed sccsid variable
  5014. + *
  5015. + * Revision 2.5 2005-04-02 19:06:02+05:30 Cprogrammer
  5016. + * djb version
  5017. + *
  5018. + * Revision 2.4 2005-03-30 22:52:47+05:30 Cprogrammer
  5019. + * BUG - Incorrect free
  5020. + *
  5021. + * Revision 2.3 2004-07-12 22:47:58+05:30 Cprogrammer
  5022. + * bug fix. Free all allocated members
  5023. + *
  5024. + * Revision 2.2 2002-12-21 18:21:09+05:30 Cprogrammer
  5025. + * added functionality of escaping text via quotes
  5026. + *
  5027. + * Revision 2.1 2002-08-13 20:35:44+05:30 Cprogrammer
  5028. + * addition spaces were not getting skipped
  5029. + *
  5030. + * Revision 1.2 2002-03-03 17:23:05+05:30 Cprogrammer
  5031. + * replaced strcpy with scopy
  5032. + *
  5033. + * Revision 1.1 2001-12-13 01:46:09+05:30 Cprogrammer
  5034. + * Initial revision
  5035. + *
  5036. + */
  5037. +#include "alloc.h"
  5038. +#include "str.h"
  5039. +#include "stralloc.h"
  5040. +#include "env.h"
  5041. +#include <ctype.h>
  5042. +
  5043. +#define isEscape(ch) ((ch) == '"' || (ch) == '\'')
  5044. +
  5045. +/*
  5046. + * function to expand a string into command line
  5047. + * arguments. To free memory allocated by this
  5048. + * function the following should be done
  5049. + *
  5050. + * free(argv);
  5051. + *
  5052. + */
  5053. +char **
  5054. +MakeArgs(char *cmmd)
  5055. +{
  5056. + char *ptr, *marker;
  5057. + char **argv;
  5058. + int argc, idx;
  5059. + static stralloc sptr = { 0 };
  5060. +
  5061. + for (ptr = cmmd;*ptr && isspace((int) *ptr);ptr++);
  5062. + idx = str_len(ptr);
  5063. + if (!stralloc_copys(&sptr, ptr))
  5064. + return((char **) 0);
  5065. + if (!stralloc_0(&sptr))
  5066. + return((char **) 0);
  5067. + /*-
  5068. + * Get the number of arguments by counting
  5069. + * white spaces. Allow escape via the double
  5070. + * quotes character at the first word
  5071. + */
  5072. + for (argc = 0, ptr = sptr.s;*ptr;)
  5073. + {
  5074. + for (;*ptr && isspace((int) *ptr);ptr++);
  5075. + if (!*ptr)
  5076. + break;
  5077. + argc++;
  5078. + marker = ptr;
  5079. + /*- Move till you hit the next white space */
  5080. + for (;*ptr && !isspace((int) *ptr);ptr++)
  5081. + {
  5082. + /*-
  5083. + * 1. If escape char is encounted skip till you
  5084. + * hit the terminating escape char
  5085. + * 2. If terminating escape char is missing, come
  5086. + * back to the start escape char
  5087. + */
  5088. + if (ptr == marker && isEscape(*ptr))
  5089. + {
  5090. + for (ptr++;*ptr && !isEscape(*ptr);ptr++);
  5091. + if (!*ptr)
  5092. + ptr = marker;
  5093. + }
  5094. + } /*- for(;*ptr && !isspace((int) *ptr);ptr++) */
  5095. + } /*- for (argc = 0, ptr = sptr.s;*ptr;) */
  5096. + /*
  5097. + * Allocate memory to store the arguments
  5098. + * Do not bother extra bytes occupied by
  5099. + * white space characters.
  5100. + */
  5101. + if (!(argv = (char **) alloc((argc + 1) * sizeof(char *))))
  5102. + return ((char **) 0);
  5103. + for (idx = 0, ptr = sptr.s;*ptr;)
  5104. + {
  5105. + for (;*ptr && isspace((int) *ptr);ptr++)
  5106. + *ptr = 0;
  5107. + if (!*ptr)
  5108. + break;
  5109. + if (*ptr == '$')
  5110. + argv[idx++] = env_get(ptr + 1);
  5111. + else
  5112. + argv[idx++] = ptr;
  5113. + marker = ptr;
  5114. + for (;*ptr && !isspace((int) *ptr);ptr++)
  5115. + {
  5116. + if (ptr == marker && isEscape(*ptr))
  5117. + {
  5118. + for (ptr++;*ptr && !isEscape(*ptr);ptr++);
  5119. + if (!*ptr)
  5120. + ptr = marker;
  5121. + else /*- Remove the quotes */
  5122. + {
  5123. + argv[idx - 1] += 1;
  5124. + *ptr = 0;
  5125. + }
  5126. + }
  5127. + }
  5128. + } /*- for (idx = 0, ptr = sptr.s;*ptr;) */
  5129. + argv[idx++] = (char *) 0;
  5130. + return (argv);
  5131. +}
  5132. +
  5133. +void
  5134. +FreeMakeArgs(char **argv)
  5135. +{
  5136. + alloc_free(argv);
  5137. + return;
  5138. +}
  5139. +
  5140. +void
  5141. +getversion_MakeArgs__c()
  5142. +{
  5143. + static char *x = "$Id: MakeArgs.c,v 2.8 2007-12-21 14:35:42+05:30 Cprogrammer Stab mbhangui $";
  5144. + x++;
  5145. + x--;
  5146. + return;
  5147. +}
  5148. --- qmail-1.03.orig/Makefile 2009-10-15 20:38:22.838352000 +0300
  5149. +++ qmail-1.03/Makefile 2009-10-16 00:05:47.238647935 +0300
  5150. @@ -1045,6 +1045,7 @@
  5151. dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
  5152. forward preline condredirect bouncesaying except maildirmake \
  5153. maildir2mbox maildirwatch qail elq pinq idedit install-big \
  5154. +qmail-dk qmail-dkim dkimtest spawn-filter dk-filter \
  5155. install instcheck home home+df proc proc+df binm1 \
  5156. binm1+df binm2 binm2+df binm3 binm3+df
  5157. @@ -1204,7 +1205,7 @@
  5158. maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \
  5159. qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \
  5160. qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \
  5161. -envelopes.0 forgeries.0
  5162. +envelopes.0 forgeries.0 qmail-dk.0 qmail-dkim.0 dk-filter.0 spawn-filter.0
  5163. mbox.0: \
  5164. mbox.5
  5165. @@ -1475,6 +1476,48 @@
  5166. | sed s}BREAK}"`head -1 conf-break`"}g \
  5167. | sed s}SPAWN}"`head -1 conf-spawn`"}g \
  5168. > qmail-control.5
  5169. +qmail-dk: \
  5170. +load qmail-dk.o triggerpull.o fmtqfn.o now.o date822fmt.o \
  5171. +subgetopt.o MakeArgs.o datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
  5172. +str.a case.a fs.a auto_qmail.o auto_split.o auto_uids.o fd.a wait.a \
  5173. +/usr/lib/libdomainkeys.a env.a getln.a control.o stralloc.a
  5174. + ./load qmail-dk triggerpull.o fmtqfn.o now.o \
  5175. + date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
  5176. + subgetopt.o MakeArgs.o substdio.a error.a fs.a auto_qmail.o \
  5177. + auto_split.o auto_uids.o \
  5178. + fd.a wait.a /usr/lib/libdomainkeys.a -lcrypto -lresolv env.a control.o open.a getln.a \
  5179. + stralloc.a alloc.a substdio.a str.a case.a
  5180. +
  5181. +qmail-dk.0: \
  5182. +qmail-dk.8
  5183. + nroff -man qmail-dk.8 > qmail-dk.0
  5184. +
  5185. +qmail-dk.o: \
  5186. +compile qmail-dk.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
  5187. +qmail.h alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
  5188. +env.h wait.h fd.h fork.h str.h \
  5189. +auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
  5190. + ./compile qmail-dk.c
  5191. +
  5192. +qmail-dkim: \
  5193. +load qmail-dkim.o triggerpull.o fmtqfn.o now.o date822fmt.o \
  5194. +subgetopt.o MakeArgs.o dkimdns.o datetime.a seek.a ndelay.a \
  5195. +open.a sig.a alloc.a substdio.a error.a \
  5196. +str.a case.a fs.a auto_qmail.o auto_split.o auto_uids.o fd.a wait.a \
  5197. +/usr/lib/libdomainkeys.a env.a getln.a control.o stralloc.a libdkim.a
  5198. + g++ -o qmail-dkim qmail-dkim.o triggerpull.o fmtqfn.o now.o \
  5199. + subgetopt.o MakeArgs.o date822fmt.o dkimdns.o datetime.a seek.a ndelay.a \
  5200. + open.a sig.a substdio.a error.a fs.a auto_qmail.o \
  5201. + auto_split.o auto_uids.o fd.a wait.a \
  5202. + /usr/lib/libdomainkeys.a -lcrypto -lresolv env.a control.o open.a getln.a \
  5203. + stralloc.a alloc.a substdio.a scan_ulong.o str.a case.a libdkim.a
  5204. +
  5205. +qmail-dkim.o: \
  5206. +compile qmail-dkim.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
  5207. +qmail.h alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
  5208. +sgetopt.h env.h wait.h fd.h fork.h str.h dkim.h \
  5209. +auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
  5210. + ./compile qmail-dkim.c
  5211. qmail-forward: \
  5212. load qmail-forward.o qmail.o control.o now.o env.a fd.a wait.a open.a getln.a \
  5213. @@ -1506,6 +1549,20 @@
  5214. | sed s}SPAWN}"`head -1 conf-spawn`"}g \
  5215. > qmail-getpw.8
  5216. +qmail-dkim.0: qmail-dkim.8
  5217. + nroff -man qmail-dkim.8 > qmail-dkim.0
  5218. +qmail-dkim.8: qmail-dkim.9
  5219. + cat qmail-dkim.9 \
  5220. + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
  5221. + > qmail-dkim.8
  5222. +
  5223. +dk-filter.0: dk-filter.8
  5224. + nroff -man dk-filter.8 > dk-filter.0
  5225. +dk-filter.8: dk-filter.9
  5226. + cat dk-filter.9 \
  5227. + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
  5228. + > dk-filter.8
  5229. +
  5230. qmail-getpw.o: \
  5231. compile qmail-getpw.c readwrite.h substdio.h subfd.h substdio.h \
  5232. error.h exit.h byte.h str.h case.h fmt.h auto_usera.h auto_break.h \
  5233. @@ -1971,11 +2028,11 @@
  5234. qmail-rspawn: \
  5235. load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \
  5236. seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \
  5237. -auto_qmail.o auto_uids.o auto_spawn.o
  5238. +auto_qmail.o auto_uids.o auto_spawn.o envread.o str_diffn.o
  5239. ./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \
  5240. sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \
  5241. substdio.a error.a str.a auto_qmail.o auto_uids.o \
  5242. - auto_spawn.o
  5243. + auto_spawn.o envread.o str_diffn.o
  5244. qmail-rspawn.0: \
  5245. qmail-rspawn.8
  5246. @@ -2501,11 +2558,11 @@
  5247. ./compile splogger.c
  5248. str.a: \
  5249. -makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \
  5250. +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_cpyb.o str_chr.o \
  5251. str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \
  5252. byte_cr.o byte_zero.o byte_repl.o
  5253. ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \
  5254. - str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \
  5255. + str_cpyb.o str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \
  5256. byte_diff.o byte_copy.o byte_cr.o byte_zero.o byte_repl.o
  5257. str_chr.o: \
  5258. @@ -2516,6 +2573,10 @@
  5259. compile str_cpy.c str.h
  5260. ./compile str_cpy.c
  5261. +str_cpyb.o: \
  5262. +compile str_cpyb.c str.h
  5263. + ./compile str_cpyb.c
  5264. +
  5265. str_diff.o: \
  5266. compile str_diff.c str.h
  5267. ./compile str_diff.c
  5268. @@ -2729,6 +2790,62 @@
  5269. compile wait_pid.c error.h haswaitp.h
  5270. ./compile wait_pid.c
  5271. +MakeArgs.o: compile MakeArgs.c alloc.h str.h alloc.h stralloc.h
  5272. + ./compile MakeArgs.c
  5273. +
  5274. +spawn-filter: \
  5275. +load spawn-filter.o \
  5276. +fmt_ulong.o scan_ulong.o control.o open_read.o wildmat.o qregex.o MakeArgs.o \
  5277. +case_lowerb.o constmap.o byte_chr.o byte_cr.o case_diffb.o \
  5278. +error.a env.a stralloc.a wait.a strerr.a str.a getln.a substdio.a alloc.a
  5279. + ./load spawn-filter \
  5280. + fmt_ulong.o scan_ulong.o control.o open_read.o wildmat.o qregex.o MakeArgs.o \
  5281. + case_lowerb.o constmap.o byte_chr.o byte_cr.o case_diffb.o \
  5282. + error.a env.a stralloc.a wait.a strerr.a str.a getln.a substdio.a alloc.a
  5283. +
  5284. +spawn-filter.o: \
  5285. +compile spawn-filter.c fmt.h str.h strerr.h env.h substdio.h stralloc.h error.h \
  5286. +wait.h qregex.h
  5287. + ./compile spawn-filter.c
  5288. +
  5289. +qregex.o: \
  5290. +compile qregex.c case.h stralloc.h constmap.h substdio.h byte.h env.h
  5291. + ./compile qregex.c
  5292. +
  5293. +wildmat.o: \
  5294. +compile wildmat.c
  5295. + ./compile wildmat.c
  5296. +
  5297. +spawn-filter.0: \
  5298. +spawn-filter.8
  5299. + nroff -man spawn-filter.8 > spawn-filter.0
  5300. +
  5301. +spawn-filter.8: \
  5302. +spawn-filter.9
  5303. + cat spawn-filter.9 \
  5304. + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
  5305. + > spawn-filter.8
  5306. +
  5307. +dk-filter: \
  5308. +warn-auto.sh dk-filter.sh conf-qmail
  5309. + cat warn-auto.sh dk-filter.sh \
  5310. + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
  5311. + > dk-filter
  5312. +
  5313. +DKIMHDRS = dkim.h dkimdns.h dkimbase.h dkimsign.h dkimverify.h
  5314. +DKIMSRCS = dkimfuncs.cpp dkimbase.cpp dkimsign.cpp dkimverify.cpp
  5315. +DKIMOBJS = $(DKIMSRCS:.cpp=.o)
  5316. +dkimtest : libdkim.a dkimtest.o dkimdns.o
  5317. + g++ -g -o dkimtest $(LFLAGS) -L. dkimtest.o dkimdns.o libdkim.a -lcrypto -lresolv
  5318. +
  5319. +dkimtest.o: dkimtest.c $(DKIMHDRS)
  5320. + g++ -I. -c dkimtest.c
  5321. +libdkim.a: $(DKIMOBJS) makelib
  5322. + rm -f libdkim.a
  5323. + ./makelib libdkim.a $(DKIMOBJS)
  5324. +.cpp.o:
  5325. + g++ -I. -g $(CFLAGS) $(INCL) -c $<
  5326. +
  5327. xtext.o: \
  5328. compile xtext.c xtext.h stralloc.h
  5329. ./compile xtext.c
  5330. --- qmail-1.03.orig/qmail.c 2009-10-15 20:38:23.998352000 +0300
  5331. +++ qmail-1.03/qmail.c 2009-10-16 00:18:36.984355926 +0300
  5332. @@ -32,6 +32,7 @@
  5333. {
  5334. int pim[2];
  5335. int pie[2];
  5336. + int pic[2];
  5337. #ifdef ALTQUEUE
  5338. setup_qqargs();
  5339. @@ -39,17 +40,21 @@
  5340. if (pipe(pim) == -1) return -1;
  5341. if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
  5342. -
  5343. + if (pipe(pic) == -1) { close(pim[0]); close(pim[1]); close(pie[0]); close(pie[1]); return -1; }
  5344. +
  5345. switch(qq->pid = vfork()) {
  5346. case -1:
  5347. close(pim[0]); close(pim[1]);
  5348. close(pie[0]); close(pie[1]);
  5349. + close(pic[0]); close(pic[1]);
  5350. return -1;
  5351. case 0:
  5352. close(pim[1]);
  5353. close(pie[1]);
  5354. + close(pic[0]); /*- we want to receive data */
  5355. if (fd_move(0,pim[0]) == -1) _exit(120);
  5356. if (fd_move(1,pie[0]) == -1) _exit(120);
  5357. + if (fd_move(CUSTOM_ERR_FD,pic[1]) == -1) _exit(120);
  5358. if (chdir(auto_qmail) == -1) _exit(61);
  5359. execv(*binqqargs,binqqargs);
  5360. _exit(120);
  5361. @@ -57,6 +62,7 @@
  5362. qq->fdm = pim[1]; close(pim[0]);
  5363. qq->fde = pie[1]; close(pie[0]);
  5364. + qq->fdc = pic[0]; close(pic[1]);
  5365. substdio_fdbuf(&qq->ss,subwrite,qq->fdm,qq->buf,sizeof(qq->buf));
  5366. qq->flagerr = 0;
  5367. return 0;
  5368. @@ -141,10 +147,19 @@
  5369. {
  5370. int wstat;
  5371. int exitcode;
  5372. + int len = 0;
  5373. + char ch;
  5374. + static char errstr[256];
  5375. qmail_put(qq,"",1);
  5376. if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
  5377. close(qq->fde);
  5378. + substdio_fdbuf(&qq->ss, read, qq->fdc, qq->buf, sizeof(qq->buf));
  5379. + while (substdio_bget(&qq->ss, &ch, 1) && len < 255)
  5380. + errstr[len] = ch; len++;
  5381. + if (len > 0)
  5382. + errstr[len] = 0; /* add str-term */
  5383. + close(qq->fdc);
  5384. if ((unsigned long)wait_pid(&wstat,qq->pid) != qq->pid)
  5385. return "Zqq waitpid surprise (#4.3.0)";
  5386. @@ -156,6 +171,7 @@
  5387. case 115: /* compatibility */
  5388. case 11: return "Denvelope address too long for qq (#5.1.3)";
  5389. case 31: return "Dmail server permanently rejected message (#5.3.0)";
  5390. + case 32: return "DPrivate key file does not exist (#5.3.5)";
  5391. case 51: return "Zqq out of memory (#4.3.0)";
  5392. case 52: return "Zqq timeout (#4.3.0)";
  5393. case 53: return "Zqq write error or disk full (#4.3.0)";
  5394. @@ -175,6 +191,9 @@
  5395. case 74: return "Zcommunication with mail server failed (#4.4.2)";
  5396. case 91: /* fall through */
  5397. case 81: return "Zqq internal bug (#4.3.0)";
  5398. + case 88: /*- custom error */
  5399. + if (len > 2)
  5400. + return errstr;
  5401. case 120: return "Zunable to exec qq (#4.3.0)";
  5402. default:
  5403. if ((exitcode >= 11) && (exitcode <= 40))
  5404. diff -Naur qmail-1.03.org/qmail-dk.8 qmail-1.03/qmail-dk.8
  5405. --- qmail-1.03.org/qmail-dk.8 1970-01-01 05:30:00.000000000 +0530
  5406. +++ qmail-1.03/qmail-dk.8 2009-04-21 11:19:07.000000000 +0530
  5407. @@ -0,0 +1,141 @@
  5408. +.TH qmail-dk 8
  5409. +.SH NAME
  5410. +qmail-dk \- sign/verify and queue a mail message for delivery
  5411. +.SH SYNOPSIS
  5412. +.B qmail-dk
  5413. +.SH DESCRIPTION
  5414. +.B qmail-dk
  5415. +has the same interface as
  5416. +.B qmail-queue
  5417. +except that it inserts an appropriate DomainKeys header before it
  5418. +queues the message. To invoke
  5419. +.BR qmail-dk ,
  5420. +set QMAILQUEUE to point to qmail-dk in the environment when
  5421. +you send or receive email. qmail-dk will call
  5422. +.BR qmail-queue .
  5423. +To invoke an executable other than
  5424. +.B qmail-queue
  5425. +set DKQUEUE=bin/qmail-queue for example.
  5426. +
  5427. +.B qmail-dk
  5428. +supports DomainKey signing and verification. It uses the libdomainkey
  5429. +and OpenSSL libraries. To sign a message, set the
  5430. +.B DKSIGN
  5431. +environment variable to the pathname to the private key that will be
  5432. +used to sign the message. If there is a % character in the environment
  5433. +variable, it is removed and replaced by the domain name in the From: header.
  5434. +If, after substituting the %, that file does not exist, the message will not be signed.
  5435. +If there is no % and the file does not exist, the message will be rejected with error 32.
  5436. +The selector will be taken from the
  5437. +basename of the file. The private key should be created by
  5438. +.BR dknewkey ,
  5439. +which comes with libdomainkey.
  5440. +
  5441. +To verify a message, set the
  5442. +.B DKVERIFY
  5443. +environment variable to a desired set of letters. Precisely, if you
  5444. +want a libdomainkey return status to generate an error, include that
  5445. +letter, where A is the first return status (DK_STAT_OK), B is the
  5446. +second (DK_STAT_BADSIG), etc. The letter should be uppercase if you
  5447. +want a permanent error to be returned (exit code 13), and lowercase if
  5448. +you want a temporary error to be returned (exit code 84).
  5449. +The complete set of letters with the corresponding return status is given below
  5450. +
  5451. + A - DK_STAT_OK - Function completed successfully
  5452. + B - DK_STAT_BADSIG - Signature was available but failed to verify against
  5453. + domain specified key
  5454. + C - DK_STAT_NOSIG - No signature available in message
  5455. + D - DK_STAT_NOKEY - No public key available (permanent failure)
  5456. + E - DK_STAT_BADKEY - Unusable key, public if verifying, private if signing
  5457. + F - DK_STAT_CANTVRFY - Cannot get domain key to verify signature
  5458. + (temporary failure)
  5459. + G - DK_STAT_SYNTAX - Message is not valid syntax. Signature could not be
  5460. + created/checked
  5461. + H - DK_STAT_NORESOURCE - Could not get critical resource (temporary failure)
  5462. + I - DK_STAT_ARGS - Arguments are not usable.
  5463. + J - DK_STAT_REVOKED - Key has been revoked.
  5464. + K - DK_STAT_INTERNAL - cannot call this routine in this context. Internal error.
  5465. + L - DK_STAT_GRANULARITY - Granularity mismatch: sender doesn't match g= option.
  5466. +
  5467. +For example, if you want to permanently reject messages that have a
  5468. +signature that has been revoked, include the letter 'K' in the
  5469. +.B DKVERIFY
  5470. +environment variable. A conservative set of letters is
  5471. +.BR DEGIJKfh .
  5472. +Reject permanently BADSIG, NOKEY, BADKEY, SYNTAX, ARGS, REVOKED, and
  5473. +INTERNAL errors, and temporarily CANTVRFY and NORESOURCE. Add in
  5474. +.B B
  5475. +if you want to reject messages that have a signature that doesn't
  5476. +verify (presumably because the message is a forgery or has been
  5477. +damaged in transit. Note that
  5478. +.B qmail-dk
  5479. +always inserts the
  5480. +.B DomainKey-Status
  5481. +header, so that messages can be
  5482. +rejected at delivery time, or in the mail reader.
  5483. +
  5484. +Typically, you would sign messages generated on-host by setting
  5485. +.B DKSIGN
  5486. +in the environment before running an email program. DKSIGN will be carried
  5487. +through qmail's sendmail emulation through
  5488. +.B qmail-inject
  5489. +to
  5490. +.BR qmail-dk .
  5491. +You would also set it for
  5492. +.B qmail-smtpd
  5493. +at the same time
  5494. +.B RELAYCLIENT
  5495. +is set, most often in the tcpserver cdb file. If a host is authorized
  5496. +to relay, you probably want to sign messages sent by that host.
  5497. +.B DKVERIFY
  5498. +should be set for all other hosts.
  5499. +
  5500. +If neither
  5501. +.B DKSIGN
  5502. +nor
  5503. +.B DKVERIFY
  5504. +are set, then
  5505. +.B DKSIGN
  5506. +will be set to /var/qmail/control/domainkeys/%/default. If such a private key exists, it will be used to sign the domain.
  5507. +
  5508. +By default
  5509. +.B qmail-dk
  5510. +will use all of the headers when signing a message.
  5511. +The environment variable
  5512. +.B DKEXCLUDEHEADERS
  5513. +may be set to a colon-separated list of headers that are to be excluded from signing.
  5514. +
  5515. +.B qmail-dk
  5516. +will ordinarily spawn
  5517. +.BR qmail-queue ,
  5518. +but if DKQUEUE is set in the environment,
  5519. +the program that it points to will be executed instead.
  5520. +
  5521. +.SH "EXIT CODES"
  5522. +.B qmail-dk
  5523. +returns the same exit codes as qmail-queue with these additions:
  5524. +.TP 5
  5525. +.B 35
  5526. +The private key file does not exist.
  5527. +.TP 5
  5528. +.B 57
  5529. +Trouble waiting for qmail-queue to exit.
  5530. +.TP 5
  5531. +.B 58
  5532. +Unable to vfork.
  5533. +.TP 5
  5534. +.B 59
  5535. +Unable to create a pipe to qmail-queue.
  5536. +.SH "SEE ALSO"
  5537. +addresses(5),
  5538. +envelopes(5),
  5539. +qmail-header(5),
  5540. +dknewkey(8),
  5541. +dktest(8),
  5542. +qmail-inject(8),
  5543. +qmail-qmqpc(8),
  5544. +qmail-queue(8),
  5545. +qmail-send(8),
  5546. +qmail-smtpd(8),
  5547. +domain-keys(5)
  5548. +
  5549. diff -Naur qmail-1.03.org/qmail-dk.c qmail-1.03/qmail-dk.c
  5550. --- qmail-1.03.org/qmail-dk.c 1970-01-01 05:30:00.000000000 +0530
  5551. +++ qmail-1.03/qmail-dk.c 2009-04-21 19:58:19.000000000 +0530
  5552. @@ -0,0 +1,772 @@
  5553. +/*
  5554. + * $Log: qmail-dk.c,v $
  5555. + * Revision 1.26 2009-04-21 09:05:14+05:30 Cprogrammer
  5556. + * return relevant error message for reading private key
  5557. + *
  5558. + * Revision 1.25 2009-04-21 08:56:03+05:30 Cprogrammer
  5559. + * return temp errors for temporary failures
  5560. + *
  5561. + * Revision 1.24 2009-04-21 08:15:39+05:30 Cprogrammer
  5562. + * moved stralloc variable outside block
  5563. + *
  5564. + * Revision 1.23 2009-04-20 22:20:40+05:30 Cprogrammer
  5565. + * added DKSIGNOPTIONS
  5566. + *
  5567. + * Revision 1.22 2009-04-07 11:38:02+05:30 Cprogrammer
  5568. + * use TMPDIR env variable for tmp directory
  5569. + *
  5570. + * Revision 1.21 2009-04-05 12:52:10+05:30 Cprogrammer
  5571. + * added preprocessor warning
  5572. + *
  5573. + * Revision 1.20 2009-03-31 08:21:12+05:30 Cprogrammer
  5574. + * set dksign when RELAYCLIENT is defined when both dksign, dkverify are undefined
  5575. + *
  5576. + * Revision 1.19 2009-03-28 22:26:35+05:30 Cprogrammer
  5577. + * use DKSIGN,DKVERIFY env variables if RELAYCLIENT is not set
  5578. + *
  5579. + * Revision 1.18 2009-03-28 22:02:32+05:30 Cprogrammer
  5580. + * removed extra white space
  5581. + *
  5582. + * Revision 1.17 2009-03-28 11:34:51+05:30 Cprogrammer
  5583. + * BUG fix. corrected setting of dksign, dkverify variables
  5584. + *
  5585. + * Revision 1.16 2009-03-22 16:58:13+05:30 Cprogrammer
  5586. + * report custom errors to qmail-queue through custom error interface
  5587. + *
  5588. + * Revision 1.15 2009-03-21 15:15:56+05:30 Cprogrammer
  5589. + * improved logic
  5590. + *
  5591. + * Revision 1.14 2009-03-20 22:35:24+05:30 Cprogrammer
  5592. + * fix for multi-line headers
  5593. + *
  5594. + * Revision 1.13 2009-03-19 08:28:12+05:30 Cprogrammer
  5595. + * added EXCLUDEHEADERS
  5596. + *
  5597. + * Revision 1.12 2009-03-14 17:11:32+05:30 Cprogrammer
  5598. + * added DK_STAT_GRANULARITY
  5599. + *
  5600. + * Revision 1.11 2009-03-14 08:52:54+05:30 Cprogrammer
  5601. + * look for domainkey in control/domainkeys
  5602. + *
  5603. + * Revision 1.10 2005-08-23 17:33:37+05:30 Cprogrammer
  5604. + * gcc 4 compliance
  5605. + *
  5606. + * Revision 1.9 2005-04-01 21:42:04+05:30 Cprogrammer
  5607. + * added DK_STAT_SYNTAX
  5608. + * changed error codes
  5609. + *
  5610. + * Revision 1.8 2004-11-02 09:15:53+05:30 Cprogrammer
  5611. + * commented out writing of Comments: header
  5612. + *
  5613. + * Revision 1.7 2004-10-24 21:32:00+05:30 Cprogrammer
  5614. + * removed unecessary header files
  5615. + *
  5616. + * Revision 1.6 2004-10-22 20:28:18+05:30 Cprogrammer
  5617. + * added RCS id
  5618. + *
  5619. + * Revision 1.5 2004-10-22 15:36:45+05:30 Cprogrammer
  5620. + * removed readwrite.h
  5621. + *
  5622. + * Revision 1.4 2004-10-22 14:44:26+05:30 Cprogrammer
  5623. + * use control_readnativefile to avoid skipping signure with '#' char
  5624. + *
  5625. + * Revision 1.3 2004-10-20 20:08:53+05:30 Cprogrammer
  5626. + * libdomainkeys-0.62
  5627. + *
  5628. + * Revision 1.2 2004-09-23 22:55:32+05:30 Cprogrammer
  5629. + * removed uneccessary header files
  5630. + *
  5631. + * Revision 1.1 2004-08-28 01:02:16+05:30 Cprogrammer
  5632. + * Initial revision
  5633. + *
  5634. + */
  5635. +#include <unistd.h>
  5636. +#include <stdlib.h>
  5637. +#include <sys/types.h>
  5638. +#include <sys/stat.h>
  5639. +#include "sgetopt.h"
  5640. +#include "substdio.h"
  5641. +#include "open.h"
  5642. +#include "qmail.h"
  5643. +#include "sig.h"
  5644. +#include "fmt.h"
  5645. +#include "fd.h"
  5646. +#include "alloc.h"
  5647. +#include "str.h"
  5648. +#include "getln.h"
  5649. +#include "case.h"
  5650. +#include "stralloc.h"
  5651. +#include "datetime.h"
  5652. +#include "now.h"
  5653. +#include "wait.h"
  5654. +#include "auto_qmail.h"
  5655. +#include "env.h"
  5656. +#include "scan.h"
  5657. +#include "control.h"
  5658. +#include "domainkeys.h"
  5659. +
  5660. +#define DEATH 86400 /*- 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
  5661. +#define ADDR 1003
  5662. +#define ADVICE_BUF 2048
  5663. +
  5664. +char inbuf[2048];
  5665. +struct substdio ssin;
  5666. +char outbuf[256];
  5667. +struct substdio ssout;
  5668. +struct substdio sserr;
  5669. +char errbuf[256];
  5670. +
  5671. +datetime_sec starttime;
  5672. +struct datetime dt;
  5673. +unsigned long mypid;
  5674. +unsigned long uid;
  5675. +char *pidfn;
  5676. +int messfd;
  5677. +int readfd;
  5678. +
  5679. +char **MakeArgs(char *);
  5680. +void FreeMakeArgs(char **);
  5681. +
  5682. +void
  5683. +die(e)
  5684. + int e;
  5685. +{
  5686. + _exit(e);
  5687. +}
  5688. +
  5689. +void
  5690. +die_write()
  5691. +{
  5692. + die(53);
  5693. +}
  5694. +
  5695. +void
  5696. +die_read()
  5697. +{
  5698. + die(54);
  5699. +}
  5700. +
  5701. +void
  5702. +sigalrm()
  5703. +{
  5704. + /*- thou shalt not clean up here */
  5705. + die(52);
  5706. +}
  5707. +
  5708. +void
  5709. +sigbug()
  5710. +{
  5711. + die(81);
  5712. +}
  5713. +
  5714. +void
  5715. +custom_error(char *flag, char *status, char *code)
  5716. +{
  5717. + char *c;
  5718. +
  5719. + if (substdio_put(&sserr, flag, 1) == -1)
  5720. + die_write();
  5721. + if (substdio_put(&sserr, "qmail-dk: ", 10) == -1)
  5722. + die_write();
  5723. + if (substdio_puts(&sserr, status) == -1)
  5724. + die_write();
  5725. + if (code)
  5726. + {
  5727. + if (substdio_put(&sserr, " (#", 3) == -1)
  5728. + die_write();
  5729. + c = (*flag == 'Z') ? "4" : "5";
  5730. + if (substdio_put(&sserr, c, 1) == -1)
  5731. + die_write();
  5732. + if (substdio_put(&sserr, code + 1, 4) == -1)
  5733. + die_write();
  5734. + if (substdio_put(&sserr, ")", 1) == -1)
  5735. + die_write();
  5736. + }
  5737. + if (substdio_flush(&sserr) == -1)
  5738. + die_write();
  5739. + return;
  5740. +}
  5741. +
  5742. +void
  5743. +maybe_die_dk(e)
  5744. + DK_STAT e;
  5745. +{
  5746. + switch (e)
  5747. + {
  5748. + case DK_STAT_NORESOURCE:
  5749. + _exit(51);
  5750. + case DK_STAT_INTERNAL:
  5751. + _exit(81);
  5752. + case DK_STAT_ARGS:
  5753. + custom_error("Z", "Arguments are not usable. (#4.3.5)", 0);
  5754. + _exit(88);
  5755. + case DK_STAT_SYNTAX:
  5756. + custom_error("Z", "Message is not valid syntax. Signature could not be created/checked (#4.6.0)", 0);
  5757. + _exit(88);
  5758. + case DK_STAT_CANTVRFY:
  5759. + custom_error("Z", "Cannot get domainkeys to verify signature (#5.7.5)", 0);
  5760. + _exit(88);
  5761. + case DK_STAT_BADKEY:
  5762. + if (env_get("DKVERIFY"))
  5763. + custom_error("Z", "Unusable public key for verifying (#5.7.5)", 0);
  5764. + else
  5765. + custom_error("Z", "Unusable private key for signing (#5.7.15", 0);
  5766. + _exit(88);
  5767. + default:
  5768. + return;
  5769. + }
  5770. +}
  5771. +
  5772. +unsigned int
  5773. +pidfmt(s, seq)
  5774. + char *s;
  5775. + unsigned long seq;
  5776. +{
  5777. + unsigned int i;
  5778. + unsigned int len;
  5779. + char *tmpdir;
  5780. +
  5781. + if (!(tmpdir = env_get("TMPDIR")))
  5782. + tmpdir = "/tmp";
  5783. + len = 0;
  5784. + i = fmt_str(s, tmpdir);
  5785. + len += i;
  5786. + if (s)
  5787. + s += i;
  5788. + i = fmt_str(s, "/qmail-dk.");
  5789. + len += i;
  5790. + if (s)
  5791. + s += i;
  5792. + i = fmt_ulong(s, mypid);
  5793. + len += i;
  5794. + if (s)
  5795. + s += i;
  5796. + i = fmt_str(s, ".");
  5797. + len += i;
  5798. + if (s)
  5799. + s += i;
  5800. + i = fmt_ulong(s, starttime);
  5801. + len += i;
  5802. + if (s)
  5803. + s += i;
  5804. + i = fmt_str(s, ".");
  5805. + len += i;
  5806. + if (s)
  5807. + s += i;
  5808. + i = fmt_ulong(s, seq);
  5809. + len += i;
  5810. + if (s)
  5811. + s += i;
  5812. + ++len;
  5813. + if (s)
  5814. + *s++ = 0;
  5815. +
  5816. + return len;
  5817. +}
  5818. +
  5819. +void
  5820. +pidopen()
  5821. +{
  5822. + unsigned int len;
  5823. + unsigned long seq;
  5824. +
  5825. + seq = 1;
  5826. + len = pidfmt((char *) 0, seq);
  5827. + if (!(pidfn = alloc(len)))
  5828. + die(51);
  5829. + for (seq = 1; seq < 10; ++seq)
  5830. + {
  5831. + if (pidfmt((char *) 0, seq) > len)
  5832. + die(81); /*- paranoia */
  5833. + pidfmt(pidfn, seq);
  5834. + if ((messfd = open_excl(pidfn)) != -1)
  5835. + return;
  5836. + }
  5837. + die(63);
  5838. +}
  5839. +
  5840. +char tmp[FMT_ULONG];
  5841. +DK_LIB *dklib;
  5842. +DK *dk;
  5843. +DK_STAT st;
  5844. +char *dksign = 0;
  5845. +char *dkverify = 0;
  5846. +stralloc dkoutput = { 0 }; /*- Domainkey-Signature */
  5847. +stralloc dksignature = { 0 }; /*- content of private signature */
  5848. +stralloc dkopts = { 0 };
  5849. +char *dkqueue = 0;
  5850. +char *dkexcludeheaders;
  5851. +
  5852. +static void
  5853. +write_signature(DK *dk, char *dk_selector, char *keyfn,
  5854. + int advicelen, int opth, char *canon)
  5855. +{
  5856. + unsigned char advice[ADVICE_BUF];
  5857. + char *selector, *from, *tmp;
  5858. + static stralloc keyfnfrom = { 0 };
  5859. + int i;
  5860. +
  5861. + from = dk_from(dk);
  5862. + i = str_chr(keyfn, '%');
  5863. + if (keyfn[i])
  5864. + {
  5865. + if (!stralloc_copyb(&keyfnfrom, keyfn, i))
  5866. + die(51);
  5867. + if (!stralloc_cats(&keyfnfrom, from))
  5868. + die(51);
  5869. + if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
  5870. + die(51);
  5871. + } else
  5872. + if (!stralloc_copys(&keyfnfrom, keyfn))
  5873. + die(51);
  5874. + if (!stralloc_0(&keyfnfrom))
  5875. + die(51);
  5876. + switch (control_readfile(&dksignature, keyfnfrom.s, 0))
  5877. + {
  5878. + case 0: /*- file not present */
  5879. + if (keyfn[i])
  5880. + return;
  5881. + die(32);
  5882. + case 1:
  5883. + break;
  5884. + default:
  5885. + custom_error("Z", "Unable to read private key. (#4.3.0)", 0);
  5886. + _exit(88);
  5887. + }
  5888. + for (i = 0; i < dksignature.len; i++)
  5889. + {
  5890. + if (dksignature.s[i] == '\0')
  5891. + dksignature.s[i] = '\n';
  5892. + }
  5893. + if (!stralloc_0(&dksignature))
  5894. + die(51);
  5895. + st = dk_getsig(dk, dksignature.s, advice, advicelen);
  5896. + maybe_die_dk(st);
  5897. + if (!dk_selector)
  5898. + {
  5899. + selector = keyfn;
  5900. + while (*keyfn)
  5901. + {
  5902. + if (*keyfn == '/')
  5903. + selector = keyfn + 1;
  5904. + keyfn++;
  5905. + }
  5906. + } else
  5907. + selector = dk_selector;
  5908. + if (!stralloc_cats(&dkoutput,
  5909. +#if 0
  5910. + "Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys\n"
  5911. +#endif
  5912. + "DomainKey-Signature: a=rsa-sha1; q=dns; c="))
  5913. + die(51);
  5914. + if (!stralloc_cats(&dkoutput, canon))
  5915. + die(51);
  5916. + if (!stralloc_cats(&dkoutput, ";\n"))
  5917. + die(51);
  5918. + if (!stralloc_cats(&dkoutput, " s="))
  5919. + die(51);
  5920. + if (!stralloc_cats(&dkoutput, selector))
  5921. + die(51);
  5922. + if (!stralloc_cats(&dkoutput, "; d="))
  5923. + die(51);
  5924. + if (from)
  5925. + {
  5926. + if (!stralloc_cats(&dkoutput, from))
  5927. + die(51);
  5928. + } else
  5929. + if (!stralloc_cats(&dkoutput, "unknown"))
  5930. + die(51);
  5931. + if (!stralloc_cats(&dkoutput, ";\n"))
  5932. + die(51);
  5933. + if (!stralloc_cats(&dkoutput, " b="))
  5934. + die(51);
  5935. + if (!stralloc_cats(&dkoutput, (char *) advice))
  5936. + die(51);
  5937. + if (dkexcludeheaders || opth)
  5938. + {
  5939. + if ((i = dk_headers(dk, NULL)) > 0)
  5940. + {
  5941. + if (!(tmp = alloc(i)))
  5942. + die(51);
  5943. + if (!dk_headers(dk, tmp))
  5944. + die(51);
  5945. + if (!stralloc_cats(&dkoutput, ";\n h="))
  5946. + die(51);
  5947. + if (!stralloc_cats(&dkoutput, tmp))
  5948. + die(51);
  5949. + alloc_free(tmp);
  5950. + }
  5951. + }
  5952. + if (!stralloc_cats(&dkoutput, ";\n"))
  5953. + die(51);
  5954. +}
  5955. +
  5956. +int
  5957. +find_header(stralloc *line)
  5958. +{
  5959. + static stralloc headers = { 0 };
  5960. + int n, i, j;
  5961. +
  5962. + for (n = 0; n < line->len; ++n)
  5963. + {
  5964. + if (line->s[n] == ':')
  5965. + break;
  5966. + }
  5967. + if (n == line->len)
  5968. + return -1;
  5969. + if (!headers.len)
  5970. + {
  5971. + if (!stralloc_copys(&headers, ""))
  5972. + die(51);
  5973. + if (dkexcludeheaders)
  5974. + {
  5975. + if (!stralloc_cats(&headers, dkexcludeheaders))
  5976. + die(51);
  5977. + if (!stralloc_append(&headers, ":"))
  5978. + die(51);
  5979. + }
  5980. + }
  5981. + if (!headers.len)
  5982. + return 0;
  5983. + for (i = j = 0; i < headers.len; ++i)
  5984. + {
  5985. + if (headers.s[i] != ':')
  5986. + continue;
  5987. + if (i - j == n && !case_diffb(headers.s + j, n, line->s))
  5988. + return 1;
  5989. + j = i + 1;
  5990. + }
  5991. + return 0;
  5992. +}
  5993. +
  5994. +int
  5995. +dk_setoptions(char **selector, int *advicelen, int *opth, int *optr, int *optc,
  5996. + char **canon, char *signOptions)
  5997. +{
  5998. + char **argv;
  5999. + int ch, argc;
  6000. +
  6001. + *opth = 0;
  6002. + *optr = 0;
  6003. + *optc = DK_CANON_NOFWS;
  6004. + *canon = "nofws";
  6005. + *selector = 0;
  6006. + if (!signOptions)
  6007. + return (0);
  6008. + if (!stralloc_copys(&dkopts, "qmail-dk "))
  6009. + die(51);
  6010. + if (!stralloc_cats(&dkopts, signOptions))
  6011. + die(51);
  6012. + if (!stralloc_0(&dkopts))
  6013. + die(51);
  6014. + if (!(argv = MakeArgs(dkopts.s)))
  6015. + die(51);
  6016. + for (argc = 0;argv[argc];argc++);
  6017. + while ((ch = sgopt(argc, argv, "hrb:c:s:")) != sgoptdone)
  6018. + {
  6019. + switch (ch)
  6020. + {
  6021. + case 'h':
  6022. + *opth = 1;
  6023. + break;
  6024. + case 'r':
  6025. + *optr = 1;
  6026. + *opth = 1;
  6027. + break;
  6028. + case 'b':
  6029. + *advicelen = atoi(optarg);
  6030. + if (*advicelen > ADVICE_BUF);
  6031. + *advicelen = ADVICE_BUF;
  6032. + break;
  6033. + case 'c':
  6034. + if (!str_diffn("simple\0", optarg, 7))
  6035. + {
  6036. + *optc = DK_CANON_SIMPLE;
  6037. + *canon = "simple";
  6038. + }
  6039. + break;
  6040. + case 's':
  6041. + *selector = optarg;
  6042. + break;
  6043. + default:
  6044. + FreeMakeArgs(argv);
  6045. + return (1);
  6046. + }
  6047. + } /*- while ((ch = sgopt(argc, argv, "hrb:c:s:")) != sgoptdone) */
  6048. + FreeMakeArgs(argv);
  6049. + return (0);
  6050. +}
  6051. +
  6052. +static char *binqqargs[2] = { "bin/qmail-queue", 0 };
  6053. +int
  6054. +main(int argc, char *argv[])
  6055. +{
  6056. + int errfd, pim[2];
  6057. + int wstat, match, opth = 0, optr = 0, optc = DK_CANON_NOFWS,
  6058. + advicelen = ADVICE_BUF;
  6059. + char *x, *relayclient, *canon = "nofws", *selector = 0;
  6060. + stralloc line = {0};
  6061. + unsigned long pid;
  6062. +
  6063. + sig_blocknone();
  6064. + umask(033);
  6065. + if (chdir(auto_qmail) == -1)
  6066. + die(61);
  6067. + if (!dksign)
  6068. + dksign = env_get("DKSIGN");
  6069. + if (!dkverify)
  6070. + dkverify = env_get("DKVERIFY");
  6071. + if (!dksign && !dkverify && (relayclient = env_get("RELAYCLIENT")))
  6072. + dksign = "control/domainkeys/%/default";
  6073. + dkqueue = env_get("DKQUEUE");
  6074. + if (dkqueue && *dkqueue)
  6075. + binqqargs[0] = dkqueue;
  6076. + if (dksign || dkverify)
  6077. + {
  6078. + if (!(dklib = dk_init(&st)))
  6079. + {
  6080. + maybe_die_dk(st);
  6081. + custom_error("Z", "dk initialization failed (#4.3.0)", 0);
  6082. + _exit(88);
  6083. + }
  6084. + }
  6085. + /*- Initialization */
  6086. + if (dksign)
  6087. + {
  6088. + if (dk_setoptions(&selector, &advicelen, &opth, &optr, &optc, &canon, env_get("DKSIGNOPTIONS")))
  6089. + {
  6090. + custom_error("Z", "Invalid DKSIGNOPTIONS (#4.3.0)", 0);
  6091. + _exit(88);
  6092. + }
  6093. + if (!(dk = dk_sign(dklib, &st, optc)))
  6094. + {
  6095. + maybe_die_dk(st);
  6096. + custom_error("Z", "dk_sign failed (#4.3.0)", 0);
  6097. + _exit(88);
  6098. + }
  6099. + if (optr && dk_setopts(dk, DKOPT_RDUPE) != DK_STAT_OK)
  6100. + {
  6101. + custom_error("Z", "DKOPT_RDUPE failed (#4.3.0)", 0);
  6102. + _exit(88);
  6103. + }
  6104. + } else
  6105. + if (dkverify)
  6106. + {
  6107. + if (!(dk = dk_verify(dklib, &st)))
  6108. + {
  6109. + maybe_die_dk(st);
  6110. + custom_error("Z", "dk_verify failed (#4.3.0)", 0);
  6111. + _exit(88);
  6112. + }
  6113. + }
  6114. + mypid = getpid();
  6115. + uid = getuid();
  6116. + starttime = now();
  6117. + datetime_tai(&dt, starttime);
  6118. + sig_pipeignore();
  6119. + sig_miscignore();
  6120. + sig_alarmcatch(sigalrm);
  6121. + sig_bugcatch(sigbug);
  6122. + alarm(DEATH);
  6123. + pidopen();
  6124. + if ((readfd = open_read(pidfn)) == -1)
  6125. + die(63);
  6126. + if (unlink(pidfn) == -1)
  6127. + die(63);
  6128. + substdio_fdbuf(&ssout, write, messfd, outbuf, sizeof(outbuf));
  6129. + substdio_fdbuf(&ssin, read, 0, inbuf, sizeof(inbuf));
  6130. + if (!(x = env_get("ERROR_FD")))
  6131. + errfd = CUSTOM_ERR_FD;
  6132. + else
  6133. + scan_int(x, &errfd);
  6134. + substdio_fdbuf(&sserr, write, errfd, errbuf, sizeof(errbuf));
  6135. + dkexcludeheaders = env_get("DKEXCLUDEHEADERS");
  6136. + if (dkexcludeheaders)
  6137. + {
  6138. + int hdr_continue, in_header = 1;
  6139. +
  6140. + hdr_continue = 0;
  6141. + for (;;)
  6142. + {
  6143. +
  6144. + if (getln(&ssin, &line, &match, '\n') == -1)
  6145. + die_read();
  6146. + if (!match && line.len == 0)
  6147. + break;
  6148. + if (substdio_put(&ssout, line.s, line.len) == -1)
  6149. + die_write();
  6150. + if (!dksign && !dkverify)
  6151. + continue;
  6152. + if (in_header)
  6153. + {
  6154. + if (line.s[0] == ' ' || line.s[0] == '\t')
  6155. + {
  6156. + if (hdr_continue)
  6157. + continue;
  6158. + } else
  6159. + if (find_header(&line) == 1) {
  6160. + hdr_continue = 1;
  6161. + continue;
  6162. + } else
  6163. + hdr_continue = 0;
  6164. + }
  6165. + if (match)
  6166. + {
  6167. + st = dk_message(dk, (unsigned char *) line.s, line.len - 1);
  6168. + maybe_die_dk(st);
  6169. + st = dk_message(dk, (unsigned char *) "\r\n", 2);
  6170. + } else
  6171. + st = dk_message(dk, (unsigned char *) line.s, line.len);
  6172. + maybe_die_dk(st);
  6173. + }
  6174. + } else
  6175. + for (;;)
  6176. + {
  6177. + register int n;
  6178. + register char *x;
  6179. + int i;
  6180. +
  6181. + if ((n = substdio_feed(&ssin)) < 0)
  6182. + die_read();
  6183. + if (!n)
  6184. + break;
  6185. + x = substdio_PEEK(&ssin);
  6186. + if (dksign || dkverify)
  6187. + {
  6188. + for (i = 0; i < n; i++)
  6189. + {
  6190. + if (x[i] == '\n')
  6191. + st = dk_message(dk, (unsigned char *) "\r\n", 2);
  6192. + else
  6193. + st = dk_message(dk, (unsigned char *) x + i, 1);
  6194. + maybe_die_dk(st);
  6195. + }
  6196. + }
  6197. + if (substdio_put(&ssout, x, n) == -1)
  6198. + die_write();
  6199. + substdio_SEEK(&ssin, n);
  6200. + }
  6201. + if (substdio_flush(&ssout) == -1)
  6202. + die_write();
  6203. + if (dksign || dkverify)
  6204. + {
  6205. + st = dk_eom(dk, (void *) 0);
  6206. + maybe_die_dk(st);
  6207. + if (dksign)
  6208. + write_signature(dk, selector, dksign, advicelen, opth, canon);
  6209. + else
  6210. + if (dkverify)
  6211. + {
  6212. + char *status = 0, *code = 0;
  6213. +
  6214. + if (!stralloc_copys(&dkoutput, "DomainKey-Status: "))
  6215. + die(51);
  6216. + switch (st)
  6217. + {
  6218. + case DK_STAT_OK:
  6219. + status = "good ";
  6220. + break;
  6221. + case DK_STAT_BADSIG:
  6222. + status = "bad ";
  6223. + code = "X.7.5";
  6224. + break;
  6225. + case DK_STAT_NOSIG:
  6226. + status = "no signature";
  6227. + code = "X.7.5";
  6228. + break;
  6229. + case DK_STAT_NOKEY:
  6230. + case DK_STAT_CANTVRFY:
  6231. + status = "no key ";
  6232. + code = "X.7.0";
  6233. + break;
  6234. + case DK_STAT_BADKEY:
  6235. + status = "bad key ";
  6236. + code = "X.7.5";
  6237. + break;
  6238. + case DK_STAT_INTERNAL:
  6239. + status = "bad format ";
  6240. + code = "X.3.0";
  6241. + break;
  6242. + case DK_STAT_ARGS:
  6243. + status = "bad format ";
  6244. + code = "X.3.5";
  6245. + break;
  6246. + case DK_STAT_SYNTAX:
  6247. + status = "bad format ";
  6248. + code = "X.6.0";
  6249. + break;
  6250. + case DK_STAT_NORESOURCE:
  6251. + status = "no resources";
  6252. + code = "X.3.0";
  6253. + break;
  6254. + case DK_STAT_REVOKED:
  6255. + status = "revoked ";
  6256. + code = "X.7.5";
  6257. + break;
  6258. + case DK_STAT_GRANULARITY:
  6259. + status = "bad sender ";
  6260. + code = "X.7.5";
  6261. + break;
  6262. + }
  6263. + if (!stralloc_cats(&dkoutput, status))
  6264. + die(51);
  6265. + if (!stralloc_cats(&dkoutput, "\n"))
  6266. + die(51);
  6267. + if (dkverify[str_chr(dkverify, 'A' + st)])
  6268. + {
  6269. + custom_error("D", status, code); /*- return permanent error */
  6270. + die(88);
  6271. + }
  6272. + if (dkverify[str_chr(dkverify, 'a' + st)])
  6273. + {
  6274. + custom_error("Z", status, code); /*- return temporary error */
  6275. + die(88);
  6276. + }
  6277. + }
  6278. + }
  6279. + if (pipe(pim) == -1)
  6280. + die(59);
  6281. + switch (pid = vfork())
  6282. + {
  6283. + case -1:
  6284. + close(pim[0]);
  6285. + close(pim[1]);
  6286. + die(58);
  6287. + case 0:
  6288. + close(pim[1]);
  6289. + if (fd_move(0, pim[0]) == -1)
  6290. + die(120);
  6291. + execv(*binqqargs, binqqargs);
  6292. + die(120);
  6293. + }
  6294. + close(pim[0]);
  6295. + substdio_fdbuf(&ssin, read, readfd, inbuf, sizeof(inbuf));
  6296. + substdio_fdbuf(&ssout, write, pim[1], outbuf, sizeof(outbuf));
  6297. + if (substdio_bput(&ssout, dkoutput.s, dkoutput.len) == -1) /*- write DK signature */
  6298. + die_write();
  6299. + switch (substdio_copy(&ssout, &ssin))
  6300. + {
  6301. + case -2:
  6302. + die_read();
  6303. + case -3:
  6304. + die_write();
  6305. + }
  6306. + if (substdio_flush(&ssout) == -1)
  6307. + die_write();
  6308. + close(pim[1]);
  6309. + if (wait_pid(&wstat, pid) != pid)
  6310. + die(57);
  6311. + if (wait_crashed(wstat))
  6312. + die(57);
  6313. + die(wait_exitcode(wstat));
  6314. + /*- Not Reached */
  6315. + exit(0);
  6316. +}
  6317. +
  6318. +void
  6319. +getversion_qmail_dk_c()
  6320. +{
  6321. + static char *x = "$Id: qmail-dk.c,v 1.26 2009-04-21 09:05:14+05:30 Cprogrammer Exp mbhangui $";
  6322. +
  6323. + x++;
  6324. +}
  6325. diff -Naur qmail-1.03.org/qmail-dkim.9 qmail-1.03/qmail-dkim.9
  6326. --- qmail-1.03.org/qmail-dkim.9 1970-01-01 05:30:00.000000000 +0530
  6327. +++ qmail-1.03/qmail-dkim.9 2009-04-21 11:19:07.000000000 +0530
  6328. @@ -0,0 +1,303 @@
  6329. +.TH qmail-dk 8
  6330. +.SH NAME
  6331. +qmail-dkim \- sign/verify using DKIM (SSP/ADSP optionally) and queue a mail message for delivery
  6332. +.SH SYNOPSIS
  6333. +.B qmail-dkim
  6334. +.SH DESCRIPTION
  6335. +.B qmail-dkim
  6336. +has the same interface as
  6337. +.B qmail-queue
  6338. +except that it inserts an appropriate DKIM header (rfc4871) before it
  6339. +queues the message. To invoke
  6340. +.BR qmail-dkim ,
  6341. +set QMAILQUEUE to point to qmail-dkim in the environment when
  6342. +you send or receive email. qmail-dkim will call
  6343. +.BR qmail-queue .
  6344. +To invoke an executable other than
  6345. +.B qmail-queue
  6346. +set DKIMQUEUE=bin/qmail-dk for example.
  6347. +
  6348. +.B qmail-dkim
  6349. +supports DKIM signing and verification and can optionally use
  6350. +.B Sender Signing Practice (SSP)
  6351. +or
  6352. +.B Author Domain Signing Practice.
  6353. +It uses the libdkim and OpenSSL libraries. To sign a message, set the
  6354. +.B DKIMSIGN
  6355. +environment variable to the pathname of the private key that will be
  6356. +used to sign the message. If there is a % character in the environment
  6357. +variable, it is removed and replaced by the domain name in the From: header.
  6358. +If, after substituting the %, that file does not exist, the message will not be signed.
  6359. +If there is no % and the file does not exist, the message will be rejected with error 32.
  6360. +The selector (s=) will be taken from the
  6361. +basename of the file. The private key should be created by
  6362. +.BR dknewkey(8) .
  6363. +You can set various DKIM options in getopt style, by setting the environment variable
  6364. +.B DKIMSIGNOPTIONS
  6365. +
  6366. + b <standard> 1 - allman, 2 - ietf or 3 - both
  6367. + c <canonicalization> r for relaxed [DEFAULT], s - simple,
  6368. + t relaxed/simple, u - simple/relaxed
  6369. + l include body length tag
  6370. + q include query method tag;
  6371. + t include a timestamp tag
  6372. + h
  6373. + i <identity> the identity, if not provided it will not be included
  6374. + x <expire_time> the expire time in seconds since epoch
  6375. + ( DEFAULT = current time + 604800)
  6376. + if set to - then it will not be included
  6377. + z <hash> 1 for sha1, 2 for sha256, 3 for both
  6378. +
  6379. +.EX
  6380. + DKIMSIGNOPTIONS="-b 1 -c r -q"
  6381. + sets allman standard, with relaxed canonicalization and include query method tag
  6382. +.EE
  6383. +
  6384. +Apart from setting
  6385. +.BR DKIMSIGNOPTIONS ,
  6386. +you can set the identity and the expire time by setting
  6387. +.B DKIMIDENTITY
  6388. +and
  6389. +.B DKIMEXPIRE
  6390. +respectively.
  6391. +.B DKIMIDENTITY
  6392. +takes precedence over -i option specified in
  6393. +.BR DKIMSIGNOPTIONS.
  6394. +Similarly,
  6395. +.B DKIMEXPIRE
  6396. +takes precedence over -x option specifed in
  6397. +.BR DKIMSIGNOPTIONS.
  6398. +.B qmail-dkim
  6399. +uses the domain found in the Sender: header. If not it uses the domain in the From: header. You can override this by
  6400. +setting
  6401. +.B DKIMDOMAIN
  6402. +environment variable.
  6403. +.B DKIMDOMAIN
  6404. +can be set to an email address or a domain (without the at sign).
  6405. +
  6406. +To verify a message, set the
  6407. +.B DKIMVERIFY
  6408. +environment variable to a desired set of letters. Precisely, if you
  6409. +want a libdkim return status to generate an error, include that
  6410. +letter, where A is the first return status (DKIM_SUCCESS), B is the
  6411. +second (DKIM_FINISHED_BODY), etc. The letter should be uppercase if you
  6412. +want a permanent error to be returned (exit code 13), and lowercase if
  6413. +you want a temporary error to be returned (exit code 89).
  6414. +The complete set of letters with the corresponding return status is given below
  6415. +
  6416. + A - DKIM_SUCCESS - Function executed successfully
  6417. + B - DKIM_FINISHED_BODY - process result: no more message
  6418. + body is needed
  6419. + C - DKIM_PARTIAL_SUCCESS - verify result: at least one
  6420. + but not all signatures verified
  6421. + D - DKIM_NEUTRAL - verify result: no signatures
  6422. + verified but message is
  6423. + not suspicious
  6424. + E - DKIM_SUCCESS_BUT_EXTRA - signature result: signature
  6425. + verified but it did not
  6426. + include all of the body
  6427. + F - DKIM_3PS_SIGNATURE - 3rd-party signature
  6428. + G - DKIM_FAIL - Function failed to execute
  6429. + H - DKIM_BAD_SYNTAX - signature error: DKIM-Signature
  6430. + could not parse or has bad
  6431. + tags/values
  6432. + I - DKIM_SIGNATURE_BAD - signature error: RSA verify
  6433. + failed
  6434. + J - DKIM_SIGNATURE_BAD_BUT_TESTING - signature error: RSA verify
  6435. + failed but testing
  6436. + K - DKIM_SIGNATURE_EXPIRED - signature error: x= is old
  6437. + L - DKIM_SELECTOR_INVALID - signature error: selector doesn't
  6438. + parse or contains invalid values
  6439. + M - DKIM_SELECTOR_GRANULARITY_MISMATCH - signature error: selector
  6440. + g= doesn't match i=
  6441. + N - DKIM_SELECTOR_KEY_REVOKED - signature error: selector
  6442. + p= empty
  6443. + O - DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG - signature error: selector domain
  6444. + name too long to request
  6445. + P - DKIM_SELECTOR_DNS_TEMP_FAILURE - signature error: temporary dns
  6446. + failure requesting selector
  6447. + Q - DKIM_SELECTOR_DNS_PERM_FAILURE - signature error: permanent dns
  6448. + failure requesting selector
  6449. + R - DKIM_SELECTOR_PUBLIC_KEY_INVALID - signature error: selector
  6450. + p= value invalid or wrong format
  6451. + S - DKIM_NO_SIGNATURES - process error, no sigs
  6452. + T - DKIM_NO_VALID_SIGNATURES - process error, no valid sigs
  6453. + U - DKIM_BODY_HASH_MISMATCH - sigature verify error: message
  6454. + body does not hash to bh value
  6455. + V - DKIM_SELECTOR_ALGORITHM_MISMATCH - signature error: selector
  6456. + h= doesn't match signature a=
  6457. + W - DKIM_STAT_INCOMPAT - signature error: incompatible v=
  6458. +
  6459. +For example, if you want to permanently reject messages that have a
  6460. +signature that is expired, include the letter 'K' in the
  6461. +.B DKIMVERIFY
  6462. +environment variable. A conservative set of letters is
  6463. +.BR FGHIKLMNOQRTUVWjp .
  6464. +Reject permanently 3PS, FAILURE, SYNTAX, SIGNATURE_BAD, SIGNATURE_EXPIRED, SELECTOR_INVALID,
  6465. +GRANULARITY_MISMATCH, SELECTOR_KEY_REVOKED, DOMAIN_NAME_TOO_LONG, SELECTOR_PUBLIC_KEY_INVALID,
  6466. +NO_VALID_SIGNATURES and BODY_HASH_MISMATCH errors, and temporarily SIGNATURE_BAD_BUT_TESTING and DNS_TEMP_FAILURE .
  6467. +Add in
  6468. +.B S
  6469. +if you want to reject messages that do not have a DKIM signature. You can use the control files
  6470. +signaturedomains and nosignature domains (See Below) to further fine tune the action to be
  6471. +taken when a mail arrives with no DKIM signature. Note that
  6472. +.B qmail-dkim
  6473. +always inserts the
  6474. +.B DKIM-Status
  6475. +header, so that messages can be
  6476. +rejected later at delivery time, or in the mail reader. In that case you may set
  6477. +.B DKIMVERIFY
  6478. +to an empty string.
  6479. +
  6480. +qmail-dkim supports signing practice which can be additonall checked when a signature
  6481. +verifcation fails -
  6482. +
  6483. +.BR "SSP - Sender Signing Practice"
  6484. +
  6485. +and
  6486. +
  6487. +.BR "ADSP - Author Domain Signing Practice" .
  6488. +
  6489. +When a signature fails to verify for a message, you can use SSP/ADSP to determine if the message is suspicious or not.
  6490. +To verify a message against SSP/ADSP, set the
  6491. +.B DKIMPRACTICE
  6492. +environment variable to the desired set of letters allowed for DKIMVERIFY environment variable.
  6493. +SSP/ADSP should be used only when signature verification fails. SSP/ADSP gets invoked only when libdkim returns the
  6494. +error codes (F,G,H,I,J,K,L,M,N,P,Q,R,S,T,U,V,W) for signature verification. In case you want to test
  6495. +against SSP/ADSP only for DKIM_NO_SIGNATURE and DKIM_NO_VALID_SIGNATURE
  6496. +set the environment variable
  6497. +.BR DKIMPRACTICE="ST" .
  6498. +The default is "FGHIJKLMNPQRSTUVW". If you want automatic behaviour, set DKIMADSPERROR to an empty string.
  6499. +.B qmail-dkim
  6500. +uses ADSP as the default signing practice. You can override this by setting the SIGN_PRACTICE to ssp, adsp, local (lowercase).
  6501. +if you set SIGN_PRACTICE to \fIlocal\fB,
  6502. +.B qmail-dkim
  6503. +will check the domain against the control file
  6504. +.I signaturedomains
  6505. +(See Below). If the domain is found listed in
  6506. +.I signaturedomains
  6507. +.B qmail-dkim
  6508. +will bypass ADSP/SSP and return DKIM_FAIL if signature fails to verify. Setting SIGN_PRACTICE
  6509. +to anything else will cause
  6510. +.B qmail-dkim
  6511. +to disable Signing Practice.
  6512. +
  6513. +If ADSP or SSP is checked,
  6514. +.B qmail-dkim
  6515. +will insert the
  6516. +.B X-DKIM-ADSP
  6517. +or
  6518. +.B X-DKIM-SSP
  6519. +header as given below
  6520. +
  6521. + A - DKIM_SUCCESS - Message passes ADSP test
  6522. + B - DKIM_ADSP_UNKNOWN - some messages may be signed
  6523. + C - DKIM_ADSP_ALL - All message are signed with author signature
  6524. + D - DKIM_ADSP_DISCARDABLE - messages which fail verification are Discardable
  6525. + E - DKIM_ADSP_SCOPE - domain is out of scope
  6526. + F - DKIM_ADSP_TEMPFAIL - Temporary Error
  6527. +
  6528. + or
  6529. +
  6530. + A - DKIM_SUCCESS - Message passes ADSP test
  6531. + B - DKIM_SSP_UNKNOWN - some messages may be signed
  6532. + C - DKIM_SSP_ALL - All message are signed with author signature
  6533. + D - DKIM_SSP_STRICT - messages which fail verification are Discardable
  6534. + E - DKIM_SSP_SCOPE - domain is out of scope
  6535. + F - DKIM_SSP_TEMPFAIL - Temporary Error
  6536. +
  6537. +You can have a control file
  6538. +.I signaturedomains
  6539. +containing a list of domains which you know are sure to sign messages using DKIM. If a message comes
  6540. +from a domain listed in
  6541. +.IR signaturedomains ,
  6542. +and the signature fails verification (any of DKIM failure status),
  6543. +.B qmail-dkim
  6544. +will bypass ADSP/SSP checks and return DKIM_FAIL. The name of this control file can be
  6545. +overriden by the environment variable
  6546. +.BR SIGNATUREDOMAINS .
  6547. +
  6548. +You can have a control file
  6549. +.I nosignaturedomains
  6550. +containing a list of domains which you know are sure not to sign messages using DKIM.
  6551. +If a message comes from a domain listed in
  6552. +.IR signaturedomains ,
  6553. +and does not have a DKIM-Signature header,
  6554. +.B qmail-dkim
  6555. +will bypass ADSP/SSP checks and return DKIM_NEUTRAL. The wildcard entry '*' in this file, will
  6556. +result in all mails which do not have a signature to pass DKIM test (unless the domain is listed
  6557. +in the control file
  6558. +.BR signaturedomains ).
  6559. +The name of this control file can be overriden by the environment variable
  6560. +.BR NOSIGNATUREDOMAINS .
  6561. +
  6562. +Typically, you would sign messages generated on-host by setting
  6563. +.B DKIMSIGN
  6564. +in the environment before running an email program. DKIMSIGN will be carried
  6565. +through qmail's sendmail emulation through
  6566. +.B qmail-inject
  6567. +to
  6568. +.BR qmail-dkim .
  6569. +You would also set it for
  6570. +.B qmail-smtpd
  6571. +at the same time
  6572. +.B RELAYCLIENT
  6573. +is set, most often in the tcpserver cdb file. If a host is authorized
  6574. +to relay, you probably want to sign messages sent by that host.
  6575. +.B DKIMVERIFY
  6576. +should be set for all other hosts.
  6577. +
  6578. +If neither
  6579. +.B DKIMSIGN
  6580. +nor
  6581. +.B DKIMVERIFY
  6582. +are set, then
  6583. +.B DKIMSIGN
  6584. +will be set to QMAILHOME/control/domainkeys/private. If such a private key exists, it will be used to sign the domain.
  6585. +
  6586. +By default
  6587. +.B qmail-dkim
  6588. +will use all of the headers when signing a message.
  6589. +
  6590. +.B qmail-dkim
  6591. +will ordinarily spawn
  6592. +.BR qmail-queue ,
  6593. +but if DKIMQUEUE is set in the environment,
  6594. +the program that it points to will be executed instead.
  6595. +
  6596. +.SH "EXIT CODES"
  6597. +.B qmail-dkim
  6598. +returns the same exit codes as qmail-queue with these additions:
  6599. +.TP 5
  6600. +.B 32
  6601. +The private key file does not exist.
  6602. +.TP 5
  6603. +.B 57
  6604. +Trouble waiting for qmail-queue to exit.
  6605. +.TP 5
  6606. +.B 58
  6607. +Unable to vfork.
  6608. +.TP 5
  6609. +.B 59
  6610. +Unable to create a pipe to qmail-queue.
  6611. +.SH "SEE ALSO"
  6612. +addresses(5),
  6613. +envelopes(5),
  6614. +qmail-header(5),
  6615. +dknewkey(8),
  6616. +dktest(8),
  6617. +qmail-inject(8),
  6618. +qmail-qmqpc(8),
  6619. +qmail-queue(8),
  6620. +qmail-send(8),
  6621. +qmail-smtpd(8),
  6622. +qmail-dk(8),
  6623. +domain-keys(5)
  6624. +
  6625. +.SH "AUTHORS"
  6626. +
  6627. +Manvendra Bhangui.
  6628. +.SH PROBLEMS
  6629. +Problems with
  6630. +.B qmail-dkim
  6631. +should be forwarded to "Manvendra Bhangui" <mbhangui@gmail.com>
  6632. diff -Naur qmail-1.03.org/qmail-dkim.c qmail-1.03/qmail-dkim.c
  6633. --- qmail-1.03.org/qmail-dkim.c 1970-01-01 05:30:00.000000000 +0530
  6634. +++ qmail-1.03/qmail-dkim.c 2009-04-21 11:19:07.000000000 +0530
  6635. @@ -0,0 +1,1273 @@
  6636. +/*
  6637. + * $Log: qmail-dkim.c,v $
  6638. + * Revision 1.18 2009-04-16 13:48:32+05:30 Cprogrammer
  6639. + * added dkim_setoptions() to set all DKIM options
  6640. + *
  6641. + * Revision 1.17 2009-04-07 11:36:56+05:30 Cprogrammer
  6642. + * use TMPDIR env variable for tmp directory
  6643. + *
  6644. + * Revision 1.16 2009-04-05 12:52:17+05:30 Cprogrammer
  6645. + * added preprocessor warning
  6646. + *
  6647. + * Revision 1.15 2009-04-04 00:33:44+05:30 Cprogrammer
  6648. + * removed dk_strdup()
  6649. + *
  6650. + * Revision 1.14 2009-03-31 08:21:58+05:30 Cprogrammer
  6651. + * set dkimsign when RELAYCLIENT is defined when both dkimsign and dkimverify are undefined
  6652. + *
  6653. + * Revision 1.13 2009-03-30 22:25:54+05:30 Cprogrammer
  6654. + * made DKIM messages friendlier
  6655. + *
  6656. + * Revision 1.12 2009-03-30 14:47:59+05:30 Cprogrammer
  6657. + * added descriptive text for original dkim error
  6658. + *
  6659. + * Revision 1.11 2009-03-29 19:20:43+05:30 Cprogrammer
  6660. + * added nosignaturedomains
  6661. + *
  6662. + * Revision 1.10 2009-03-28 22:27:02+05:30 Cprogrammer
  6663. + * use DKIMSIGN, DKIMVERIFY if RELAYCLIENT is not set
  6664. + *
  6665. + * Revision 1.9 2009-03-28 22:03:05+05:30 Cprogrammer
  6666. + * fixed DKIM return codes
  6667. + *
  6668. + * Revision 1.8 2009-03-28 13:37:37+05:30 Cprogrammer
  6669. + * call DKIMVerifyGetDetails() always
  6670. + *
  6671. + * Revision 1.7 2009-03-28 11:39:23+05:30 Cprogrammer
  6672. + * set automatic setting of dkimsign, dkimverify variables based on RELAYCLIENT
  6673. + *
  6674. + * Revision 1.6 2009-03-28 11:35:58+05:30 Cprogrammer
  6675. + * added ADSP/SSP
  6676. + *
  6677. + * Revision 1.5 2009-03-22 17:39:38+05:30 Cprogrammer
  6678. + * set identity using basename of signature or environment variable DKIMIDENTITY
  6679. + *
  6680. + * Revision 1.4 2009-03-22 16:58:38+05:30 Cprogrammer
  6681. + * fixed bug with verification
  6682. + * report custom errors to qmail-queue through custom error interface
  6683. + *
  6684. + * Revision 1.3 2009-03-21 12:34:38+05:30 Cprogrammer
  6685. + * use hasdkim.h for conditional compilation of dkim
  6686. + *
  6687. + * Revision 1.2 2009-03-20 22:35:57+05:30 Cprogrammer
  6688. + * set error to DKIM_NO_SIGNATURE when DKIM-Signature is not present
  6689. + *
  6690. + * Revision 1.1 2009-03-18 13:54:49+05:30 Cprogrammer
  6691. + * Initial revision
  6692. + *
  6693. + */
  6694. +#include <unistd.h>
  6695. +#include <stdlib.h>
  6696. +#include <ctype.h>
  6697. +#include <sys/types.h>
  6698. +#include <sys/stat.h>
  6699. +#include "sgetopt.h"
  6700. +#include "substdio.h"
  6701. +#include "open.h"
  6702. +#include "qmail.h"
  6703. +#include "sig.h"
  6704. +#include "case.h"
  6705. +#include "fmt.h"
  6706. +#include "fd.h"
  6707. +#include "alloc.h"
  6708. +#include "str.h"
  6709. +#include "stralloc.h"
  6710. +#include "datetime.h"
  6711. +#include "now.h"
  6712. +#include "wait.h"
  6713. +#include "auto_qmail.h"
  6714. +#include "env.h"
  6715. +#include "control.h"
  6716. +#include "dkim.h"
  6717. +
  6718. +#define DEATH 86400 /*- 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
  6719. +#define ADDR 1003
  6720. +#define HAVE_EVP_SHA256
  6721. +#define strncasecmp(x,y,z) case_diffb((x), (z), (y))
  6722. +#define strcasecmp(x,y) case_diffs((x), (y))
  6723. +
  6724. +char inbuf[2048];
  6725. +char outbuf[256];
  6726. +char errbuf[256];
  6727. +struct substdio ssin;
  6728. +struct substdio ssout;
  6729. +struct substdio sserr;
  6730. +
  6731. +datetime_sec starttime;
  6732. +struct datetime dt;
  6733. +unsigned long mypid;
  6734. +unsigned long uid;
  6735. +char *pidfn;
  6736. +int messfd;
  6737. +int readfd;
  6738. +
  6739. +char **MakeArgs(char *);
  6740. +void FreeMakeArgs(char **);
  6741. +
  6742. +void
  6743. +die(e)
  6744. + int e;
  6745. +{
  6746. + _exit(e);
  6747. +}
  6748. +
  6749. +void
  6750. +die_write()
  6751. +{
  6752. + die(53);
  6753. +}
  6754. +
  6755. +void
  6756. +die_read()
  6757. +{
  6758. + die(54);
  6759. +}
  6760. +
  6761. +void
  6762. +sigalrm()
  6763. +{
  6764. + /*- thou shalt not clean up here */
  6765. + die(52);
  6766. +}
  6767. +
  6768. +void
  6769. +sigbug()
  6770. +{
  6771. + die(81);
  6772. +}
  6773. +
  6774. +void
  6775. +custom_error(char *flag, char *status, char *code)
  6776. +{
  6777. + char *c;
  6778. +
  6779. + if (substdio_put(&sserr, flag, 1) == -1)
  6780. + die_write();
  6781. + if (substdio_put(&sserr, "qmail-dkim: ", 12) == -1)
  6782. + die_write();
  6783. + if (substdio_puts(&sserr, status) == -1)
  6784. + die_write();
  6785. + if (code)
  6786. + {
  6787. + if (substdio_put(&sserr, " (#", 3) == -1)
  6788. + die_write();
  6789. + c = (*flag == 'Z') ? "4" : "5";
  6790. + if (substdio_put(&sserr, c, 1) == -1)
  6791. + die_write();
  6792. + if (substdio_put(&sserr, code + 1, 4) == -1)
  6793. + die_write();
  6794. + if (substdio_put(&sserr, ")", 1) == -1)
  6795. + die_write();
  6796. + }
  6797. + if (substdio_flush(&sserr) == -1)
  6798. + die_write();
  6799. + return;
  6800. +}
  6801. +
  6802. +int DKIM_CALL
  6803. +SignThisHeader(const char *szHeader)
  6804. +{
  6805. + if (strncasecmp((char *) szHeader, "X-", 2) == 0
  6806. + || strncasecmp((char *) szHeader, "Received:", 9) == 0
  6807. + || strncasecmp((char *) szHeader, "Authentication-Results:", 23) == 0
  6808. + || strncasecmp((char *) szHeader, "Return-Path:", 12) == 0)
  6809. + {
  6810. + return 0;
  6811. + }
  6812. + return 1;
  6813. +}
  6814. +
  6815. +void
  6816. +maybe_die_dkim(e)
  6817. + int e;
  6818. +{
  6819. + switch (e)
  6820. + {
  6821. + case DKIM_OUT_OF_MEMORY:
  6822. + case DKIM_BUFFER_TOO_SMALL:
  6823. + _exit (51);
  6824. + case DKIM_INVALID_CONTEXT:
  6825. + custom_error("Z", "DKIMContext structure invalid for this operation (#4.3.0)", 0);
  6826. + _exit(88);
  6827. + case DKIM_NO_SENDER:
  6828. + custom_error("Z", "Could not find From: or Sender: header in message (#5.1.7)", 0);
  6829. + _exit(88);
  6830. + case DKIM_BAD_PRIVATE_KEY:
  6831. + custom_error("D", "Could not parse private key (#5.7.5)", 0);
  6832. + _exit(88);
  6833. + default:
  6834. + return;
  6835. + }
  6836. +}
  6837. +
  6838. +unsigned int
  6839. +pidfmt(s, seq)
  6840. + char *s;
  6841. + unsigned long seq;
  6842. +{
  6843. + unsigned int i;
  6844. + unsigned int len;
  6845. + char *tmpdir;
  6846. +
  6847. + if (!(tmpdir = env_get("TMPDIR")))
  6848. + tmpdir = "/tmp";
  6849. + len = 0;
  6850. + i = fmt_str(s, tmpdir);
  6851. + len += i;
  6852. + if (s)
  6853. + s += i;
  6854. + i = fmt_str(s, "/qmail-dkim.");
  6855. + len += i;
  6856. + if (s)
  6857. + s += i;
  6858. + i = fmt_ulong(s, mypid);
  6859. + len += i;
  6860. + if (s)
  6861. + s += i;
  6862. + i = fmt_str(s, ".");
  6863. + len += i;
  6864. + if (s)
  6865. + s += i;
  6866. + i = fmt_ulong(s, starttime);
  6867. + len += i;
  6868. + if (s)
  6869. + s += i;
  6870. + i = fmt_str(s, ".");
  6871. + len += i;
  6872. + if (s)
  6873. + s += i;
  6874. + i = fmt_ulong(s, seq);
  6875. + len += i;
  6876. + if (s)
  6877. + s += i;
  6878. + ++len;
  6879. + if (s)
  6880. + *s++ = 0;
  6881. +
  6882. + return len;
  6883. +}
  6884. +
  6885. +void
  6886. +pidopen()
  6887. +{
  6888. + unsigned int len;
  6889. + unsigned long seq;
  6890. +
  6891. + seq = 1;
  6892. + len = pidfmt((char *) 0, seq);
  6893. + if (!(pidfn = alloc(len)))
  6894. + die(51);
  6895. + for (seq = 1; seq < 10; ++seq)
  6896. + {
  6897. + if (pidfmt((char *) 0, seq) > len)
  6898. + die(81); /*- paranoia */
  6899. + pidfmt(pidfn, seq);
  6900. + if ((messfd = open_excl(pidfn)) != -1)
  6901. + return;
  6902. + }
  6903. + die(63);
  6904. +}
  6905. +
  6906. +char tmp[FMT_ULONG];
  6907. +DKIMContext ctxt;
  6908. +char *dkimsign = 0;
  6909. +char *dkimverify = 0;
  6910. +char *dkimadspverify = 0, *dkimpractice = "FGHIJKLMNPQRSTUVW";
  6911. +stralloc dkimoutput = { 0 }; /*- DKIM-Signature */
  6912. +stralloc dksignature = { 0 }; /*- content of private signature */
  6913. +stralloc sigdomains = { 0 }; /*- domains which must have signatures */
  6914. +stralloc nsigdomains = { 0 }; /*- domains which do not have signatures */
  6915. +stralloc dkimopts = { 0 };
  6916. +char *dkimqueue = 0;
  6917. +
  6918. +static void
  6919. +write_signature(char *domain, char *keyfn)
  6920. +{
  6921. + char *pSig;
  6922. + int i;
  6923. + static stralloc keyfnfrom = { 0 };
  6924. +
  6925. + i = str_chr(keyfn, '%');
  6926. + if (keyfn[i])
  6927. + {
  6928. + if (!stralloc_copyb(&keyfnfrom, keyfn, i))
  6929. + die(51);
  6930. + if (!stralloc_cats(&keyfnfrom, domain))
  6931. + die(51);
  6932. + if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
  6933. + die(51);
  6934. + } else
  6935. + if (!stralloc_copys(&keyfnfrom, keyfn))
  6936. + die(51);
  6937. + if (!stralloc_0(&keyfnfrom))
  6938. + die(51);
  6939. + switch (control_readfile(&dksignature, keyfnfrom.s, 0))
  6940. + {
  6941. + case 0: /*- missing signature file */
  6942. + if (keyfn[i])
  6943. + return;
  6944. + die(32);
  6945. + case 1:
  6946. + break;
  6947. + default:
  6948. + custom_error("Z", "Unable to read private key. (#4.3.0)", 0);
  6949. + _exit(88);
  6950. + }
  6951. + for (i = 0; i < dksignature.len; i++)
  6952. + {
  6953. + if (dksignature.s[i] == '\0')
  6954. + dksignature.s[i] = '\n';
  6955. + }
  6956. + if (!stralloc_0(&dksignature))
  6957. + die(51);
  6958. + i = DKIMSignGetSig2(&ctxt, dksignature.s, &pSig);
  6959. + maybe_die_dkim(i);
  6960. + if (pSig)
  6961. + {
  6962. + if (!stralloc_catb(&dkimoutput, pSig, str_len(pSig)))
  6963. + die(51);
  6964. + if (!stralloc_cats(&dkimoutput, "\n"))
  6965. + die(51);
  6966. + }
  6967. + DKIMSignFree(&ctxt);
  6968. +}
  6969. +
  6970. +#include <openssl/evp.h>
  6971. +#define DKIM_MALLOC(s) OPENSSL_malloc(s)
  6972. +#define DKIM_MFREE(s) OPENSSL_free(s); s = NULL;
  6973. +char *dns_text(char *);
  6974. +
  6975. +int
  6976. +ParseTagValues(char *list, char *letters[], char *values[])
  6977. +{
  6978. + char *tmp, *ptr, *key;
  6979. + int i;
  6980. +
  6981. + /*- start with all args unset */
  6982. + for (i = 0; letters[i]; i++)
  6983. + values[i] = 0;
  6984. + key = 0;
  6985. + for(ptr = list;*ptr;)
  6986. + {
  6987. + if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')) /*- FWS */
  6988. + *ptr++ = 0;
  6989. + if (!key)
  6990. + key = ptr;
  6991. + if (*ptr == '=')
  6992. + {
  6993. + *ptr = 0;
  6994. + for (i = 0;letters[i];i++)
  6995. + {
  6996. + if (!str_diff(letters[i], key))
  6997. + {
  6998. + ptr++;
  6999. + for (;*ptr;)
  7000. + {
  7001. + if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n'))
  7002. + {
  7003. + ptr++;
  7004. + continue;
  7005. + }
  7006. + break;
  7007. + }
  7008. + values[i] = ptr;
  7009. + for(;*ptr && *ptr != ';';ptr++);
  7010. + tmp = ptr;
  7011. + if (*ptr)
  7012. + *ptr++ = 0;
  7013. + for(;tmp != values[i];tmp--) /*- RFC 4871 3.2 */
  7014. + {
  7015. + if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\r') || (*tmp == '\n'))
  7016. + {
  7017. + *tmp = 0;
  7018. + continue;
  7019. + }
  7020. + break;
  7021. + }
  7022. + key = 0;
  7023. + break;
  7024. + }
  7025. + }
  7026. + } else
  7027. + ptr++;
  7028. + }
  7029. + return (0);
  7030. +}
  7031. +
  7032. +int
  7033. +checkSSP(char *domain, int *bTesting)
  7034. +{
  7035. + char *query, *results;
  7036. + char *tags[] = { "dkim", "t", 0};
  7037. + char *values[2];
  7038. + int bIsParentSSP = 0, iSSP = DKIM_SSP_UNKNOWN;
  7039. +
  7040. + *bTesting = 0;
  7041. + if (!(query = DKIM_MALLOC(str_len("_ssp._domainkey.") + str_len(domain) + 1)))
  7042. + die(51);
  7043. + sprintf(query, "_ssp._domainkey.%s", domain);
  7044. + results = dns_text(query);
  7045. + DKIM_MFREE(query);
  7046. + if (!str_diff(results, "e=temp;"))
  7047. + {
  7048. + DKIM_MFREE(results);
  7049. + return DKIM_SSP_TEMPFAIL;
  7050. + } else
  7051. + if (!str_diff(results, "e=perm;"))
  7052. + {
  7053. + DKIM_MFREE(results);
  7054. + results = dns_text(domain);
  7055. + if (!str_diff(results, "e=temp;"))
  7056. + {
  7057. + DKIM_MFREE(results);
  7058. + return DKIM_SSP_TEMPFAIL;
  7059. + } else
  7060. + if (!str_diff(results, "e=perm;"))
  7061. + {
  7062. + DKIM_MFREE(results);
  7063. + return DKIM_SSP_SCOPE;
  7064. + }
  7065. + bIsParentSSP = 1;
  7066. + }
  7067. + if (!ParseTagValues(results, tags, values))
  7068. + return DKIM_SSP_UNKNOWN;
  7069. + if (values[0] != NULL) {
  7070. + if (strcasecmp(values[0], "all") == 0)
  7071. + iSSP = DKIM_SSP_ALL;
  7072. + else
  7073. + if (strcasecmp(values[0], "strict") == 0)
  7074. + iSSP = DKIM_SSP_STRICT;
  7075. + }
  7076. + // flags
  7077. + if (values[1] != NULL) {
  7078. + char *s, *p;
  7079. + for (p = values[1], s = values[1]; *p; p++)
  7080. + {
  7081. + if (*p == '|')
  7082. + *p = 0;
  7083. + else
  7084. + continue;
  7085. + if (!str_diff(s, "y"))
  7086. + *bTesting = 1;
  7087. + else
  7088. + if (!str_diff(s, "s")) {
  7089. + if (bIsParentSSP) {
  7090. + /*
  7091. + * this is a parent's SSP record that should not apply to subdomains
  7092. + * the message is non-suspicious
  7093. + */
  7094. + *bTesting = 0;
  7095. + return (DKIM_SSP_UNKNOWN);
  7096. + }
  7097. + }
  7098. + s = p + 1;
  7099. + }
  7100. + }
  7101. + return iSSP;
  7102. +}
  7103. +
  7104. +int
  7105. +checkADSP(char *domain)
  7106. +{
  7107. + char *query, *results;
  7108. + char *tags[] = { "dkim", 0};
  7109. + char *values[1];
  7110. +
  7111. + results = dns_text(domain);
  7112. + if (!str_diff(results, "e=perm;"))
  7113. + {
  7114. + DKIM_MFREE(results);
  7115. + return DKIM_ADSP_SCOPE;
  7116. + }
  7117. + else
  7118. + if (!str_diff(results, "e=temp;"))
  7119. + {
  7120. + DKIM_MFREE(results);
  7121. + return DKIM_ADSP_TEMPFAIL;
  7122. + }
  7123. + if (!(query = DKIM_MALLOC(str_len("_adsp._domainkey.") + str_len(domain) + 1)))
  7124. + die(51);
  7125. + sprintf(query, "_adsp._domainkey.%s", domain);
  7126. + results = dns_text(query);
  7127. + DKIM_MFREE(query);
  7128. + if (!str_diff(results, "e=perm;"))
  7129. + {
  7130. + DKIM_MFREE(results);
  7131. + return DKIM_ADSP_SCOPE;
  7132. + } else
  7133. + if (!str_diff(results, "e=temp;"))
  7134. + {
  7135. + DKIM_MFREE(results);
  7136. + return DKIM_ADSP_TEMPFAIL;
  7137. + }
  7138. + DKIM_MFREE(results);
  7139. + if (!ParseTagValues(results, tags, values))
  7140. + return DKIM_SSP_UNKNOWN;
  7141. + if (values[0] != NULL) {
  7142. + if (strcasecmp(values[0], "all") == 0)
  7143. + return (DKIM_ADSP_ALL);
  7144. + else
  7145. + if (strcasecmp(values[0], "discardable") == 0)
  7146. + return (DKIM_ADSP_DISCARDABLE);
  7147. + }
  7148. + return DKIM_ADSP_UNKNOWN; /*- No ADSP Record */
  7149. +}
  7150. +
  7151. +void
  7152. +dkimverify_exit(int dkimRet, char *status, char *code)
  7153. +{
  7154. + if (dkimRet < 0)
  7155. + {
  7156. + if (dkimverify[str_chr(dkimverify, 'F' - dkimRet)])
  7157. + {
  7158. + custom_error("D", status, code);
  7159. + die(88);
  7160. + }
  7161. + if (dkimverify[str_chr(dkimverify, 'f' - dkimRet)])
  7162. + {
  7163. + custom_error("Z", status, code);
  7164. + die(88);
  7165. + }
  7166. + } else
  7167. + {
  7168. + if (dkimverify[str_chr(dkimverify, 'A' + dkimRet)])
  7169. + {
  7170. + custom_error("D", status, code);
  7171. + die(88);
  7172. + }
  7173. + if (dkimverify[str_chr(dkimverify, 'a' + dkimRet)])
  7174. + {
  7175. + custom_error("Z", status, code);
  7176. + die(88);
  7177. + }
  7178. + }
  7179. +}
  7180. +
  7181. +void
  7182. +writeHeaderNexit(int ret, int origRet, int resDKIMSSP, int resDKIMADSP, int useSSP, int useADSP)
  7183. +{
  7184. + char *dkimStatus = 0, *sspStatus = 0, *adspStatus = 0, *code = 0, *orig = 0;
  7185. + char strnum[FMT_ULONG];
  7186. +
  7187. + switch (ret)
  7188. + {
  7189. + case DKIM_SUCCESS: /*- 0 */ /*- A */
  7190. + dkimStatus = "good ";
  7191. + code = "X.7.0";
  7192. + break;
  7193. + case DKIM_FINISHED_BODY: /*- 1 process result: no more message body is needed */
  7194. + dkimStatus = "process result: no more message body is needed";
  7195. + code = "X.7.0";
  7196. + break;
  7197. + case DKIM_PARTIAL_SUCCESS: /*- 2 verify result: at least one but not all signatures verified */
  7198. + dkimStatus = "verify result: at least none but not all signatures verified";
  7199. + code = "X.7.0";
  7200. + break;
  7201. + case DKIM_NEUTRAL: /*- 3 verify result: no signatures verified but message is not suspicious */
  7202. + dkimStatus = "verify result: no signatures verified but message is not suspicious";
  7203. + code = "X.7.0";
  7204. + break;
  7205. + case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
  7206. + dkimStatus = "signature result: signature verified but it did not include all of the body";
  7207. + code = "X.7.0";
  7208. + break;
  7209. + case DKIM_FAIL: /*- -1 */ /*- F */
  7210. + dkimStatus = "DKIM Signature verification failed";
  7211. + code = "X.7.0";
  7212. + break;
  7213. + case DKIM_BAD_SYNTAX: /*- -2 */ /*- G */
  7214. + dkimStatus = "signature error: DKIM-Signature could not parse or has bad tags/values";
  7215. + code = "X.7.5";
  7216. + break;
  7217. + case DKIM_SIGNATURE_BAD: /*- -3 */
  7218. + dkimStatus = "signature error: RSA verify failed";
  7219. + code = "X.7.5";
  7220. + break;
  7221. + case DKIM_SIGNATURE_BAD_BUT_TESTING:
  7222. + dkimStatus = "signature error: RSA verify failed but testing";
  7223. + code = "X.7.5";
  7224. + break;
  7225. + case DKIM_SIGNATURE_EXPIRED:
  7226. + dkimStatus = "signature error: x= is old";
  7227. + code = "X.7.5";
  7228. + break;
  7229. + case DKIM_SELECTOR_INVALID:
  7230. + dkimStatus = "signature error: selector doesn't parse or contains invalid values";
  7231. + code = "X.7.5";
  7232. + break;
  7233. + case DKIM_SELECTOR_GRANULARITY_MISMATCH:
  7234. + dkimStatus = "signature error: selector g= doesn't match i=";
  7235. + code = "X.7.5";
  7236. + break;
  7237. + case DKIM_SELECTOR_KEY_REVOKED:
  7238. + dkimStatus = "signature error: selector p= empty";
  7239. + code = "X.7.5";
  7240. + break;
  7241. + case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
  7242. + dkimStatus = "signature error: selector domain name too long to request";
  7243. + code = "X.7.0";
  7244. + break;
  7245. + case DKIM_SELECTOR_DNS_TEMP_FAILURE:
  7246. + dkimStatus = "signature error: temporary dns failure requesting selector";
  7247. + code = "X.7.0";
  7248. + break;
  7249. + case DKIM_SELECTOR_DNS_PERM_FAILURE:
  7250. + dkimStatus = "signature error: permanent dns failure requesting selector";
  7251. + code = "X.7.0";
  7252. + break;
  7253. + case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
  7254. + dkimStatus = "signature error: selector p= value invalid or wrong format";
  7255. + code = "X.7.5";
  7256. + break;
  7257. + case DKIM_NO_SIGNATURES:
  7258. + dkimStatus = "no signatures";
  7259. + code = "X.7.5";
  7260. + break;
  7261. + case DKIM_NO_VALID_SIGNATURES:
  7262. + dkimStatus = "no valid signatures";
  7263. + code = "X.7.5";
  7264. + break;
  7265. + case DKIM_BODY_HASH_MISMATCH:
  7266. + dkimStatus = "sigature verify error: message body does not hash to bh value";
  7267. + code = "X.7.7";
  7268. + break;
  7269. + case DKIM_SELECTOR_ALGORITHM_MISMATCH:
  7270. + dkimStatus = "signature error: selector h= doesn't match signature a=";
  7271. + code = "X.7.7";
  7272. + break;
  7273. + case DKIM_STAT_INCOMPAT:
  7274. + dkimStatus = "signature error: incompatible v=";
  7275. + code = "X.7.6";
  7276. + break;
  7277. + default:
  7278. + dkimStatus = "error";
  7279. + code = "X.3.0";
  7280. + break;
  7281. + }
  7282. + if (useSSP && resDKIMSSP != -1)
  7283. + {
  7284. + switch(resDKIMSSP)
  7285. + {
  7286. + case DKIM_SSP_ALL:
  7287. + sspStatus = (char *) "all;";
  7288. + break;
  7289. + case DKIM_SSP_STRICT:
  7290. + sspStatus = (char *) "strict;";
  7291. + break;
  7292. + case DKIM_SSP_SCOPE:
  7293. + sspStatus = (char *) "out of scope;";
  7294. + break;
  7295. + case DKIM_SSP_TEMPFAIL:
  7296. + sspStatus = (char *) "temporary failure;";
  7297. + break;
  7298. + case DKIM_SSP_UNKNOWN:
  7299. + default:
  7300. + sspStatus = (char *) "unknown;";
  7301. + break;
  7302. + }
  7303. + }
  7304. + if (useADSP && resDKIMADSP != -1)
  7305. + {
  7306. + switch(resDKIMADSP)
  7307. + {
  7308. + case DKIM_ADSP_ALL:
  7309. + adspStatus = (char *) "all;";
  7310. + break;
  7311. + case DKIM_ADSP_DISCARDABLE:
  7312. + adspStatus = (char *) "discardable;";
  7313. + break;
  7314. + case DKIM_ADSP_SCOPE:
  7315. + adspStatus = (char *) "out of scope;";
  7316. + break;
  7317. + case DKIM_ADSP_TEMPFAIL:
  7318. + adspStatus = (char *) "temporary failure;";
  7319. + break;
  7320. + case DKIM_ADSP_UNKNOWN:
  7321. + default:
  7322. + adspStatus = (char *) "unknown ;";
  7323. + break;
  7324. + }
  7325. + }
  7326. + if (!stralloc_copys(&dkimoutput, "DKIM-Status: "))
  7327. + die(51);
  7328. + if (!stralloc_cats(&dkimoutput, dkimStatus))
  7329. + die(51);
  7330. + if (origRet != DKIM_MAX_ERROR && ret != origRet)
  7331. + {
  7332. + if (!stralloc_cats(&dkimoutput, "\n\t(old="))
  7333. + die(51);
  7334. + switch (origRet)
  7335. + {
  7336. + case DKIM_SUCCESS: /*- 0 */ /*- A */
  7337. + orig = "SUCCESS";
  7338. + break;
  7339. + case DKIM_FINISHED_BODY: /*- 1 process result: no more message body is needed */
  7340. + orig = "FINISHED BODY";
  7341. + break;
  7342. + case DKIM_PARTIAL_SUCCESS: /*- 2 verify result: at least one but not all signatures verified */
  7343. + orig = "PARTIAL SUCCESS";
  7344. + break;
  7345. + case DKIM_NEUTRAL: /*- 3 verify result: no signatures verified but message is not suspicious */
  7346. + orig = "NEUTRAL";
  7347. + break;
  7348. + case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
  7349. + orig = "SUCCESS(BUT EXTRA)";
  7350. + break;
  7351. + case DKIM_FAIL: /*- -1 */ /*- F */
  7352. + orig = "FAIL";
  7353. + break;
  7354. + case DKIM_BAD_SYNTAX: /*- -2 */ /*- G */
  7355. + orig = "BAD SYNTAX";
  7356. + break;
  7357. + case DKIM_SIGNATURE_BAD: /*- -3 */
  7358. + orig = "SIGNATURE BAD";
  7359. + break;
  7360. + case DKIM_SIGNATURE_BAD_BUT_TESTING:
  7361. + orig = "SIGNATURE BAD (TESTING)";
  7362. + break;
  7363. + case DKIM_SIGNATURE_EXPIRED:
  7364. + orig = "SIGNATURE EXPIRED";
  7365. + break;
  7366. + case DKIM_SELECTOR_INVALID:
  7367. + orig = "SELECTOR INVALID";
  7368. + break;
  7369. + case DKIM_SELECTOR_GRANULARITY_MISMATCH:
  7370. + orig = "SELECTOR GRANULARITY MISMATCH";
  7371. + break;
  7372. + case DKIM_SELECTOR_KEY_REVOKED:
  7373. + orig = "SELECTOR KEY REVOKED";
  7374. + break;
  7375. + case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
  7376. + orig = "DOMAIN NAME TOO LONG";
  7377. + break;
  7378. + case DKIM_SELECTOR_DNS_TEMP_FAILURE:
  7379. + orig = "DNS TEMP FAILURE";
  7380. + break;
  7381. + case DKIM_SELECTOR_DNS_PERM_FAILURE:
  7382. + orig = "DNS PERM FAILURE";
  7383. + break;
  7384. + case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
  7385. + orig = "PUBLIC KEY INVALID";
  7386. + break;
  7387. + case DKIM_NO_SIGNATURES:
  7388. + orig = "NO SIGNATURES";
  7389. + break;
  7390. + case DKIM_NO_VALID_SIGNATURES:
  7391. + orig = "NO VALID SIGNATURES";
  7392. + break;
  7393. + case DKIM_BODY_HASH_MISMATCH:
  7394. + orig = "BODY HASH MISMATCH";
  7395. + break;
  7396. + case DKIM_SELECTOR_ALGORITHM_MISMATCH:
  7397. + orig = "ALGORITHM MISMATCH";
  7398. + break;
  7399. + case DKIM_STAT_INCOMPAT:
  7400. + orig = "STAT INCOMPAT";
  7401. + break;
  7402. + default:
  7403. + orig = "Unkown error";
  7404. + break;
  7405. + }
  7406. + if (!stralloc_cats(&dkimoutput, orig))
  7407. + die(51);
  7408. + if (!stralloc_cats(&dkimoutput, ":"))
  7409. + die(51);
  7410. + if (origRet < 0)
  7411. + {
  7412. + if (!stralloc_cats(&dkimoutput, "-"))
  7413. + die(51);
  7414. + strnum[fmt_ulong(strnum, 0 - origRet)] = 0;
  7415. + } else
  7416. + strnum[fmt_ulong(strnum, origRet)] = 0;
  7417. + if (!stralloc_cats(&dkimoutput, strnum))
  7418. + die(51);
  7419. + if (!stralloc_cats(&dkimoutput, ")"))
  7420. + die(51);
  7421. + }
  7422. + if (!stralloc_cats(&dkimoutput, "\n"))
  7423. + die(51);
  7424. + if (useSSP && sspStatus) {
  7425. + if (!stralloc_cats(&dkimoutput, "X-DKIM-SSP: "))
  7426. + die(51);
  7427. + if (!stralloc_cats(&dkimoutput, sspStatus))
  7428. + die(51);
  7429. + if (!stralloc_cats(&dkimoutput, "\n"))
  7430. + die(51);
  7431. + }
  7432. + if (useADSP && adspStatus) {
  7433. + if (!stralloc_cats(&dkimoutput, "X-DKIM-ADSP: "))
  7434. + die(51);
  7435. + if (!stralloc_cats(&dkimoutput, adspStatus))
  7436. + die(51);
  7437. + if (!stralloc_cats(&dkimoutput, "\n"))
  7438. + die(51);
  7439. + }
  7440. + dkimverify_exit(ret, dkimStatus, code);
  7441. + return;
  7442. +}
  7443. +
  7444. +int
  7445. +checkPractice(int dkimRet)
  7446. +{
  7447. + char *ptr;
  7448. +
  7449. + if (!(ptr = env_get("DKIMPRACTICE")))
  7450. + return (0);
  7451. + else
  7452. + dkimpractice = ptr;
  7453. + if (!*ptr)
  7454. + {
  7455. + if (dkimRet < 0 || dkimRet == DKIM_3PS_SIGNATURE)
  7456. + return (1);
  7457. + return (0);
  7458. + }
  7459. + if (dkimRet < 0)
  7460. + {
  7461. + if (dkimpractice[str_chr(dkimpractice, 'F' - dkimRet)])
  7462. + return (1);
  7463. + if (dkimpractice[str_chr(dkimpractice, 'f' - dkimRet)])
  7464. + return (1);
  7465. + } else
  7466. + {
  7467. + if (dkimpractice[str_chr(dkimpractice, 'A' + dkimRet)])
  7468. + return (1);
  7469. + if (dkimpractice[str_chr(dkimpractice, 'a' + dkimRet)])
  7470. + return (1);
  7471. + }
  7472. + return (0);
  7473. +}
  7474. +
  7475. +static char *binqqargs[2] = { "bin/qmail-queue", 0 };
  7476. +
  7477. +int
  7478. +dkim_setoptions(DKIMSignOptions *opts, char *signOptions)
  7479. +{
  7480. + int ch, argc;
  7481. + char **argv;
  7482. +
  7483. + opts->nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
  7484. + opts->nCanon = DKIM_SIGN_RELAXED; /*- c */
  7485. + opts->nIncludeBodyLengthTag = 0; /*- l */
  7486. + opts->nIncludeQueryMethod = 0; /*- q */
  7487. + opts->nIncludeTimeStamp = 0; /*- t */
  7488. + opts->nIncludeCopiedHeaders = 0; /*- h */
  7489. + opts->szIdentity[0] = '\0';
  7490. + opts->expireTime = starttime + 604800; // expires in 1 week
  7491. + opts->nHash = DKIM_HASH_SHA1;
  7492. + str_copy(opts->szRequiredHeaders, "NonExistent");
  7493. + if (!signOptions)
  7494. + return (0);
  7495. + if (!stralloc_copys(&dkimopts, "dkim "))
  7496. + die(51);
  7497. + if (!stralloc_cats(&dkimopts, signOptions))
  7498. + die(51);
  7499. + if (!stralloc_0(&dkimopts))
  7500. + die(51);
  7501. + if (!(argv = MakeArgs(dkimopts.s)))
  7502. + die(51);
  7503. + for (argc = 0;argv[argc];argc++);
  7504. +#ifdef HAVE_EVP_SHA256
  7505. + while ((ch = sgopt(argc, argv, "b:c:li:qthx:z:")) != sgoptdone)
  7506. +#else
  7507. + while ((ch = sgopt(argc, argv, "b:c:li:qthx:")) != sgoptdone)
  7508. +#endif
  7509. + {
  7510. + switch (ch)
  7511. + {
  7512. + case 'b':
  7513. + switch (*optarg)
  7514. + {
  7515. + case '1':
  7516. + opts->nIncludeBodyHash = DKIM_BODYHASH_ALLMAN_1;
  7517. + break;
  7518. + case '2':
  7519. + opts->nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
  7520. + break;
  7521. + case '3':
  7522. + opts->nIncludeBodyHash = DKIM_BODYHASH_BOTH;
  7523. + break;
  7524. + default:
  7525. + FreeMakeArgs(argv);
  7526. + return (1);
  7527. + }
  7528. + break;
  7529. + case 'c':
  7530. + switch (*optarg)
  7531. + {
  7532. + case 'r':
  7533. + opts->nCanon = DKIM_SIGN_RELAXED;
  7534. + break;
  7535. + case 's':
  7536. + opts->nCanon = DKIM_SIGN_SIMPLE;
  7537. + break;
  7538. + case 't':
  7539. + opts->nCanon = DKIM_SIGN_RELAXED_SIMPLE;
  7540. + break;
  7541. + case 'u':
  7542. + opts->nCanon = DKIM_SIGN_SIMPLE_RELAXED;
  7543. + break;
  7544. + default:
  7545. + FreeMakeArgs(argv);
  7546. + return (1);
  7547. + }
  7548. + break;
  7549. + case 'l': /*- body length tag */
  7550. + opts->nIncludeBodyLengthTag = 1;
  7551. + break;
  7552. + case 'q': /*- query method tag */
  7553. + opts->nIncludeQueryMethod = 1;
  7554. + break;
  7555. + case 't': /*- timestamp tag */
  7556. + opts->nIncludeTimeStamp = 1;
  7557. + break;
  7558. + case 'h':
  7559. + opts->nIncludeCopiedHeaders = 1;
  7560. + break;
  7561. + case 'i': /*- identity */
  7562. + if (*optarg == '-') /* do not use i= tag */
  7563. + opts->szIdentity[0] = '\0';
  7564. + else
  7565. + str_copyb(opts->szIdentity, optarg, sizeof(opts->szIdentity) - 1);
  7566. + break;
  7567. + case 'x': /*- expire time */
  7568. + if (*optarg == '-')
  7569. + opts->expireTime = 0;
  7570. + else
  7571. + opts->expireTime = starttime + atoi(optarg);
  7572. + break;
  7573. +#ifdef HAVE_EVP_SHA256
  7574. + case 'z': /*- sign w/ sha1, sha256 or both */
  7575. + switch (*optarg)
  7576. + {
  7577. + case '1':
  7578. + opts->nHash = DKIM_HASH_SHA1;
  7579. + break;
  7580. + case '2':
  7581. + opts->nHash = DKIM_HASH_SHA256;
  7582. + break;
  7583. + case '3':
  7584. + opts->nHash = DKIM_HASH_SHA1_AND_256;
  7585. + break;
  7586. + default:
  7587. + FreeMakeArgs(argv);
  7588. + return (1);
  7589. + }
  7590. + break;
  7591. +#endif
  7592. + default:
  7593. + FreeMakeArgs(argv);
  7594. + return (1);
  7595. + } /*- switch (ch) */
  7596. + } /*- while (1) */
  7597. + FreeMakeArgs(argv);
  7598. + return (0);
  7599. +}
  7600. +
  7601. +int
  7602. +main(int argc, char *argv[])
  7603. +{
  7604. + int pim[2];
  7605. + int wstat;
  7606. + int resDKIMSSP = -1, resDKIMADSP = -1, useSSP = 0, useADSP = 0, accept3ps = 0;
  7607. + int sCount = 0, sSize = 0;
  7608. + int ret = 0, origRet = DKIM_MAX_ERROR, i, nSigCount = 0, len, token_len;
  7609. + unsigned long pid;
  7610. + char *selector, *p;
  7611. + DKIMSignOptions opts = { 0 };
  7612. + DKIMVerifyDetails *pDetails;
  7613. + DKIMVerifyOptions vopts = { 0 };
  7614. +
  7615. + starttime = now();
  7616. + sig_blocknone();
  7617. + umask(033);
  7618. + if (chdir(auto_qmail) == -1)
  7619. + die(61);
  7620. + if (!dkimsign)
  7621. + dkimsign = env_get("DKIMSIGN");
  7622. + if (!dkimverify)
  7623. + dkimverify = env_get("DKIMVERIFY");
  7624. + if (!dkimsign && !dkimverify && (p = env_get("RELAYCLIENT")))
  7625. + dkimsign = "control/domainkeys/%/default";
  7626. + dkimqueue = env_get("DKIMQUEUE");
  7627. + if (dkimqueue && *dkimqueue)
  7628. + binqqargs[0] = dkimqueue;
  7629. + substdio_fdbuf(&sserr, write, CUSTOM_ERR_FD, errbuf, sizeof(errbuf));
  7630. + if (dkimsign)
  7631. + {
  7632. + /* selector */
  7633. + p = dkimsign;
  7634. + selector = p;
  7635. + while (*p)
  7636. + {
  7637. + if (*p == '/' && *(p + 1))
  7638. + selector = p + 1;
  7639. + p++;
  7640. + }
  7641. + str_copyb(opts.szSelector, selector, sizeof(opts.szSelector) - 1);
  7642. +
  7643. + if (dkim_setoptions(&opts, env_get("DKIMSIGNOPTIONS")))
  7644. + {
  7645. + custom_error("Z", "Invalid DKIMSIGNOPTIONS (#4.3.0)", 0);
  7646. + _exit(88);
  7647. + }
  7648. + p = env_get("DKIMIDENTITY");
  7649. + if (p && *p)
  7650. + str_copyb(opts.szIdentity, p, sizeof(opts.szIdentity) - 1);
  7651. + p = env_get("DKIMEXPIRE");
  7652. + if (p && *p)
  7653. + opts.expireTime = starttime + atol(p);
  7654. + else
  7655. + if (p)
  7656. + opts.expireTime = 0;
  7657. + opts.pfnHeaderCallback = SignThisHeader;
  7658. + if (DKIMSignInit(&ctxt, &opts) != DKIM_SUCCESS) /*- failed to initialize signature */
  7659. + die(51);
  7660. + } else
  7661. + {
  7662. + char *x;
  7663. +
  7664. + if (!(x = env_get("SIGN_PRACTICE")))
  7665. + x = "adsp";
  7666. + if (!str_diffn("adsp", x, 4))
  7667. + {
  7668. + useADSP = 1;
  7669. + accept3ps = 1;
  7670. + }
  7671. + else
  7672. + if (!str_diffn("ssp", x, 3))
  7673. + {
  7674. + useSSP = 1;
  7675. + accept3ps = 1;
  7676. + } else
  7677. + if (!str_diffn("local", x, 5))
  7678. + {
  7679. + useSSP = 0;
  7680. + useADSP = 0;
  7681. + accept3ps = 1;
  7682. + }
  7683. + if (useADSP)
  7684. + vopts.nCheckPractices = useADSP;
  7685. + else
  7686. + if (useSSP)
  7687. + vopts.nCheckPractices = useSSP;
  7688. + else
  7689. + vopts.nCheckPractices = 0;
  7690. + vopts.nAccept3ps = accept3ps;
  7691. + vopts.pfnSelectorCallback = NULL; /*- SelectorCallback; */
  7692. + DKIMVerifyInit(&ctxt, &vopts); /*- this is always successful */
  7693. + }
  7694. + /*- Initialization */
  7695. + mypid = getpid();
  7696. + uid = getuid();
  7697. + datetime_tai(&dt, starttime);
  7698. + sig_pipeignore();
  7699. + sig_miscignore();
  7700. + sig_alarmcatch(sigalrm);
  7701. + sig_bugcatch(sigbug);
  7702. + alarm(DEATH);
  7703. + pidopen(); /*- fd = messfd */
  7704. + if ((readfd = open_read(pidfn)) == -1)
  7705. + die(63);
  7706. + if (unlink(pidfn) == -1)
  7707. + die(63);
  7708. + substdio_fdbuf(&ssout, write, messfd, outbuf, sizeof(outbuf));
  7709. + substdio_fdbuf(&ssin, read, 0, inbuf, sizeof(inbuf));
  7710. + for (;;)
  7711. + {
  7712. + register int n;
  7713. + register char *x;
  7714. + int i, j;
  7715. +
  7716. + if ((n = substdio_feed(&ssin)) < 0)
  7717. + die_read();
  7718. + if (!n)
  7719. + break;
  7720. + x = substdio_PEEK(&ssin);
  7721. + if (dkimsign || dkimverify)
  7722. + {
  7723. + for (i = 0; i < n; i++)
  7724. + {
  7725. + if (x[i] == '\n')
  7726. + {
  7727. + if (dkimsign)
  7728. + j = DKIMSignProcess(&ctxt, "\r\n", 2);
  7729. + else
  7730. + j = DKIMVerifyProcess(&ctxt, "\r\n", 2);
  7731. + } else
  7732. + {
  7733. + if (dkimsign)
  7734. + j = DKIMSignProcess(&ctxt, x + i, 1);
  7735. + else
  7736. + j = DKIMVerifyProcess(&ctxt, x + i, 1);
  7737. + }
  7738. + maybe_die_dkim(j);
  7739. + if (j > 0 && j < DKIM_FINISHED_BODY)
  7740. + break;
  7741. + if (!ret && j)
  7742. + ret = j;
  7743. + }
  7744. + } /*- for(;;) */
  7745. + if (substdio_put(&ssout, x, n) == -1)
  7746. + die_write();
  7747. + substdio_SEEK(&ssin, n);
  7748. + }
  7749. + if (substdio_flush(&ssout) == -1)
  7750. + die_write();
  7751. + if (dkimsign || dkimverify)
  7752. + {
  7753. + if (dkimsign)
  7754. + write_signature(DKIMSignGetDomain(&ctxt), dkimsign);
  7755. + else
  7756. + if (dkimverify)
  7757. + {
  7758. + char szPolicy[512];
  7759. +
  7760. + if (!ret)
  7761. + {
  7762. + if ((ret = DKIMVerifyResults(&ctxt, &sCount, &sSize)) != DKIM_SUCCESS)
  7763. + maybe_die_dkim(ret);
  7764. + if ((ret = DKIMVerifyGetDetails(&ctxt, &nSigCount, &pDetails, szPolicy)) != DKIM_SUCCESS)
  7765. + maybe_die_dkim(ret);
  7766. + else
  7767. + for (ret = DKIM_SUCCESS,i = 0; i < nSigCount; i++) {
  7768. + if (pDetails[i].nResult < 0)
  7769. + {
  7770. + ret = pDetails[i].nResult;
  7771. + break; /*- don't know if it is right to break */
  7772. + }
  7773. + }
  7774. + if (!nSigCount)
  7775. + ret = DKIM_NO_SIGNATURES;
  7776. + }
  7777. + if (checkPractice(ret)) {
  7778. + char *domain;
  7779. +
  7780. + origRet = ret;
  7781. + if ((domain = DKIMVerifyGetDomain(&ctxt)))
  7782. + {
  7783. + if (!(p = env_get("SIGNATUREDOMAINS")))
  7784. + {
  7785. + if (control_readfile(&sigdomains, "control/signaturedomains", 0) == -1)
  7786. + die(55);
  7787. + } else
  7788. + if (!stralloc_copys(&sigdomains, p))
  7789. + die(51);
  7790. + for (len = 0, p = sigdomains.s;len < sigdomains.len;)
  7791. + {
  7792. + len += ((token_len = str_len(p)) + 1); /*- next domain */
  7793. + if (!case_diffb(p, token_len, domain))
  7794. + {
  7795. + ret = DKIM_FAIL;
  7796. + useADSP = 0;
  7797. + useSSP = 0;
  7798. + break;
  7799. + }
  7800. + p = sigdomains.s + len;
  7801. + }
  7802. + if (!(p = env_get("NOSIGNATUREDOMAINS")))
  7803. + {
  7804. + if (control_readfile(&nsigdomains, "control/nosignaturedomains", 0) == -1)
  7805. + die(55);
  7806. + } else
  7807. + if (!stralloc_copys(&nsigdomains, p))
  7808. + die(51);
  7809. + for (len = 0, p = nsigdomains.s;len < nsigdomains.len;)
  7810. + {
  7811. + len += ((token_len = str_len(p)) + 1); /*- next domain */
  7812. + if (*p == '*' || !case_diffb(p, token_len, domain))
  7813. + {
  7814. + ret = DKIM_NEUTRAL;
  7815. + useADSP = 0;
  7816. + useSSP = 0;
  7817. + break;
  7818. + }
  7819. + p = nsigdomains.s + len;
  7820. + }
  7821. + }
  7822. + if (!domain || !*domain)
  7823. + ; /*- do nothing ? */
  7824. + else
  7825. + if (useADSP)
  7826. + {
  7827. + resDKIMADSP = checkADSP(domain);
  7828. + if (sCount > 0) {
  7829. + if (resDKIMADSP == DKIM_ADSP_UNKNOWN || resDKIMADSP == DKIM_ADSP_ALL)
  7830. + ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
  7831. + }
  7832. + /* if the message should be signed, return fail */
  7833. + if (resDKIMADSP == DKIM_ADSP_DISCARDABLE)
  7834. + ret = DKIM_FAIL;
  7835. + else
  7836. + ret = DKIM_NEUTRAL;
  7837. + } else
  7838. + if (useSSP)
  7839. + {
  7840. + int bTestingPractices = 0;
  7841. + char *domain;
  7842. +
  7843. + if ((domain = DKIMVerifyGetDomain(&ctxt)))
  7844. + resDKIMSSP = checkSSP(domain, &bTestingPractices);
  7845. + if (sCount > 0) {
  7846. + if ((resDKIMSSP == DKIM_SSP_UNKNOWN || resDKIMSSP == DKIM_SSP_ALL))
  7847. + ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
  7848. + }
  7849. + // if the SSP is testing, return neutral
  7850. + if (bTestingPractices)
  7851. + ret = DKIM_NEUTRAL;
  7852. + /* if the message should be signed, return fail */
  7853. + if (resDKIMSSP == DKIM_SSP_ALL || resDKIMSSP == DKIM_SSP_STRICT)
  7854. + ret = DKIM_FAIL;
  7855. + else
  7856. + ret = DKIM_NEUTRAL;
  7857. + }
  7858. + }
  7859. + DKIMVerifyFree(&ctxt);
  7860. + writeHeaderNexit(ret, origRet, resDKIMSSP, resDKIMADSP, useSSP, useADSP);
  7861. + } /*- if (dkimverify) */
  7862. + }
  7863. + if (pipe(pim) == -1)
  7864. + die(59);
  7865. + switch (pid = vfork())
  7866. + {
  7867. + case -1:
  7868. + close(pim[0]);
  7869. + close(pim[1]);
  7870. + die(58);
  7871. + case 0:
  7872. + close(pim[1]);
  7873. + if (fd_move(0, pim[0]) == -1)
  7874. + die(120);
  7875. + execv(*binqqargs, binqqargs);
  7876. + die(120);
  7877. + }
  7878. + close(pim[0]);
  7879. + substdio_fdbuf(&ssin, read, readfd, inbuf, sizeof(inbuf));
  7880. + substdio_fdbuf(&ssout, write, pim[1], outbuf, sizeof(outbuf));
  7881. + if (substdio_bput(&ssout, dkimoutput.s, dkimoutput.len) == -1) /*- write DKIM signature */
  7882. + die_write();
  7883. + switch (substdio_copy(&ssout, &ssin))
  7884. + {
  7885. + case -2:
  7886. + die_read();
  7887. + case -3:
  7888. + die_write();
  7889. + }
  7890. + if (substdio_flush(&ssout) == -1)
  7891. + die_write();
  7892. + close(pim[1]);
  7893. + if (wait_pid(&wstat, pid) != pid)
  7894. + die(57);
  7895. + if (wait_crashed(wstat))
  7896. + die(57);
  7897. + die(wait_exitcode(wstat));
  7898. + /*- Not Reached */
  7899. + exit(0);
  7900. +}
  7901. +
  7902. +void
  7903. +getversion_qmail_dkim_c()
  7904. +{
  7905. + static char *x = "$Id: qmail-dkim.c,v 1.18 2009-04-16 13:48:32+05:30 Cprogrammer Exp mbhangui $";
  7906. +
  7907. + x++;
  7908. +}
  7909. --- qmail-1.03.orig/qmail.h 2009-10-15 20:38:24.006353000 +0300
  7910. +++ qmail-1.03/qmail.h 2009-10-16 00:27:32.250352161 +0300
  7911. @@ -3,11 +3,13 @@
  7912. #include "substdio.h"
  7913. +#define CUSTOM_ERR_FD 2
  7914. struct qmail {
  7915. int flagerr;
  7916. unsigned long pid;
  7917. int fdm;
  7918. int fde;
  7919. + int fdc;
  7920. substdio ss;
  7921. char buf[1024];
  7922. } ;
  7923. --- qmail-1.03.orig/qmail-lspawn.c 2009-10-15 20:38:23.890352000 +0300
  7924. +++ qmail-1.03/qmail-lspawn.c 2009-10-16 00:24:38.748439191 +0300
  7925. @@ -713,6 +713,7 @@
  7926. char *s; char *r; unsigned int at;
  7927. {
  7928. int f;
  7929. + char *ptr;
  7930. if (!(f = fork()))
  7931. {
  7932. @@ -865,7 +866,10 @@
  7933. check_home(args[3], aliasempty);
  7934. #endif
  7935. - execv(*args,args);
  7936. + if(!(ptr = env_get("QMAILLOCAL")))
  7937. + execv(*args, args);
  7938. + else
  7939. + execv(ptr, args);
  7940. if (error_temp(errno)) _exit(QLX_EXECSOFT);
  7941. _exit(QLX_EXECHARD);
  7942. }
  7943. --- qmail-1.03.orig/qmail-rspawn.c 2009-10-15 20:38:23.946351000 +0300
  7944. +++ qmail-1.03/qmail-rspawn.c 2009-10-16 00:29:46.282544374 +0300
  7945. @@ -89,7 +89,7 @@
  7946. char *s; char *r; unsigned int at;
  7947. {
  7948. int f;
  7949. - char *(args[5]);
  7950. + char *(args[5]), *ptr;
  7951. args[0] = (char *)"qmail-remote";
  7952. args[1] = r + at + 1;
  7953. @@ -102,7 +102,10 @@
  7954. if (fd_move(0,fdmess) == -1) _exit(111);
  7955. if (fd_move(1,fdout) == -1) _exit(111);
  7956. if (fd_copy(2,1) == -1) _exit(111);
  7957. - execvp(*args,args);
  7958. + if(!(ptr = env_get("QMAILREMOTE")))
  7959. + execvp(*args, args);
  7960. + else
  7961. + execvp(ptr, args);
  7962. if (error_temp(errno)) _exit(111);
  7963. _exit(100);
  7964. }
  7965. diff -Naur qmail-1.03.org/qregex.c qmail-1.03/qregex.c
  7966. --- qmail-1.03.org/qregex.c 1970-01-01 05:30:00.000000000 +0530
  7967. +++ qmail-1.03/qregex.c 2009-04-21 11:19:07.000000000 +0530
  7968. @@ -0,0 +1,239 @@
  7969. +/*
  7970. + * $Log: qregex.c,v $
  7971. + * Revision 1.13 2007-12-20 13:51:04+05:30 Cprogrammer
  7972. + * removed compiler warning
  7973. + *
  7974. + * Revision 1.12 2005-08-23 17:41:36+05:30 Cprogrammer
  7975. + * regex to be turned on only of QREGEX is defined to non-zero value
  7976. + *
  7977. + * Revision 1.11 2005-04-02 19:07:25+05:30 Cprogrammer
  7978. + * use internal wildmat version
  7979. + *
  7980. + * Revision 1.10 2005-01-22 00:39:04+05:30 Cprogrammer
  7981. + * added missing error handling
  7982. + *
  7983. + * Revision 1.9 2004-10-22 20:29:45+05:30 Cprogrammer
  7984. + * added RCS id
  7985. + *
  7986. + * Revision 1.8 2004-09-21 23:48:18+05:30 Cprogrammer
  7987. + * made matchregex() visible
  7988. + * introduced dotChar (configurable dot char)
  7989. + *
  7990. + * Revision 1.7 2004-02-05 18:48:48+05:30 Cprogrammer
  7991. + * changed curregex to static
  7992. + *
  7993. + * Revision 1.6 2003-12-23 23:22:53+05:30 Cprogrammer
  7994. + * implicitly use wildcard if address starts with '@'
  7995. + *
  7996. + * Revision 1.5 2003-12-22 18:33:12+05:30 Cprogrammer
  7997. + * added address_match()
  7998. + *
  7999. + * Revision 1.4 2003-12-22 13:21:08+05:30 Cprogrammer
  8000. + * added text and pattern as part of error message
  8001. + *
  8002. + * Revision 1.3 2003-12-22 10:04:04+05:30 Cprogrammer
  8003. + * conditional compilation of qregex
  8004. + *
  8005. + * Revision 1.2 2003-12-21 15:32:18+05:30 Cprogrammer
  8006. + * added regerror
  8007. + *
  8008. + * Revision 1.1 2003-12-20 13:17:16+05:30 Cprogrammer
  8009. + * Initial revision
  8010. + *
  8011. + * qregex (v2)
  8012. + * $Id: qregex.c,v 1.13 2007-12-20 13:51:04+05:30 Cprogrammer Stab mbhangui $
  8013. + *
  8014. + * Author : Evan Borgstrom (evan at unixpimps dot org)
  8015. + * Created : 2001/12/14 23:08:16
  8016. + * Modified: $Date: 2007-12-20 13:51:04+05:30 $
  8017. + * Revision: $Revision: 1.13 $
  8018. + *
  8019. + * Do POSIX regex matching on addresses for anti-relay / spam control.
  8020. + * It logs to the maillog
  8021. + * See the qregex-readme file included with this tarball.
  8022. + * If you didn't get this file in a tarball please see the following URL:
  8023. + * http://www.unixpimps.org/software/qregex
  8024. + *
  8025. + * qregex.c is released under a BSD style copyright.
  8026. + * See http://www.unixpimps.org/software/qregex/copyright.html
  8027. + *
  8028. + * Note: this revision follows the coding guidelines set forth by the rest of
  8029. + * the qmail code and that described at the following URL.
  8030. + * http://cr.yp.to/qmail/guarantee.html
  8031. + *
  8032. + */
  8033. +#include "case.h"
  8034. +#include "scan.h"
  8035. +#include "stralloc.h"
  8036. +#include "constmap.h"
  8037. +#include "substdio.h"
  8038. +#include "byte.h"
  8039. +#include "env.h"
  8040. +#include <sys/types.h>
  8041. +#include <regex.h>
  8042. +#include <unistd.h>
  8043. +
  8044. +static int wildmat_match(stralloc *, int, struct constmap *, int, stralloc *);
  8045. +static int regex_match(stralloc *, int, stralloc *);
  8046. +int wildmat_internal(char *, char *);
  8047. +
  8048. +static char sserrbuf[512];
  8049. +static substdio sserr = SUBSTDIO_FDBUF(write, 2, sserrbuf, sizeof(sserrbuf));
  8050. +static char dotChar = '@';
  8051. +
  8052. +int
  8053. +address_match(stralloc *addr, int bhfok, stralloc *bhf,
  8054. + struct constmap *mapbhf, int bhpok, stralloc *bhp)
  8055. +{
  8056. + char *ptr;
  8057. + int x = 0;
  8058. +
  8059. + case_lowerb(addr->s, addr->len); /*- convert into lower case */
  8060. + if ((ptr = env_get("QREGEX")))
  8061. + scan_int(ptr, &x);
  8062. + if (ptr && x)
  8063. + return (regex_match(addr, bhfok, bhf));
  8064. + else
  8065. + return (wildmat_match(addr, bhfok, mapbhf, bhpok, bhp));
  8066. +}
  8067. +
  8068. +int
  8069. +matchregex(char *text, char *regex)
  8070. +{
  8071. + regex_t qreg;
  8072. + char errbuf[512];
  8073. + int retval = 0;
  8074. +
  8075. +#define REGCOMP(X,Y) regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
  8076. + /*- build the regex */
  8077. + if ((retval = REGCOMP(qreg, regex)) != 0)
  8078. + {
  8079. + regerror(retval, &qreg, errbuf, sizeof(errbuf));
  8080. + regfree(&qreg);
  8081. + if (substdio_puts(&sserr, text) == -1)
  8082. + return (-retval);
  8083. + if (substdio_puts(&sserr, ": ") == -1)
  8084. + return (-retval);
  8085. + if (substdio_puts(&sserr, regex) == -1)
  8086. + return (-retval);
  8087. + if (substdio_puts(&sserr, ": ") == -1)
  8088. + return (-retval);
  8089. + if (substdio_puts(&sserr, errbuf) == -1)
  8090. + return (-retval);
  8091. + if (substdio_puts(&sserr, "\n") == -1)
  8092. + return (-retval);
  8093. + if (substdio_flush(&sserr) == -1)
  8094. + return (-retval);
  8095. + return (-retval);
  8096. + }
  8097. + /*- execute the regex */
  8098. +#define REGEXEC(X,Y) regexec(&X, Y, (size_t) 0, (regmatch_t *) 0, (int) 0)
  8099. + retval = REGEXEC(qreg, text);
  8100. + regfree(&qreg);
  8101. + return (retval == REG_NOMATCH ? 0 : 1);
  8102. +}
  8103. +
  8104. +static int
  8105. +wildmat_match(stralloc * addr, int mapfile, struct constmap *ptrmap, int patfile, stralloc *wildcard)
  8106. +{
  8107. + int i = 0;
  8108. + int j = 0;
  8109. + int k = 0;
  8110. + char subvalue;
  8111. +
  8112. + if (mapfile)
  8113. + {
  8114. + if (constmap(ptrmap, addr->s, addr->len - 1))
  8115. + return 1;
  8116. + if ((j = byte_rchr(addr->s, addr->len, dotChar)) < addr->len)
  8117. + {
  8118. + if (constmap(ptrmap, addr->s + j, addr->len - j - 1))
  8119. + return 1;
  8120. + }
  8121. + }
  8122. + /*- Include control file control/xxxxpatterns and evaluate with Wildmat check */
  8123. + if (patfile && wildcard)
  8124. + {
  8125. + i = 0;
  8126. + for (j = 0; j < wildcard->len; ++j)
  8127. + {
  8128. + if (!wildcard->s[j])
  8129. + {
  8130. + subvalue = wildcard->s[i] != '!';
  8131. + if (!subvalue)
  8132. + i++;
  8133. + if ((k != subvalue) && wildmat_internal(addr->s, wildcard->s + i))
  8134. + k = subvalue;
  8135. + i = j + 1;
  8136. + }
  8137. + }
  8138. + return k;
  8139. + }
  8140. + return (0);
  8141. +}
  8142. +
  8143. +static int
  8144. +regex_match(stralloc * addr, int mapfile, stralloc *map)
  8145. +{
  8146. + int i = 0;
  8147. + int j = 0;
  8148. + int k = 0;
  8149. + int negate = 0, match;
  8150. + static stralloc curregex = { 0 };
  8151. +
  8152. + match = 0;
  8153. + if (mapfile)
  8154. + {
  8155. + while (j < map->len)
  8156. + {
  8157. + i = j;
  8158. + while ((map->s[i] != '\0') && (i < map->len))
  8159. + i++;
  8160. + if (map->s[j] == '!')
  8161. + {
  8162. + negate = 1;
  8163. + j++;
  8164. + }
  8165. + if (*(map->s + j) == dotChar)
  8166. + {
  8167. + if (!stralloc_copys(&curregex, ".*"))
  8168. + return(-1);
  8169. + if (!stralloc_catb(&curregex, map->s + j, (i - j)))
  8170. + return(-1);
  8171. + } else
  8172. + if (!stralloc_copyb(&curregex, map->s + j, (i - j)))
  8173. + return(-1);
  8174. + if (!stralloc_0(&curregex))
  8175. + return(-1);
  8176. + if((k = matchregex(addr->s, curregex.s)) == 1)
  8177. + {
  8178. + if (negate)
  8179. + return(0);
  8180. + match = 1;
  8181. + }
  8182. + j = i + 1;
  8183. + negate = 0;
  8184. + }
  8185. + }
  8186. + return (match);
  8187. +}
  8188. +
  8189. +void
  8190. +setdotChar(c)
  8191. + char c;
  8192. +{
  8193. + dotChar = c;
  8194. + return;
  8195. +}
  8196. +
  8197. +void
  8198. +getversion_qregex_c()
  8199. +{
  8200. + static char *x = "$Id: qregex.c,v 1.13 2007-12-20 13:51:04+05:30 Cprogrammer Stab mbhangui $";
  8201. +
  8202. +#ifdef INDIMAIL
  8203. + x = sccsidh;
  8204. +#else
  8205. + x++;
  8206. +#endif
  8207. +}
  8208. diff -Naur qmail-1.03.org/qregex.h qmail-1.03/qregex.h
  8209. --- qmail-1.03.org/qregex.h 1970-01-01 05:30:00.000000000 +0530
  8210. +++ qmail-1.03/qregex.h 2009-04-21 11:19:07.000000000 +0530
  8211. @@ -0,0 +1,24 @@
  8212. +/*
  8213. + * $Log: qregex.h,v $
  8214. + * Revision 1.3 2004-09-21 23:49:02+05:30 Cprogrammer
  8215. + * added matchregex() and setdotChar()
  8216. + *
  8217. + * Revision 1.2 2003-12-22 18:35:26+05:30 Cprogrammer
  8218. + * added address_match() function
  8219. + *
  8220. + * Revision 1.1 2003-12-20 13:17:45+05:30 Cprogrammer
  8221. + * Initial revision
  8222. + *
  8223. + */
  8224. +/*
  8225. + * simple header file for the matchregex prototype
  8226. + */
  8227. +#ifndef _QREGEX_H_
  8228. +#define _QREGEX_H_
  8229. +#include "constmap.h"
  8230. +#include "stralloc.h"
  8231. +
  8232. +int address_match(stralloc *, int, stralloc *, struct constmap *, int, stralloc *);
  8233. +int matchregex(char *, char *);
  8234. +void setdotChar(char);
  8235. +#endif
  8236. --- qmail-1.03.orig/scan_ulong.c 2009-10-15 20:38:24.150352000 +0300
  8237. +++ qmail-1.03/scan_ulong.c 2009-10-16 00:40:58.551137909 +0300
  8238. @@ -9,3 +9,43 @@
  8239. { result = result * 10 + c; ++pos; }
  8240. *u = result; return pos;
  8241. }
  8242. +
  8243. +unsigned int
  8244. +scan_int(s, i)
  8245. + register char *s;
  8246. + register int *i;
  8247. +{
  8248. + register unsigned int pos;
  8249. + register int result;
  8250. + register unsigned char c;
  8251. + int sign;
  8252. +
  8253. + pos = 0;
  8254. + result = 0;
  8255. + sign = 1;
  8256. + /*-
  8257. + * determine sign of the number
  8258. + */
  8259. + switch (s[0])
  8260. + {
  8261. + case '\0':
  8262. + return 0;
  8263. + case '-':
  8264. + ++pos;
  8265. + sign = -1;
  8266. + break;
  8267. + case '+':
  8268. + ++pos;
  8269. + sign = 1;
  8270. + break;
  8271. + default:
  8272. + break;
  8273. + }
  8274. + while ((c = (unsigned char)(s[pos] - '0')) < 10)
  8275. + {
  8276. + result = result * 10 + c;
  8277. + ++pos;
  8278. + }
  8279. + *i = result * sign;
  8280. + return pos;
  8281. +}
  8282. diff -Naur qmail-1.03.org/softwarelicense1-1.html qmail-1.03/softwarelicense1-1.html
  8283. --- qmail-1.03.org/softwarelicense1-1.html 1970-01-01 05:30:00.000000000 +0530
  8284. +++ qmail-1.03/softwarelicense1-1.html 2009-04-21 11:19:07.000000000 +0530
  8285. @@ -0,0 +1,59 @@
  8286. +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  8287. +<html>
  8288. +<head>
  8289. +<title>Yahoo! DomainKeys Public License Agreement v1.0</title>
  8290. +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  8291. +</head>
  8292. +
  8293. +<body>
  8294. +Yahoo! DomainKeys Public License Agreement v1.1<br>
  8295. +(this &quot;Agreement&quot;)
  8296. +<p>Copyright (c) 2004, Yahoo! Inc.<br>
  8297. + All rights reserved.</p>
  8298. +
  8299. +<br>
  8300. +<a href=http://domainkeys.sourceforge.net/license/softwarelicense1-1.html>(Available online)</a>
  8301. +<br>
  8302. +
  8303. +
  8304. +<p>This Agreement is between Licensor and You. You agree to be bound by all the terms and conditions set forth below, and, subject to those terms and conditions, You may use the intellectual property described below. </p>
  8305. +<p>1. LICENSE GRANT. </p>
  8306. +<p>1.1. Subject to the terms and conditions of this Agreement, each DomainKeys Developer hereby grants You a royalty-free, perpetual, worldwide, sublicensable, non-exclusive license to use, reproduce, modify, publicly display, publicly perform, and distribute the Licensed Code.</p>
  8307. +<p>1.2. Subject to the terms and conditions of this Agreement, Licensor hereby grants You a royalty-free, perpetual, worldwide, sublicensable, non-exclusive license under its rights to the Yahoo! Patent Claims to make, use, sell, offer for sale, and/or import the Licensed Code for the sole purpose of implementing a sender verification solution in connection with e-mail. </p>
  8308. +<p>2. DEFINITIONS. </p>
  8309. +<p>2.1. &quot;Contributions&quot; means any modifications to the Licensed Code, and/or any portions thereof, that are distributed under this Agreement. A Contribution includes, without limitation, any addition to or deletion from the contents of a file containing any Licensed Code, or any new file that contains any part of the Licensed Code.</p>
  8310. +<p>2.2. &quot;DomainKeys Developer(s)&quot; means Yahoo, Inc. (&quot;Yahoo!&quot;), Licensor, and/or any other individual or entity who distributes code under this Agreement.</p>
  8311. +<p>2.3. &quot;Licensed Code&quot; means the Original Code, any Contributions (whether made by You or any DomainKeys Developer other than You), and the combination of Original Code and any such Contributions.</p>
  8312. +<p>2.4. &quot;Licensor&quot; means Yahoo! or any other individual or entity that elects to use this Agreement to license intellectual property to any licensee.</p>
  8313. +<p>2.5. &quot;Original Code&quot; means the source code and binary code that is based on the Specifications and distributed by or on behalf of Yahoo! under this Agreement for the sole purpose of implementing a sender verification solution in connection with e-mail, including any updates or upgrades to such code made available by Yahoo!.</p>
  8314. +<p>2.6. &quot;Specifications&quot; means the specification having submission ID &quot;draft-delany-domainkeys-base-01.txt&quot; dated Aug 2004 published through the IETF (Internet Engineering Task Force). The Specifications may be found at the following link: <br>
  8315. +<a href="http://antispam.yahoo.com/domainkeys/draft-delany-domainkeys-base-02.txt">http://antispam.yahoo.com/domainkeys/draft-delany-domainkeys-base-02.txt</a></p>
  8316. +<p>
  8317. + 2.7. &quot;Yahoo! Patent Claims&quot; shall mean those claims of all Yahoo! foreign and domestic patents and patent applications that base their priority on U.S. Provisional Patent Application Ser. Nos. 60/497,794, filed Aug. 26, 2003, or 60/553,300, filed Mar. 15, 2004, or U.S. Patent Application Ser. Nos. 10/671,319, filed Sep. 24, 2003, or 10/805,181, filed Mar. 19, 2004. </p>
  8318. +<p>2.8. &quot;You&quot; or &quot;Your&quot; means an individual, company, or other legal entity exercising any rights under this Agreement. Any individual who accepts the terms and conditions of this Agreement on behalf of a company or other legal entity represents and warrants that the individual has the authority to enter into this Agreement on behalf of the company or other legal entity. </p>
  8319. +<p>3. TERMS. </p>
  8320. +<p>3.1. You agree not to assert against Yahoo!, any other DomainKeys Developer or any of their respective licensees under Section 3.4, a patent infringement claim based on the manufacture, use, sale, offer for sale and/or importation of any of the specific portions of a hardware or software implementation expressly required to be compliant with the Specifications for the sole purpose of implementing a sender verification solution in connection with e-mail (&quot;Licensed Code IP Claim&quot;).</p>
  8321. +<p>3.2. To indicate your assent to the terms and conditions of this Agreement and in order to obtain a license to use, reproduce, modify, publicly display, publicly perform, distribute, and sublicense Licensed Code, You must:</p>
  8322. +<p>(a) include, attach or preserve the following prominently displayed statement in the Licensed Code: &quot;This code incorporates intellectual property owned by Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License Agreement.&quot;; </p>
  8323. +<p>(b) preserve the copyright and other proprietary notices and disclaimers of DomainKeys Developers as they appear in the Licensed Code; and </p>
  8324. +<p>(c) if the Licensed Code developed by You is distributed in source form, You must identify Yourself, in the source code of such Licensed Code, as the originator of any modifications in a manner that reasonably allows subsequent DomainKeys Developers or their licensees to identify the originator of the modifications.</p>
  8325. +<p>3.3. You will not use the name of Yahoo! to endorse or promote any products, services, or Licensed Code without specific prior written permission of Yahoo!. &quot;DomainKeys&quot; is a trademark of Yahoo!. However, You may state Your Licensed Code is &quot;DomainKeys compliant&quot;, &quot;supports DomainKeys&quot;, or is &quot;DomainKeys-enabled&quot;, without citation to Yahoo!. You must create Your own product or service names or trademarks for Your Licensed Code and You agree not to use the term &quot;DomainKeys&quot; in or as part of a name or trademark for Your Licensed Code.</p>
  8326. +<p>3.4. You may choose to distribute Licensed Code or modifications under this Agreement or a different agreement, provided that:</p>
  8327. +<p>(a) a copy of this Agreement or the different agreement is included with each copy of the Licensed Code or modifications along with the following prominently displayed statement: &quot;By using, reproducing, modifying, publicly displaying, publicly performing, distributing, and/or sublicensing this code as permitted, you agree to the terms and conditions of the Yahoo! DomainKeys Public License Agreement or other agreement contained herein.&quot;; and</p>
  8328. +<p>(b) if distributed under a different agreement, such different agreement contains terms and conditions that (i) provide no fewer rights, privileges and immunities to DomainKeys Developers than the terms and conditions of this Agreement, including, without limitation, Sections 1.2, 3.1, 3.4, 3.7, 4.1, 4.2, and 4.3, except that You may alter the terms and conditions of Section 1.1 and (ii) apply such terms and conditions to the Licensed Code and/or modifications made by You.</p>
  8329. +<p>3.5. You acknowledge that Licensed Code may be subject to U.S. export restriction and other applicable national and international laws. You agree to comply with all export, re-export, or import restrictions, laws, or regulations. </p>
  8330. +<p>3.6. Yahoo!, and only Yahoo!, may, from time to time and at its sole discretion, update or modify the terms of this Agreement. If Yahoo! makes any such modifications, You may continue under the terms and conditions of this Agreement or agree to the updated or modified terms and conditions. For the most recent version of this Agreement please contact Yahoo!.</p>
  8331. +<p>3.7. This Agreement and the rights hereunder will terminate: <br>
  8332. + (a) automatically without notice from Yahoo!, if You at any time during the term of this Agreement assert any Licensed Code IP Claim against Yahoo!; </p>
  8333. +<p>(b) upon written notice from Yahoo!, if You at any time during the term of this Agreement assert any Licensed Code IP Claim against any DomainKeys Developer (other than Yahoo!) or any licensees of any DomainKeys Developer; or </p>
  8334. +<p>(c) where (a) or (b) do not apply, automatically without notice from Yahoo!, if You fail to comply with any term(s) of this Agreement and fail to cure such breach within 30 days of You becoming aware of such breach. </p>
  8335. +<p>3.8. This Agreement constitutes the entire agreement between the parties with respect to the subject matter hereof. This Agreement shall be governed by and construed under the laws of the United States and the State of California without giving effect to California conflict of law provisions or to construction provisions favoring either party. All actions arising out of or relating to this Agreement that involve Yahoo! as a party will be adjudicated exclusively by the Superior Court of the State of California for the County of Santa Clara or the United States District Court for the Northern District of California. </p>
  8336. +<p>3.9. In the event that any provision of this Agreement is deemed to be invalid, such invalidity shall not affect the remainder of this Agreement.</p>
  8337. +<p>4. <b>LEGAL DISCLAIMERS. </b></p>
  8338. +<p>4.1. <b>THE YAHOO! PATENT CLAIMS, THIS AGREEMENT, LICENSED CODE, THE DOMAINKEYS TRADEMARK, AND THE SPECIFICATIONS ARE PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.</b> You are solely responsible for determining the appropriateness of exercising any rights under this Agreement and using the Specifications, Licensed Code, and the DomainKeys trademark and assume all risks associated in connection therewith, including, but not limited to, the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. </p>
  8339. +<p>4.2. You expressly acknowledge and agree that no assurances are provided by DomainKeys Developers with respect to the validity of the Yahoo! Patent Claims or that the Specifications, Licensed Code, the DomainKeys trademark or any implementations related to the Specifications, Licensed Code or the DomainKeys trademark do not infringe or misappropriate the patent, trademark or other intellectual property rights of any other entity. DomainKeys Developers disclaim any liability to You for claims brought by any other person or entity based on infringement or misappropriation of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, You hereby assume sole responsibility to secure any other intellectual property rights needed. </p>
  8340. +<p>4.3. <b>DOMAINKEYS DEVELOPERS SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE EXERCISE OF ANY RIGHTS UNDER THIS AGREEMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, AND EVEN IF THE REMEDIES PROVIDED FOR IN THIS AGREEMENT FAIL OF THEIR ESSENTIAL PURPOSE.</b></p>
  8341. +
  8342. +</body>
  8343. +</html>
  8344. +
  8345. diff -Naur qmail-1.03.org/spawn-filter.9 qmail-1.03/spawn-filter.9
  8346. --- qmail-1.03.org/spawn-filter.9 1970-01-01 05:30:00.000000000 +0530
  8347. +++ qmail-1.03/spawn-filter.9 2009-04-21 11:19:07.000000000 +0530
  8348. @@ -0,0 +1,103 @@
  8349. +.TH spawn-filter 8
  8350. +.SH NAME
  8351. +spawn-filter \- Helper for running filters for qmail-local and qmail-remote
  8352. +.SH SYNOPSIS
  8353. +.B spawn-filter args
  8354. +.SH DESCRIPTION
  8355. +.B spawn-filter
  8356. +is a utility to help qmail run any filter during local or remote delivery. It
  8357. +can run any filter which expects to read mess on fd 0 and writes back the message on fd 1.
  8358. +The filter can be turned on individually for local and remote mails by defining
  8359. +.B QMAILLOCAL
  8360. +and
  8361. +.B QMAILREMOTE
  8362. +environment variables respectively in
  8363. +.B qmail-send
  8364. +supervise or rc script. If spawn-filter is invoked as qmail-local, it executes the
  8365. +original
  8366. +.B qmail-local
  8367. +after runing the mail through the filter. If spawn-filter is invoked as qmail-remote, it
  8368. +executes the original
  8369. +.B qmail-remote
  8370. +after running the mail through the filter. Hence QMAILLOCAL should be set as QMAILHOME/bin/spawn-filter
  8371. +for filtering local mails and QMAILREMOTE as QMAILHOME/bin/spawn-filter for filtering
  8372. +remote mails.
  8373. +
  8374. +Filters can be run by setting the environment variable
  8375. +.B FILTERARGS
  8376. +or by using a control file
  8377. +.BR filterargs.
  8378. +The environment variable overrides the control file.
  8379. +.B spawn-filter
  8380. +uses /bin/sh to run the filter (with arguments) specified by the FILTERARGS environment variable or the control file
  8381. +.BR filterargs .
  8382. +The environment variable FILTERARGS apply to both local and remote mails. For individual domain level control,
  8383. +it is best to set using the control file filterargs.
  8384. +
  8385. +.TP 5
  8386. +.I filterargs
  8387. +The format of this file is of the form
  8388. +.B domain:args
  8389. +for both local and remote mails.
  8390. +.B domain:remote:args
  8391. +for remote mails and
  8392. +.B domain:local:args
  8393. +for local mails.
  8394. +
  8395. +.EX
  8396. +indimail.org:remote:QMAILHOME/bin/dk-filter
  8397. +.EE
  8398. +
  8399. +.TP 0
  8400. +The sequence in which the filter program is run is given below
  8401. +
  8402. +.TP 5
  8403. +1. create two pipes and fork
  8404. +.TP 5
  8405. +2. dup write end of the first pipe to descriptor 1, dup write end of the second pipe to descriptor 2 in the child and exec the filter program
  8406. +.TP 5
  8407. +3. dup read end of the pipe to descriptor 0 in parent and exec qmail-local for local mails and qmail-remote for remote mails.
  8408. +.TP 5
  8409. +4. Wait for filter to exit and read read end of second pipe for any error messages.
  8410. +.TP 5
  8411. +5. Report success or failure
  8412. +.TP 0
  8413. +
  8414. +This gives the ability for the any filter program to read the mail message from descriptor 0 before
  8415. +passing it to qmail-local/qmail-remote through the pipe.
  8416. +
  8417. +.B spawn-filter
  8418. +will attempt to make the descriptor 0 seekable if the environment variable MAKE_SEEKABLE
  8419. +is defined. This may be necessary for certain filter programs which could do lseek().
  8420. +
  8421. +.B spawn-filter
  8422. +sets the environment variable
  8423. +.B DOMAIN
  8424. +to the recipient domain. This can be conveniently used in programs/scripts which get invoked by
  8425. +setting
  8426. +.B FILTERARGS
  8427. +environment variable or by rules in the control file
  8428. +.BR filterargs .
  8429. +
  8430. +.SH "EXIT CODES"
  8431. +.B spawn-filter
  8432. +exits 111 for any error or if it is not able to exec
  8433. +QMAILHOME/bin/qmail-local (for local mails) or
  8434. +QMAILHOME/bin/qmail-remote (for remote mails).
  8435. +
  8436. +.SH "SEE ALSO"
  8437. +qmail-lspawn(8),
  8438. +qmail-rspawn(8),
  8439. +qmail-local(8),
  8440. +qmail-remote(8),
  8441. +qmail-smtpd(8),
  8442. +qmail-control(5),
  8443. +qmail-queue(8)
  8444. +
  8445. +.SH "AUTHORS"
  8446. +
  8447. +Manvendra Bhangui.
  8448. +.SH PROBLEMS
  8449. +Problems with
  8450. +.B spawn-filter
  8451. +should be forwarded to "Manvendra Bhangui" <mbhangui@gmail.com>
  8452. diff -Naur qmail-1.03.org/spawn-filter.c qmail-1.03/spawn-filter.c
  8453. --- qmail-1.03.org/spawn-filter.c 1970-01-01 05:30:00.000000000 +0530
  8454. +++ qmail-1.03/spawn-filter.c 2009-04-21 11:19:07.000000000 +0530
  8455. @@ -0,0 +1,456 @@
  8456. +/*
  8457. + * qmail-version without spam filter
  8458. + *
  8459. + * $Log: spawn-filter.c,v $
  8460. + * Revision 1.41 2009-04-03 11:42:48+05:30 Cprogrammer
  8461. + * create pipe for error messages
  8462. + *
  8463. + * Revision 1.40 2009-04-02 15:17:54+05:30 Cprogrammer
  8464. + * unset QMAILLOCAL in qmail-remote and unset QMAILREMOTE in qmail-local
  8465. + *
  8466. + * Revision 1.39 2008-06-12 08:40:55+05:30 Cprogrammer
  8467. + * added rulesfile argument
  8468. + *
  8469. + * Revision 1.38 2008-05-25 17:16:43+05:30 Cprogrammer
  8470. + * made message more readable by adding a blank space
  8471. + *
  8472. + * Revision 1.37 2007-12-20 13:51:54+05:30 Cprogrammer
  8473. + * avoid loops with FILTERARGS, SPAMFILTERARGS
  8474. + * removed compiler warning
  8475. + *
  8476. + * Revision 1.36 2006-06-07 14:11:28+05:30 Cprogrammer
  8477. + * added SPAMEXT, SPAMHOST, SPAMSENDER, QQEH environment variable
  8478. + * unset FILTERARGS before calling filters
  8479. + *
  8480. + * Revision 1.35 2006-01-22 10:14:45+05:30 Cprogrammer
  8481. + * BUG fix for spam mails wrongly getting blackholed
  8482. + *
  8483. + * Revision 1.34 2005-08-23 17:36:48+05:30 Cprogrammer
  8484. + * gcc 4 compliance
  8485. + * delete sender in spam notification
  8486. + *
  8487. + * Revision 1.33 2005-04-02 19:07:47+05:30 Cprogrammer
  8488. + * use internal wildmat version
  8489. + *
  8490. + * Revision 1.32 2004-11-22 19:50:53+05:30 Cprogrammer
  8491. + * include regex.h after sys/types.h to avoid compilation prob on RH 7.3
  8492. + *
  8493. + * Revision 1.31 2004-10-22 20:30:35+05:30 Cprogrammer
  8494. + * added RCS id
  8495. + *
  8496. + * Revision 1.30 2004-10-21 21:56:21+05:30 Cprogrammer
  8497. + * change for two additional arguments to strerr_die()
  8498. + *
  8499. + * Revision 1.29 2004-10-11 14:06:14+05:30 Cprogrammer
  8500. + * use control_readulong instead of control_readint
  8501. + *
  8502. + * Revision 1.28 2004-09-22 23:14:20+05:30 Cprogrammer
  8503. + * replaced atoi() with scan_int()
  8504. + *
  8505. + * Revision 1.27 2004-09-08 10:54:49+05:30 Cprogrammer
  8506. + * incorrect exit code in report() function for remote
  8507. + * mails. Caused qmail-rspawn to report "Unable to run qmail-remote"
  8508. + *
  8509. + * Revision 1.26 2004-07-17 21:23:31+05:30 Cprogrammer
  8510. + * change qqeh code in qmail-remote
  8511. + *
  8512. + * Revision 1.25 2004-07-15 23:40:46+05:30 Cprogrammer
  8513. + * fixed compilation warning
  8514. + *
  8515. + * Revision 1.24 2004-07-02 16:15:25+05:30 Cprogrammer
  8516. + * override control files rejectspam, spamredirect by
  8517. + * environment variables REJECTSPAM and SPAMREDIRECT
  8518. + * allow patterns in domain specification in the control files
  8519. + * spamfilterargs, filterargs, rejectspam and spamredirect
  8520. + *
  8521. + * Revision 1.23 2004-06-03 22:58:34+05:30 Cprogrammer
  8522. + * fixed compilation problem without indimail
  8523. + *
  8524. + * Revision 1.22 2004-05-23 22:18:17+05:30 Cprogrammer
  8525. + * added envrules filename as argument
  8526. + *
  8527. + * Revision 1.21 2004-05-19 23:15:07+05:30 Cprogrammer
  8528. + * added comments
  8529. + *
  8530. + * Revision 1.20 2004-05-12 22:37:47+05:30 Cprogrammer
  8531. + * added check DATALIMIT check
  8532. + *
  8533. + * Revision 1.19 2004-05-03 22:17:36+05:30 Cprogrammer
  8534. + * use QUEUE_BASE instead of auto_qmail
  8535. + *
  8536. + * Revision 1.18 2004-02-13 14:51:24+05:30 Cprogrammer
  8537. + * added envrules
  8538. + *
  8539. + * Revision 1.17 2004-01-20 06:56:56+05:30 Cprogrammer
  8540. + * unset FILTERARGS for notifications
  8541. + *
  8542. + * Revision 1.16 2004-01-20 01:52:08+05:30 Cprogrammer
  8543. + * report string length corrected
  8544. + *
  8545. + * Revision 1.15 2004-01-10 09:44:36+05:30 Cprogrammer
  8546. + * added comment for exit codes of bogofilter
  8547. + *
  8548. + * Revision 1.14 2004-01-08 00:32:49+05:30 Cprogrammer
  8549. + * use TMPDIR environment variable for temporary directory
  8550. + * send spam reports to central spam logger
  8551. + *
  8552. + * Revision 1.13 2003-12-30 00:44:42+05:30 Cprogrammer
  8553. + * set argv[0] from spamfilterprog
  8554. + *
  8555. + * Revision 1.12 2003-12-22 18:34:25+05:30 Cprogrammer
  8556. + * replaced spfcheck() with address_match()
  8557. + *
  8558. + * Revision 1.11 2003-12-20 01:35:06+05:30 Cprogrammer
  8559. + * added wait_pid to prevent zombies
  8560. + *
  8561. + * Revision 1.10 2003-12-17 23:33:39+05:30 Cprogrammer
  8562. + * improved logic for getting remote/local tokens
  8563. + *
  8564. + * Revision 1.9 2003-12-16 10:38:24+05:30 Cprogrammer
  8565. + * fixed incorrect address being returned if filterargs contained local: or
  8566. + * remote: directives
  8567. + *
  8568. + * Revision 1.8 2003-12-15 20:46:19+05:30 Cprogrammer
  8569. + * added case 100 to bounce mail
  8570. + *
  8571. + * Revision 1.7 2003-12-15 13:51:44+05:30 Cprogrammer
  8572. + * code to run additional filters using /bin/sh
  8573. + *
  8574. + * Revision 1.6 2003-12-14 11:36:18+05:30 Cprogrammer
  8575. + * added option to blackhole spammers
  8576. + *
  8577. + * Revision 1.5 2003-12-13 21:08:46+05:30 Cprogrammer
  8578. + * extensive rewrite
  8579. + * common report() function for local/remote mails to report errors
  8580. + *
  8581. + * Revision 1.4 2003-12-12 20:20:55+05:30 Cprogrammer
  8582. + * use -a option to prevent using header addresses
  8583. + *
  8584. + * Revision 1.3 2003-12-09 23:37:16+05:30 Cprogrammer
  8585. + * change for spawn-filter to be called as qmail-local or qmail-remote
  8586. + *
  8587. + * Revision 1.2 2003-12-08 23:48:23+05:30 Cprogrammer
  8588. + * new function getDomainToken() to retrieve domain specific values
  8589. + * read rejectspam and spamredirect only if SPAMEXITCODE is set
  8590. + *
  8591. + * Revision 1.1 2003-12-07 13:02:00+05:30 Cprogrammer
  8592. + * Initial revision
  8593. + *
  8594. + */
  8595. +#include "fmt.h"
  8596. +#include "str.h"
  8597. +#include "strerr.h"
  8598. +#include "env.h"
  8599. +#include "substdio.h"
  8600. +#include "subfd.h"
  8601. +#include "stralloc.h"
  8602. +#include "error.h"
  8603. +#include "control.h"
  8604. +#include "wait.h"
  8605. +#include "qregex.h"
  8606. +#include <regex.h>
  8607. +#include <unistd.h>
  8608. +#include <fcntl.h>
  8609. +
  8610. +#define REGCOMP(X,Y) regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
  8611. +#define REGEXEC(X,Y) regexec(&X, Y, (size_t) 0, (regmatch_t *) 0, (int) 0)
  8612. +
  8613. +static int mkTempFile(int);
  8614. +static void report(int, char *, char *, char *, char *, char *, char *);
  8615. +char *getDomainToken(char *, stralloc *);
  8616. +static int run_mailfilter(char *, char *, char **);
  8617. +int wildmat_internal(char *, char *);
  8618. +
  8619. +static int remotE;
  8620. +
  8621. +static void
  8622. +report(int errCode, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6)
  8623. +{
  8624. + if (!remotE) /*- strerr_die does not return */
  8625. + strerr_die(errCode, s1, s2, s3, s4, s5, s6, 0, 0, (struct strerr *) 0);
  8626. + /*- h - hard, s - soft */
  8627. + if (substdio_put(subfdoutsmall, errCode == 111 ? "s" : "h", 1) == -1)
  8628. + _exit(111);
  8629. + if (s1 && substdio_puts(subfdoutsmall, s1) == -1)
  8630. + _exit(111);
  8631. + if (s2 && substdio_puts(subfdoutsmall, s2) == -1)
  8632. + _exit(111);
  8633. + if (s3 && substdio_puts(subfdoutsmall, s3) == -1)
  8634. + _exit(111);
  8635. + if (s4 && substdio_puts(subfdoutsmall, s4) == -1)
  8636. + _exit(111);
  8637. + if (s5 && substdio_puts(subfdoutsmall, s5) == -1)
  8638. + _exit(111);
  8639. + if (s6 && substdio_puts(subfdoutsmall, s6) == -1)
  8640. + _exit(111);
  8641. + if (substdio_put(subfdoutsmall, "\0", 1) == -1)
  8642. + _exit(111);
  8643. + if (substdio_puts(subfdoutsmall,
  8644. + errCode == 111 ? "Zspawn-filter said: Message deferred" : "DGiving up on spawn-filter\n") == -1)
  8645. + _exit(111);
  8646. + if (substdio_put(subfdoutsmall, "\0", 1) == -1)
  8647. + _exit(111);
  8648. + substdio_flush(subfdoutsmall);
  8649. + /*- For qmail-rspawn to stop complaining unable to run qmail-remote */
  8650. + _exit(0);
  8651. +}
  8652. +
  8653. +static int
  8654. +run_mailfilter(char *domain, char *mailprog, char **argv)
  8655. +{
  8656. + char strnum[FMT_ULONG];
  8657. + pid_t filt_pid;
  8658. + int pipefd[2], pipefe[2];
  8659. + int wstat, filt_exitcode, len = 0;
  8660. + char *filterargs;
  8661. + static stralloc filterdefs = { 0 };
  8662. + static char errstr[1024];
  8663. + char inbuf[1024];
  8664. + char ch;
  8665. + static substdio errbuf;
  8666. +
  8667. + if (!(filterargs = env_get("FILTERARGS")))
  8668. + {
  8669. + if (control_readfile(&filterdefs, "control/filterargs", 0) == -1)
  8670. + report(111, "spawn-filter: Unable to read filterargs: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8671. + filterargs = getDomainToken(domain, &filterdefs);
  8672. + }
  8673. + if (!filterargs)
  8674. + {
  8675. + execv(mailprog, argv);
  8676. + report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
  8677. + _exit(111); /*- To make compiler happy */
  8678. + }
  8679. + if (pipe(pipefd) == -1)
  8680. + report(111, "spawn-filter: Trouble creating pipes: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8681. + if (pipe(pipefe) == -1)
  8682. + report(111, "spawn-filter: Trouble creating pipes: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8683. + switch ((filt_pid = fork()))
  8684. + {
  8685. + case -1:
  8686. + report(111, "spawn-filter: Trouble creating child filter: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8687. + case 0: /*- Filter Program */
  8688. + if (!env_put2("DOMAIN", domain))
  8689. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8690. + /*- Mail content read from fd 0 */
  8691. + if (mkTempFile(0))
  8692. + report(111, "spawn-filter: lseek error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8693. + /*- stdout will go here */
  8694. + if (dup2(pipefd[1], 1) == -1 || close(pipefd[0]) == -1)
  8695. + report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8696. + if (pipefd[1] != 1)
  8697. + close(pipefd[1]);
  8698. + /*- stderr will go here */
  8699. + if (dup2(pipefe[1], 2) == -1 || close(pipefe[0]) == -1)
  8700. + report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8701. + if (pipefe[1] != 2)
  8702. + close(pipefe[1]);
  8703. + /*- Avoid loop if program(s) defined by FILTERARGS call qmail-inject, etc */
  8704. + if (!env_unset("FILTERARGS") || !env_unset("SPAMFILTER"))
  8705. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8706. + execl("/bin/sh", "IndiMailfilter", "-c", filterargs, (char *) 0);
  8707. + report(111, "spawn-filter: could not exec /bin/sh: ", filterargs, ": ", error_str(errno), ". (#4.3.0)", 0);
  8708. + default:
  8709. + close(pipefe[1]);
  8710. + close(pipefd[1]);
  8711. + if (dup2(pipefd[0], 0))
  8712. + {
  8713. + close(pipefd[0]);
  8714. + close(pipefe[0]);
  8715. + wait_pid(&wstat, filt_pid);
  8716. + report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8717. + }
  8718. + if (pipefd[0] != 0)
  8719. + close(pipefd[0]);
  8720. + if (mkTempFile(0))
  8721. + {
  8722. + close(0);
  8723. + close(pipefe[0]);
  8724. + wait_pid(&wstat, filt_pid);
  8725. + report(111, "spawn-filter: lseek error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8726. + }
  8727. + break;
  8728. + }
  8729. + /*- Process message if exit code is 0, bounce if 100 */
  8730. + if (wait_pid(&wstat, filt_pid) != filt_pid)
  8731. + {
  8732. + close(0);
  8733. + close(pipefe[0]);
  8734. + report(111, "spawn-filter: waitpid surprise: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8735. + }
  8736. + if (wait_crashed(wstat))
  8737. + {
  8738. + close(0);
  8739. + close(pipefe[0]);
  8740. + report(111, "spawn-filter: filter crashed: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8741. + }
  8742. + switch (filt_exitcode = wait_exitcode(wstat))
  8743. + {
  8744. + case 0:
  8745. + execv(mailprog, argv);
  8746. + report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
  8747. + case 100:
  8748. + report(100, "Mail Rejected (#5.7.1)", 0, 0, 0, 0, 0);
  8749. + default:
  8750. + substdio_fdbuf(&errbuf, read, pipefe[0], inbuf, sizeof(inbuf));
  8751. + for (len = 0; substdio_bget(&errbuf, &ch, 1) && len < (sizeof(errstr) - 1); len++)
  8752. + errstr[len] = ch;
  8753. + errstr[len] = 0;
  8754. + strnum[fmt_ulong(strnum, filt_exitcode)] = 0;
  8755. + report(111, filterargs, ": (spawn-filter) exit code: ", strnum, *errstr ? ": " : 0, *errstr ? errstr : 0, ". (#4.3.0)");
  8756. + }
  8757. + /*- Not reached */
  8758. + return(111);
  8759. +}
  8760. +
  8761. +char *
  8762. +getDomainToken(char *domain, stralloc *sa)
  8763. +{
  8764. + regex_t qreg;
  8765. + int len, n, retval;
  8766. + char *ptr, *p;
  8767. + char errbuf[512];
  8768. +
  8769. + for (len = 0, ptr = sa->s;len < sa->len;)
  8770. + {
  8771. + len += ((n = str_len(ptr)) + 1);
  8772. + for (p = ptr;*p && *p != ':';p++);
  8773. + if (*p == ':')
  8774. + {
  8775. + *p = 0;
  8776. + /*- build the regex */
  8777. + if ((retval = str_diff(ptr, domain)))
  8778. + {
  8779. + if (env_get("QREGEX"))
  8780. + {
  8781. + if ((retval = REGCOMP(qreg, ptr)) != 0)
  8782. + {
  8783. + regerror(retval, &qreg, errbuf, sizeof(errbuf));
  8784. + regfree(&qreg);
  8785. + report(111, "spawn-filter: ", ptr, ": ", errbuf, ". (#4.3.0)", 0);
  8786. + }
  8787. + retval = REGEXEC(qreg, domain);
  8788. + regfree(&qreg);
  8789. + } else
  8790. + retval = !wildmat_internal(domain, ptr);
  8791. + }
  8792. + if (!retval)
  8793. + {
  8794. + *p = ':';
  8795. + /* check for local/remote directives */
  8796. + if (remotE)
  8797. + {
  8798. + if (!str_diffn(p + 1, "remote:", 7))
  8799. + return (p + 8);
  8800. + if (!str_diffn(p + 1, "local:", 6))
  8801. + return((char *) 0);
  8802. + } else
  8803. + {
  8804. + if (!str_diffn(p + 1, "remote:", 7))
  8805. + return((char *) 0);
  8806. + if (!str_diffn(p + 1, "local:", 6))
  8807. + return (p + 7);
  8808. + }
  8809. + return (p + 1);
  8810. + }
  8811. + *p = ':';
  8812. + }
  8813. + ptr = sa->s + len;
  8814. + }
  8815. + return ((char *) 0);
  8816. +}
  8817. +
  8818. +int
  8819. +mkTempFile(int seekfd)
  8820. +{
  8821. + char inbuf[2048], outbuf[2048], strnum[FMT_ULONG];
  8822. + char *tmpdir;
  8823. + static stralloc tmpFile = {0};
  8824. + struct substdio _ssin;
  8825. + struct substdio _ssout;
  8826. + int fd;
  8827. +
  8828. + if (lseek(seekfd, 0, SEEK_SET) == 0)
  8829. + return (0);
  8830. + if (errno == EBADF)
  8831. + {
  8832. + strnum[fmt_ulong(strnum, seekfd)] = 0;
  8833. + report(111, "spawn-filter: fd ", strnum, ": ", error_str(errno), ". (#4.3.0)", 0);
  8834. + }
  8835. + if (!(tmpdir = env_get("TMPDIR")))
  8836. + tmpdir = "/tmp";
  8837. + if (!stralloc_copys(&tmpFile, tmpdir))
  8838. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8839. + if (!stralloc_cats(&tmpFile, "/qmailFilterXXX"))
  8840. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8841. + if (!stralloc_catb(&tmpFile, strnum, fmt_ulong(strnum, (unsigned long) getpid())))
  8842. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8843. + if (!stralloc_0(&tmpFile))
  8844. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8845. + if ((fd = open(tmpFile.s, O_RDWR | O_EXCL | O_CREAT, 0600)) == -1)
  8846. + report(111, "spawn-filter: ", tmpFile.s, ": ", error_str(errno), ". (#4.3.0)", 0);
  8847. + unlink(tmpFile.s);
  8848. + substdio_fdbuf(&_ssout, write, fd, outbuf, sizeof(outbuf));
  8849. + substdio_fdbuf(&_ssin, read, seekfd, inbuf, sizeof(inbuf));
  8850. + switch (substdio_copy(&_ssout, &_ssin))
  8851. + {
  8852. + case -2: /*- read error */
  8853. + report(111, "spawn-filter: read error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8854. + case -3: /*- write error */
  8855. + report(111, "spawn-filter: write error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8856. + }
  8857. + if (substdio_flush(&_ssout) == -1)
  8858. + report(111, "spawn-filter: write error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8859. + if (dup2(fd, seekfd) == -1)
  8860. + report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8861. + if (lseek(seekfd, 0, SEEK_SET) != 0)
  8862. + report(111, "spawn-filter: lseek: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8863. + return (0);
  8864. +}
  8865. +int
  8866. +main(int argc, char **argv)
  8867. +{
  8868. + char *ptr, *mailprog, *domain;
  8869. + int len;
  8870. +
  8871. + len = str_len(argv[0]);
  8872. + for (ptr = argv[0] + len;*ptr != '/' && ptr != argv[0];ptr--);
  8873. + if (*ptr && *ptr == '/')
  8874. + ptr++;
  8875. + ptr += 6;
  8876. + if (*ptr == 'l') /*- qmail-local Filter */
  8877. + {
  8878. + mailprog = "bin/qmail-local";
  8879. + remotE = 0;
  8880. + domain = argv[7];
  8881. + if (!env_unset("QMAILREMOTE"))
  8882. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8883. + run_mailfilter(domain, mailprog, argv);
  8884. + report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
  8885. + } else
  8886. + if (*ptr == 'r') /*- qmail-remote Filter */
  8887. + {
  8888. + mailprog = "bin/qmail-remote";
  8889. + remotE = 1;
  8890. + domain = argv[1];
  8891. + if (!env_unset("QMAILLOCAL"))
  8892. + report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
  8893. + run_mailfilter(domain, mailprog, argv);
  8894. + report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
  8895. + } else
  8896. + {
  8897. + report(111, "spawn-filter: Incorrect usage. ", argv[0], " (#4.3.0)", 0, 0, 0);
  8898. + _exit(111);
  8899. + }
  8900. + _exit(111);
  8901. + /*- Not reached */
  8902. + return(0);
  8903. +}
  8904. +
  8905. +void
  8906. +getversion_qmail_spawn_filter_c()
  8907. +{
  8908. + static char *x = "$Id: spawn-filter.c,v 1.41 2009-04-03 11:42:48+05:30 Cprogrammer Stab mbhangui $";
  8909. +
  8910. + x++;
  8911. +}
  8912. diff -Naur qmail-1.03.org/str_cpyb.c qmail-1.03/str_cpyb.c
  8913. --- qmail-1.03.org/str_cpyb.c 1970-01-01 05:30:00.000000000 +0530
  8914. +++ qmail-1.03/str_cpyb.c 2009-04-21 11:19:07.000000000 +0530
  8915. @@ -0,0 +1,53 @@
  8916. +/*
  8917. + * $Log: str_cpyb.c,v $
  8918. + * Revision 1.2 2004-10-22 20:30:54+05:30 Cprogrammer
  8919. + * added RCS id
  8920. + *
  8921. + * Revision 1.1 2004-08-15 19:52:35+05:30 Cprogrammer
  8922. + * Initial revision
  8923. + *
  8924. + */
  8925. +#include "str.h"
  8926. +
  8927. +unsigned int
  8928. +str_copyb(s, t, max)
  8929. + register char *s;
  8930. + register char *t;
  8931. + unsigned int max;
  8932. +{
  8933. + register int len;
  8934. +
  8935. + len = 0;
  8936. + while (max-- > 0)
  8937. + {
  8938. + if (!(*s = *t))
  8939. + return len;
  8940. + ++s;
  8941. + ++t;
  8942. + ++len;
  8943. + if (!(*s = *t))
  8944. + return len;
  8945. + ++s;
  8946. + ++t;
  8947. + ++len;
  8948. + if (!(*s = *t))
  8949. + return len;
  8950. + ++s;
  8951. + ++t;
  8952. + ++len;
  8953. + if (!(*s = *t))
  8954. + return len;
  8955. + ++s;
  8956. + ++t;
  8957. + ++len;
  8958. + }
  8959. + return len;
  8960. +}
  8961. +
  8962. +void
  8963. +getversion_str_cpyb_c()
  8964. +{
  8965. + static char *x = "$Id: str_cpyb.c,v 1.2 2004-10-22 20:30:54+05:30 Cprogrammer Stab mbhangui $";
  8966. +
  8967. + x++;
  8968. +}
  8969. --- qmail-1.03.orig/TARGETS 2009-10-15 20:38:22.850353000 +0300
  8970. +++ qmail-1.03/TARGETS 2009-10-15 22:54:27.613351566 +0300
  8971. @@ -381,6 +381,27 @@
  8972. man
  8973. setup
  8974. check
  8975. +qmail-dk
  8976. +qmail-dkim
  8977. +qmail-dkim.o
  8978. +qmail-dk.o
  8979. +libdkim.a
  8980. +dkimbase.o
  8981. +dkimdns.o
  8982. +dkim.o
  8983. +dkimsign.o
  8984. +dkimverify.o
  8985. +dkimtest
  8986. +dkimtest.o
  8987. +qmail-dkim.8
  8988. +qmail-dkim.0
  8989. +str_cpyb.o
  8990. +dkimfuncs.o
  8991. +MakeArgs.o
  8992. +spawn-filter spawn-filter.o qregex.o wildmat.o
  8993. +spawn-filter.8
  8994. +qmail-dk.0 spawn-filter.0
  8995. +dk-filter echo.o echo dk-filter.0 dk-filter.8
  8996. auth_imap
  8997. Makefile.cdb-p
  8998. auth_imap.o
  8999. diff -Naur qmail-1.03.org/wildmat.c qmail-1.03/wildmat.c
  9000. --- qmail-1.03.org/wildmat.c 1970-01-01 05:30:00.000000000 +0530
  9001. +++ qmail-1.03/wildmat.c 2009-04-21 11:19:07.000000000 +0530
  9002. @@ -0,0 +1,173 @@
  9003. +/*-** wildmat.c.orig Wed Dec 3 11:46:31 1997
  9004. + * $Revision: 1.6 $
  9005. + * Do shell-style pattern matching for ?, \, [], and * characters.
  9006. + * Might not be robust in face of malformed patterns; e.g., "foo[a-"
  9007. + * could cause a segmentation violation. It is 8bit clean.
  9008. + *
  9009. + * Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  9010. + * Rich $alz is now <rsalz@osf.org>.
  9011. + * April, 1991: Replaced mutually-recursive calls with in-line code
  9012. + * for the star character.
  9013. + *
  9014. + * Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
  9015. + * This can greatly speed up failing wildcard patterns. For example:
  9016. + * pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
  9017. + * text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
  9018. + * text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
  9019. + * Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
  9020. + * the ABORT code, it takes 22310 calls to fail. Ugh. The following
  9021. + * explanation is from Lars:
  9022. + * The precondition that must be fulfilled is that DoMatch will consume
  9023. + * at least one character in text. This is true if *p is neither '*' no
  9024. + * '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
  9025. + * behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With
  9026. + * FALSE, each star-loop has to run to the end of the text; with ABORT
  9027. + * only the last one does.
  9028. + *
  9029. + * Once the control of one instance of DoMatch enters the star-loop, that
  9030. + * instance will return either TRUE or ABORT, and any calling instance
  9031. + * will therefore return immediately after (without calling recursively
  9032. + * again). In effect, only one star-loop is ever active. It would be
  9033. + * possible to modify the code to maintain this context explicitly,
  9034. + * eliminating all recursive calls at the cost of some complication and
  9035. + * loss of clarity (and the ABORT stuff seems to be unclear enough by
  9036. + * itself). I think it would be unwise to try to get this into a
  9037. + * released version unless you have a good test data base to try it out
  9038. + * on.
  9039. + */
  9040. +#define TRUE 1
  9041. +#define FALSE 0
  9042. +#define ABORT -1
  9043. +
  9044. +
  9045. +/*- What character marks an inverted character class? */
  9046. +#define NEGATE_CLASS '^'
  9047. +/*- Is "*" a common pattern? */
  9048. +#define OPTIMIZE_JUST_STAR
  9049. +/*- Do tar(1) matching rules, which ignore a trailing slash? */
  9050. +#undef MATCH_TAR_PATTERN
  9051. +
  9052. +
  9053. +/*- Match text and p, return TRUE, FALSE, or ABORT. */
  9054. +static int
  9055. +DoMatch(text, p)
  9056. + register char *text;
  9057. + register char *p;
  9058. +{
  9059. + register int last;
  9060. + register int matched;
  9061. + register int reverse;
  9062. +
  9063. + for (; *p; text++, p++)
  9064. + {
  9065. + if (*text == '\0' && *p != '*')
  9066. + return ABORT;
  9067. + switch (*p)
  9068. + {
  9069. + case '\\': /*- Literal match with following character. */
  9070. + p++;
  9071. + /*- FALLTHROUGH */
  9072. + default:
  9073. + if (*text != *p)
  9074. + return FALSE;
  9075. + continue;
  9076. + case '?': /*- Match anything. */
  9077. + continue;
  9078. + case '*':
  9079. + /*- Consecutive stars act just like one. */
  9080. + while (*++p == '*')
  9081. + continue;
  9082. + /*- Trailing star matches everything. */
  9083. + if (*p == '\0')
  9084. + return TRUE;
  9085. + while (*text)
  9086. + if ((matched = DoMatch(text++, p)) != FALSE)
  9087. + return matched;
  9088. + return ABORT;
  9089. + case '[':
  9090. + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  9091. + /*- Inverted character class. */
  9092. + if (reverse)
  9093. + p++;
  9094. + matched = FALSE;
  9095. + if (p[1] == ']' || p[1] == '-')
  9096. + {
  9097. + if (*++p == *text)
  9098. + matched = TRUE;
  9099. + }
  9100. + for (last = *p; *++p && *p != ']'; last = *p)
  9101. + {
  9102. + /*- This next line requires a good C compiler. */
  9103. + if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
  9104. + matched = TRUE;
  9105. + }
  9106. + if (matched == reverse)
  9107. + return FALSE;
  9108. + continue;
  9109. + }
  9110. + }
  9111. +
  9112. +#ifdef MATCH_TAR_PATTERN
  9113. + if (*text == '/')
  9114. + return TRUE;
  9115. +#endif /*- MATCH_TAR_ATTERN */
  9116. + return *text == '\0';
  9117. +}
  9118. +
  9119. +
  9120. +/*- User-level routine. Returns TRUE or FALSE. */
  9121. +int
  9122. +wildmat_internal(text, p)
  9123. + char *text;
  9124. + char *p;
  9125. +{
  9126. +#ifdef OPTIMIZE_JUST_STAR
  9127. + if (p[0] == '*' && p[1] == '\0')
  9128. + return TRUE;
  9129. +#endif /*- OPTIMIZE_JUST_STAR */
  9130. + return DoMatch(text, p) == TRUE;
  9131. +}
  9132. +
  9133. +#if defined(TEST)
  9134. +include < stdio.h >
  9135. +/*- Yes, we use gets not fgets. Sue me. */
  9136. +
  9137. +int
  9138. +main()
  9139. +{
  9140. + char p[80];
  9141. + char text[80];
  9142. +
  9143. + printf("Wildmat tester. Enter pattern, then strings to test.\n");
  9144. + printf("A blank line gets prompts for a new pattern; a blank pattern\n");
  9145. + printf("exits the program.\n");
  9146. + for (;;)
  9147. + {
  9148. + printf("\nEnter pattern: ");
  9149. + (void) fflush(stdout);
  9150. + if (gets(p) == NULL || p[0] == '\0')
  9151. + break;
  9152. + for (;;)
  9153. + {
  9154. + printf("Enter text: ");
  9155. + (void) fflush(stdout);
  9156. + if (gets(text) == NULL)
  9157. + exit(0);
  9158. + /*- Blank line; go back and get a new pattern. */
  9159. + if (text[0] == '\0')
  9160. + break;
  9161. + printf(" %s\n", wildmat_internal(text, p) ? "YES" : "NO");
  9162. + }
  9163. + }
  9164. + exit(0);
  9165. + /*- NOTREACHED */
  9166. +}
  9167. +#endif /*- defined(TEST) */
  9168. +
  9169. +void
  9170. +getversion_wildmat_internal_c()
  9171. +{
  9172. + static char *x = "$Id: wildmat.c,v 1.6 2008-08-03 18:26:33+05:30 Cprogrammer Stab mbhangui $";
  9173. + x++;
  9174. + x--;
  9175. +}
  9176. diff -Naur qmail-1.03.org/strerr.h qmail-1.03/strerr.h
  9177. --- qmail-1.03,orig/strerr.h 2009-10-16 15:12:01.786372335 +0300
  9178. +++ qmail-1.03/strerr.h 2009-10-16 15:12:34.890473181 +0300
  9179. @@ -1,25 +1,32 @@
  9180. +/*
  9181. + * $Log: strerr.h,v $
  9182. + * Revision 1.4 2004-10-21 21:50:27+05:30 Cprogrammer
  9183. + * added strerr_warn8,strerr_warn7,strerr_die8,strerr_die7,strerr_die8sys,strerr_die7sys,
  9184. + * strerr_die8x,strerr_die7x
  9185. + *
  9186. + * Revision 1.3 2004-10-11 14:09:04+05:30 Cprogrammer
  9187. + * added function prototypes
  9188. + *
  9189. + * Revision 1.2 2004-06-18 23:01:58+05:30 Cprogrammer
  9190. + * added RCS log
  9191. + *
  9192. + */
  9193. #ifndef STRERR_H
  9194. #define STRERR_H
  9195. struct strerr
  9196. - {
  9197. - struct strerr *who;
  9198. - const char *x;
  9199. - const char *y;
  9200. - const char *z;
  9201. - }
  9202. -;
  9203. +{
  9204. + struct strerr *who;
  9205. + char *x;
  9206. + char *y;
  9207. + char *z;
  9208. +} ;
  9209. extern struct strerr strerr_sys;
  9210. -extern void strerr_sysinit(void);
  9211. -/* XXX not available in qmail-1.03
  9212. -extern char *strerr();
  9213. -*/
  9214. -extern void strerr_warn(const char *, const char *, const char *,
  9215. - const char *, const char *, const char *, struct strerr *);
  9216. -extern void strerr_die(int, const char *, const char *, const char *,
  9217. - const char *, const char *, const char *, struct strerr *);
  9218. +void strerr_sysinit(void);
  9219. +void strerr_warn(char *, char *, char *, char *, char *, char *, char *, char *, struct strerr *);
  9220. +void strerr_die(int, char *, char *, char *, char *, char *, char *, char *, char *, struct strerr *);
  9221. #define STRERR(r,se,a) \
  9222. { se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; }
  9223. @@ -29,56 +36,72 @@
  9224. #define STRERR_SYS3(r,se,a,b,c) \
  9225. { se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; }
  9226. +#define strerr_warn8(x1,x2,x3,x4,x5,x6,x7,x8,se) \
  9227. +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),(struct strerr *) (se))
  9228. +#define strerr_warn7(x1,x2,x3,x4,x5,x6,x7,se) \
  9229. +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(x7),(char *) 0,(struct strerr *) (se))
  9230. #define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \
  9231. -strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
  9232. +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(char *) 0,(char *) 0,(struct strerr *) (se))
  9233. #define strerr_warn5(x1,x2,x3,x4,x5,se) \
  9234. -strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
  9235. +strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9236. #define strerr_warn4(x1,x2,x3,x4,se) \
  9237. -strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
  9238. +strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9239. #define strerr_warn3(x1,x2,x3,se) \
  9240. -strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9241. +strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9242. #define strerr_warn2(x1,x2,se) \
  9243. -strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9244. +strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9245. #define strerr_warn1(x1,se) \
  9246. -strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9247. +strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9248. +#define strerr_die8(e,x1,x2,x3,x4,x5,x6,x7,x8,se) \
  9249. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7), (x8), (struct strerr *) (se))
  9250. +#define strerr_die7(e,x1,x2,x3,x4,x5,x6,x7,se) \
  9251. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7), (char *) 0, (struct strerr *) (se))
  9252. #define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \
  9253. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
  9254. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(char *) 0, (char *) 0, (struct strerr *) (se))
  9255. #define strerr_die5(e,x1,x2,x3,x4,x5,se) \
  9256. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
  9257. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9258. #define strerr_die4(e,x1,x2,x3,x4,se) \
  9259. -strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
  9260. +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9261. #define strerr_die3(e,x1,x2,x3,se) \
  9262. -strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9263. +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9264. #define strerr_die2(e,x1,x2,se) \
  9265. -strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9266. +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9267. #define strerr_die1(e,x1,se) \
  9268. -strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
  9269. +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) (se))
  9270. +#define strerr_die8sys(e,x1,x2,x3,x4,x5,x6,x7,x8) \
  9271. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7), (x8), &strerr_sys)
  9272. +#define strerr_die7sys(e,x1,x2,x3,x4,x5,x6,x7) \
  9273. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7), (char *) 0, &strerr_sys)
  9274. #define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \
  9275. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys)
  9276. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(char *) 0, (char *) 0, &strerr_sys)
  9277. #define strerr_die5sys(e,x1,x2,x3,x4,x5) \
  9278. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys)
  9279. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(char *) 0, (char *) 0, &strerr_sys)
  9280. #define strerr_die4sys(e,x1,x2,x3,x4) \
  9281. -strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys)
  9282. +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(char *) 0, (char *) 0, &strerr_sys)
  9283. #define strerr_die3sys(e,x1,x2,x3) \
  9284. -strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
  9285. +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, &strerr_sys)
  9286. #define strerr_die2sys(e,x1,x2) \
  9287. -strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
  9288. +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, &strerr_sys)
  9289. #define strerr_die1sys(e,x1) \
  9290. -strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
  9291. +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, &strerr_sys)
  9292. +#define strerr_die8x(e,x1,x2,x3,x4,x5,x6,x7,x8) \
  9293. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8), (struct strerr *) 0)
  9294. +#define strerr_die7x(e,x1,x2,x3,x4,x5,x6,x7) \
  9295. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(x7), (char *) 0, (struct strerr *) 0)
  9296. #define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \
  9297. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0)
  9298. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(char *) 0, (char *) 0, (struct strerr *) 0)
  9299. #define strerr_die5x(e,x1,x2,x3,x4,x5) \
  9300. -strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0)
  9301. +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(char *) 0, (char *) 0, (struct strerr *) 0)
  9302. #define strerr_die4x(e,x1,x2,x3,x4) \
  9303. -strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0)
  9304. +strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) 0)
  9305. #define strerr_die3x(e,x1,x2,x3) \
  9306. -strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
  9307. +strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) 0)
  9308. #define strerr_die2x(e,x1,x2) \
  9309. -strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
  9310. +strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) 0)
  9311. #define strerr_die1x(e,x1) \
  9312. -strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
  9313. +strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0, (char *) 0, (struct strerr *) 0)
  9314. #endif
  9315. diff -Naur qmail-1.03.org/strerr_die.c qmail-1.03/strerr_die.c
  9316. --- qmail-1.03,orig/strerr_die.c 2009-10-16 15:12:01.786372335 +0300
  9317. +++ qmail-1.03/strerr_die.c 2009-10-16 15:12:34.890473181 +0300
  9318. @@ -1,39 +1,85 @@
  9319. +/*
  9320. + * $Log: strerr_die.c,v $
  9321. + * Revision 1.4 2004-10-22 20:30:58+05:30 Cprogrammer
  9322. + * added RCS id
  9323. + *
  9324. + * Revision 1.3 2004-10-21 21:53:02+05:30 Cprogrammer
  9325. + * added two more string args to strerr_warn() and strerr_die()
  9326. + *
  9327. + * Revision 1.2 2004-07-17 21:24:18+05:30 Cprogrammer
  9328. + * added RCS log
  9329. + *
  9330. + */
  9331. #include "substdio.h"
  9332. #include "subfd.h"
  9333. #include "exit.h"
  9334. #include "strerr.h"
  9335. -void strerr_warn(x1,x2,x3,x4,x5,x6,se)
  9336. -const char *x1; const char *x2; const char *x3;
  9337. -const char *x4; const char *x5; const char *x6;
  9338. -struct strerr *se;
  9339. +void
  9340. +strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, se)
  9341. + char *x1;
  9342. + char *x2;
  9343. + char *x3;
  9344. + char *x4;
  9345. + char *x5;
  9346. + char *x6;
  9347. + char *x7;
  9348. + char *x8;
  9349. + struct strerr *se;
  9350. {
  9351. - strerr_sysinit();
  9352. -
  9353. - if (x1) substdio_puts(subfderr,x1);
  9354. - if (x2) substdio_puts(subfderr,x2);
  9355. - if (x3) substdio_puts(subfderr,x3);
  9356. - if (x4) substdio_puts(subfderr,x4);
  9357. - if (x5) substdio_puts(subfderr,x5);
  9358. - if (x6) substdio_puts(subfderr,x6);
  9359. -
  9360. - while(se) {
  9361. - if (se->x) substdio_puts(subfderr,se->x);
  9362. - if (se->y) substdio_puts(subfderr,se->y);
  9363. - if (se->z) substdio_puts(subfderr,se->z);
  9364. - se = se->who;
  9365. - }
  9366. -
  9367. - substdio_puts(subfderr,"\n");
  9368. - substdio_flush(subfderr);
  9369. + strerr_sysinit();
  9370. +
  9371. + if (x1)
  9372. + substdio_puts(subfderr, x1);
  9373. + if (x2)
  9374. + substdio_puts(subfderr, x2);
  9375. + if (x3)
  9376. + substdio_puts(subfderr, x3);
  9377. + if (x4)
  9378. + substdio_puts(subfderr, x4);
  9379. + if (x5)
  9380. + substdio_puts(subfderr, x5);
  9381. + if (x6)
  9382. + substdio_puts(subfderr, x6);
  9383. + if (x7)
  9384. + substdio_puts(subfderr, x7);
  9385. + if (x8)
  9386. + substdio_puts(subfderr, x8);
  9387. + while (se)
  9388. + {
  9389. + if (se->x)
  9390. + substdio_puts(subfderr, se->x);
  9391. + if (se->y)
  9392. + substdio_puts(subfderr, se->y);
  9393. + if (se->z)
  9394. + substdio_puts(subfderr, se->z);
  9395. + se = se->who;
  9396. + }
  9397. + substdio_puts(subfderr, "\n");
  9398. + substdio_flush(subfderr);
  9399. }
  9400. -void strerr_die(e,x1,x2,x3,x4,x5,x6,se)
  9401. -int e;
  9402. -const char *x1; const char *x2; const char *x3;
  9403. -const char *x4; const char *x5; const char *x6;
  9404. -struct strerr *se;
  9405. +void
  9406. +strerr_die(e, x1, x2, x3, x4, x5, x6, x7, x8, se)
  9407. + int e;
  9408. + char *x1;
  9409. + char *x2;
  9410. + char *x3;
  9411. + char *x4;
  9412. + char *x5;
  9413. + char *x6;
  9414. + char *x7;
  9415. + char *x8;
  9416. + struct strerr *se;
  9417. {
  9418. - strerr_warn(x1,x2,x3,x4,x5,x6,se);
  9419. - _exit(e);
  9420. + strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, se);
  9421. + _exit(e);
  9422. +}
  9423. +
  9424. +void
  9425. +getversion_strerr_die_c()
  9426. +{
  9427. + static char *x = "$Id: strerr_die.c,v 1.4 2004-10-22 20:30:58+05:30 Cprogrammer Stab mbhangui $";
  9428. +
  9429. + x++;
  9430. }