pax_global_header00006660000000000000000000000064140564511520014515gustar00rootroot0000000000000052 comment=1d0af244310a66943ab400be56b15a9087f181eb libESMTP-1.1.0/000077500000000000000000000000001405645115200130735ustar00rootroot00000000000000libESMTP-1.1.0/.gitignore000066400000000000000000000003301405645115200150570ustar00rootroot00000000000000*.o *.so build*/ scanbuild*/ _build/ _kdoc/ # it's better to unpack these files and commit the raw source # git has its own built in compression methods *.7z *.dmg *.gz *.iso *.jar *.rar *.tar *.zip *.log *.sqlite libESMTP-1.1.0/COPYING.GPL000066400000000000000000000431311405645115200145510ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libESMTP-1.1.0/INSTALL.md000066400000000000000000000001161405645115200145210ustar00rootroot00000000000000# Installation Installation instructions may be found in `docs/download.md`. libESMTP-1.1.0/LICENSE000066400000000000000000000636361405645115200141160ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libESMTP-1.1.0/README.md000066400000000000000000000022041405645115200143500ustar00rootroot00000000000000# ![logo](docs/pillarbox.png) libESMTP, version 1.1 ## New Version Released All libESMTP users are encouraged to upgrade from version 1.0.6. After more than a decade, libESMTP version 1.0.6 is superceded. Despite proving robust a little bitrot has occurred, especially regarding OpenSSL support. Version 1.1 updates libESMTP without breaking API and ABI compatibility and provides a basis for future development. ## What is libESMTP? **libESMTP** is an SMTP client which manages submission of electronic mail via a preconfigured Mail Transport Agent (MTA) such as [Exim](https://www.exim.org/) or [Postfix](http://www.postfix.org/). libESMTP relieves the developer of the need to handle the complexity of negotiating the SMTP protocol by providing a simple API. Additionally libESMTP transparently handles many SMTP extensions including authentication. Refer to the [libESMTP Documentation](https://libesmtp.github.io/) for further information. ## Licence LibESMTP is licensed under the GNU Lesser General Public License and the example programs are under the GNU General Public Licence. Please refer to LICENSE and COPYING.GPL for full details. libESMTP-1.1.0/api.h000066400000000000000000000023051405645115200140150ustar00rootroot00000000000000#ifndef _api_h #define _api_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This file collates stuff needed by modules defining API functions. */ #define API_CHECK_ARGS(test,ret) \ do \ if (!(test)) { \ return ret; \ } \ while (0) #endif libESMTP-1.1.0/attribute.h000066400000000000000000000022231405645115200152460ustar00rootroot00000000000000#ifndef _attribute_h #define _attribute_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001-2020 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Ignore __attribute__ if compiler is not GCC */ #if !defined (__GNUC__) || __GNUC__ < 2 # define __attribute__(x) #endif #endif libESMTP-1.1.0/auth-client.c000066400000000000000000000317521405645115200154640ustar00rootroot00000000000000/* * This file is part of libESMTP, a library for submission of RFC 5322 * formatted electronic mail messages using the SMTP protocol described * in RFC 4409 and RFC 5321. * * Copyright (C) 2001 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * DOC: Auth Client * * Auth Client * ----------- * * The auth client is a simple SASL implementation supporting the * SMTP AUTH extension. */ #include #include #ifdef USE_PTHREADS #include #endif #include #ifndef DLEXT # define DLEXT ".so" #endif #ifndef RTLD_LAZY # define RTLD_LAZY RTLD_NOW #endif #include #include #include #include #include #include "auth-client.h" #include "auth-plugin.h" #include "api.h" #ifdef USE_PTHREADS static pthread_mutex_t plugin_mutex = PTHREAD_MUTEX_INITIALIZER; #endif struct auth_plugin { struct auth_plugin *next; void *module; const struct auth_client_plugin *info; }; static struct auth_plugin *client_plugins, *end_client_plugins; struct auth_context { int min_ssf; unsigned flags; const struct auth_client_plugin *client; void *plugin_ctx; auth_interact_t interact; void *interact_arg; char *external_id; }; #define mechanism_disabled(p,a,f) \ (((p)->flags & AUTH_PLUGIN_##f) && !((a)->flags & AUTH_PLUGIN_##f)) #if defined AUTHPLUGINDIR # define PLUGIN_DIR AUTHPLUGINDIR "/" #else # define PLUGIN_DIR #endif static char * plugin_name (const char *str) { char *buf, *p; static const char prefix[] = PLUGIN_DIR "sasl-"; assert (str != NULL); buf = malloc (sizeof prefix + strlen (str) + sizeof DLEXT); if (buf == NULL) return NULL; strcpy (buf, prefix); p = buf + sizeof prefix - 1; while (*str != '\0') *p++ = tolower (*str++); strcpy (p, DLEXT); return buf; } static int append_plugin (void *module, const struct auth_client_plugin *info) { struct auth_plugin *auth_plugin; assert (info != NULL); auth_plugin = malloc (sizeof (struct auth_plugin)); if (auth_plugin == NULL) { /* FIXME: propagate an ENOMEM back to the app. */ return 0; } auth_plugin->info = info; auth_plugin->module = module; auth_plugin->next = NULL; if (client_plugins == NULL) client_plugins = auth_plugin; else end_client_plugins->next = auth_plugin; end_client_plugins = auth_plugin; return 1; } static const struct auth_client_plugin * load_client_plugin (const char *name) { void *module; char *plugin; const struct auth_client_plugin *info; assert (name != NULL); /* Try searching for a plugin. */ plugin = plugin_name (name); if (plugin == NULL) return NULL; module = dlopen (plugin, RTLD_LAZY); free (plugin); if (module == NULL) return NULL; info = dlsym (module, "sasl_client"); if (info == NULL || info->response == NULL) { dlclose (module); return NULL; } /* This plugin module is OK. Add it to the list of loaded modules. */ if (!append_plugin (module, info)) { dlclose (module); return NULL; } return info; } /** * auth_client_init() - Initialise the auth client. * * Perform any preparation necessary for the auth client modules. Call this * before any other auth client APIs. */ void auth_client_init (void) { } /** * auth_client_exit() - Destroy the auth client. * * This clears any work done by auth_client_init() or any global state that may * be created by the authentication modules. Auth client APIs after this is * called may fail unpredictably or crash. */ void auth_client_exit (void) { struct auth_plugin *plugin, *next; /* Scan the auth_plugin array and dlclose() the modules */ #ifdef USE_PTHREADS pthread_mutex_lock (&plugin_mutex); #endif for (plugin = client_plugins; plugin != NULL; plugin = next) { next = plugin->next; if (plugin->module != NULL) dlclose (plugin->module); free (plugin); } client_plugins = end_client_plugins = NULL; #ifdef USE_PTHREADS pthread_mutex_unlock (&plugin_mutex); #endif } /** * auth_create_context() - Create an authentication context. * * Create a new authentication context. * * Return: The &typedef auth_context_t. */ auth_context_t auth_create_context (void) { auth_context_t context; context = malloc (sizeof (struct auth_context)); if (context == NULL) return NULL; memset (context, 0, sizeof (struct auth_context)); return context; } /** * auth_destroy_context() - Destroy an authentication context. * @context: The authentication context. * * Destroy an authentication context, releasing any resources used. * * Return: Zero on failure, non-zero on success. */ int auth_destroy_context (auth_context_t context) { API_CHECK_ARGS (context != NULL, 0); if (context->plugin_ctx != NULL) { if (context->client != NULL && context->client->destroy != NULL) (*context->client->destroy) (context->plugin_ctx); } free (context); return 1; } /** * auth_set_mechanism_flags() - Set authentication flags. * @context: The authentication context. * @set: Flags to set. * @clear: Flags to clear. * * Configure authentication mechanism flags which may affect operation of the * authentication modules. The %AUTH_PLUGIN_EXTERNAL flag is excluded from the * allowable flags. * * Return: Zero on failure, non-zero on success. */ int auth_set_mechanism_flags (auth_context_t context, unsigned set, unsigned clear) { API_CHECK_ARGS (context != NULL, 0); context->flags &= AUTH_PLUGIN_EXTERNAL | ~clear; context->flags |= ~AUTH_PLUGIN_EXTERNAL & set; return 1; } /** * auth_set_mechanism_ssf() - Set security factor. * @context: The authentication context. * @min_ssf: The minimum security factor. * * Set the minimum acceptable security factor. The exact meaning of the * security factor depends on the authentication type. * * Return: Zero on failure, non-zero on success. */ int auth_set_mechanism_ssf (auth_context_t context, int min_ssf) { API_CHECK_ARGS (context != NULL, 0); context->min_ssf = min_ssf; return 1; } /** * auth_set_external_id() - Set the external id. * @context: The authentication context. * @identity: Authentication identity. * * Set the authentication identity for the EXTERNAL SASL mechanism. This call * also configures the built-in EXTERNAL authenticator. * * The EXTERNAL mechanism is used in conjunction with authentication which has * already occurred at a lower level in the network stack, such as TLS. For * X.509 the identity is normally that used in the relevant certificate. * * Return: Zero on failure, non-zero on success. */ int auth_set_external_id (auth_context_t context, const char *identity) { static const struct auth_client_plugin external_client = { /* Plugin information */ "EXTERNAL", "SASL EXTERNAL mechanism (RFC 4422)", /* Plugin instance */ NULL, NULL, /* Authentication */ (auth_response_t) 1, AUTH_PLUGIN_EXTERNAL, /* Security Layer */ 0, NULL, NULL, }; struct auth_plugin *plugin; API_CHECK_ARGS (context != NULL, 0); if (context->external_id != NULL) free (context->external_id); if (identity != NULL) { /* Install external module if required */ for (plugin = client_plugins; plugin != NULL; plugin = plugin->next) if (plugin->info->flags & AUTH_PLUGIN_EXTERNAL) break; if (plugin == NULL) { #ifdef USE_PTHREADS pthread_mutex_lock (&plugin_mutex); #endif append_plugin (NULL, &external_client); #ifdef USE_PTHREADS pthread_mutex_unlock (&plugin_mutex); #endif } context->flags |= AUTH_PLUGIN_EXTERNAL; context->external_id = strdup (identity); } else { context->flags &= ~AUTH_PLUGIN_EXTERNAL; context->external_id = NULL; } return 1; } int auth_set_interact_cb (auth_context_t context, auth_interact_t interact, void *arg) { API_CHECK_ARGS (context != NULL, 0); context->interact = interact; context->interact_arg = arg; return 1; } /** * auth_client_enabled() - Check if mechanism is enabled. * @context: The authentication context. * * Perform various checks to ensure SASL is usable. * * Note that this does not check for loaded plugins. This is checked when * negotiating a mechanism with the MTA. * * Return: Non-zero if the SASL is usable, zero otherwise. */ int auth_client_enabled (auth_context_t context) { if (context == NULL) return 0; if (context->interact == NULL) return 0; return 1; } /** * auth_set_mechanism() - Select authentication mechanism. * @context: The authentication context. * @name: Name of the authentication mechanism. * * Perform checks, including acceptable security levels and select * the authentication mechanism if successful. * * Return: Zero on failure, non-zero on success. */ int auth_set_mechanism (auth_context_t context, const char *name) { struct auth_plugin *plugin; const struct auth_client_plugin *info; API_CHECK_ARGS (context != NULL && name != NULL, 0); #ifdef USE_PTHREADS pthread_mutex_lock (&plugin_mutex); #endif /* Get rid of old context */ if (context->plugin_ctx != NULL) { if (context->client != NULL && context->client->destroy != NULL) (*context->client->destroy) (context->plugin_ctx); context->plugin_ctx = NULL; } /* Check the list of already loaded modules. */ info = NULL; for (plugin = client_plugins; plugin != NULL; plugin = plugin->next) if (strcasecmp (name, plugin->info->keyw) == 0) { info = plugin->info; break; } /* Load the module if not found above. */ if (info == NULL && (info = load_client_plugin (name)) == NULL) { #ifdef USE_PTHREADS pthread_mutex_unlock (&plugin_mutex); #endif return 0; } /* Check the application's requirements regarding minimum SSF and whether anonymous or plain text mechanisms are explicitly allowed. This has to be checked here since the list of loaded plugins is global and the plugin may have been acceptable in another context but not in this one. */ if (info->ssf < context->min_ssf || mechanism_disabled (info, context, EXTERNAL) || mechanism_disabled (info, context, ANONYMOUS) || mechanism_disabled (info, context, PLAIN)) { #ifdef USE_PTHREADS pthread_mutex_unlock (&plugin_mutex); #endif return 0; } context->client = info; #ifdef USE_PTHREADS pthread_mutex_unlock (&plugin_mutex); #endif return 1; } const char * auth_mechanism_name (auth_context_t context) { API_CHECK_ARGS (context != NULL && context->client != NULL, NULL); return context->client->keyw; } const char * auth_response (auth_context_t context, const char *challenge, int *len) { API_CHECK_ARGS (context != NULL && context->client != NULL && len != NULL && ((context->client->flags & AUTH_PLUGIN_EXTERNAL) || context->interact != NULL), NULL); if (challenge == NULL) { if (context->plugin_ctx != NULL && context->client->destroy != NULL) (*context->client->destroy) (context->plugin_ctx); if (context->client->init == NULL) context->plugin_ctx = NULL; else if (!(*context->client->init) (&context->plugin_ctx)) return NULL; } if (context->client->flags & AUTH_PLUGIN_EXTERNAL) { *len = strlen (context->external_id); return context->external_id; } assert (context->client->response != NULL); return (*context->client->response) (context->plugin_ctx, challenge, len, context->interact, context->interact_arg); } int auth_get_ssf (auth_context_t context) { API_CHECK_ARGS (context != NULL && context->client != NULL, -1); return context->client->ssf; } void auth_encode (char **dstbuf, int *dstlen, const char *srcbuf, int srclen, void *arg) { auth_context_t context = arg; if (context != NULL && context->client != NULL && context->client->encode != NULL) (*context->client->encode) (context->plugin_ctx, dstbuf, dstlen, srcbuf, srclen); } void auth_decode (char **dstbuf, int *dstlen, const char *srcbuf, int srclen, void *arg) { auth_context_t context = arg; if (context != NULL && context->client != NULL && context->client->encode != NULL) (*context->client->decode) (context->plugin_ctx, dstbuf, dstlen, srcbuf, srclen); } libESMTP-1.1.0/auth-client.h000066400000000000000000000071061405645115200154650ustar00rootroot00000000000000#ifndef _auth_client_h #define _auth_client_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef __cplusplus extern "C" { #endif /* Someday this will expand into a standalone SASL library. For now the application must use the remainder of the SASL implementation's API to set things up before calling smtp_start_session(). */ typedef struct auth_context *auth_context_t; /* These flags are set for standard user authentication info */ #define AUTH_USER 0x0001 #define AUTH_REALM 0x0002 #define AUTH_PASS 0x0004 /* This flag is set for information passed in clear text on the wire */ #define AUTH_CLEARTEXT 0x0008 struct auth_client_request { const char *name; /* Name of field requested from the application, e.g. "user", "passphrase" "realm" etc. */ unsigned flags; /* Alternative version of above */ const char *prompt; /* Text that the application can use to prompt for input. */ unsigned size; /* Maximum length of response allowed. 0 == no limit */ }; typedef const struct auth_client_request *auth_client_request_t; typedef int (*auth_interact_t) (auth_client_request_t request, char **result, int fields, void *arg); typedef const char *(*auth_response_t) (void *ctx, const char *challenge, int *len, auth_interact_t interact, void *arg); typedef int (*auth_recode_t) (void *ctx, char **dstbuf, int *dstlen, const char *srcbuf, int srclen); /* For enabling mechanisms */ #define AUTH_PLUGIN_ANONYMOUS 0x01 /* mechanism is anonymous */ #define AUTH_PLUGIN_PLAIN 0x02 /* mechanism uses plaintext passwords */ #define AUTH_PLUGIN_EXTERNAL 0x04 /* mechanism is EXTERNAL */ void auth_client_init(void); void auth_client_exit(void); auth_context_t auth_create_context(void); int auth_destroy_context(auth_context_t context); int auth_set_mechanism_flags (auth_context_t context, unsigned set, unsigned clear); int auth_set_mechanism_ssf (auth_context_t context, int min_ssf); int auth_set_interact_cb (auth_context_t context, auth_interact_t interact, void *arg); int auth_client_enabled(auth_context_t context); int auth_set_mechanism(auth_context_t context, const char *name); const char *auth_mechanism_name (auth_context_t context); const char *auth_response(auth_context_t context, const char *challenge, int *len); int auth_get_ssf(auth_context_t context); void auth_encode(char **dstbuf, int *dstlen, const char *srcbuf, int srclen, void *arg); void auth_decode(char **dstbuf, int *dstlen, const char *srcbuf, int srclen, void *arg); int auth_set_external_id (auth_context_t context, const char *identity); #ifdef __cplusplus }; #endif #endif libESMTP-1.1.0/auth-plugin.h000066400000000000000000000042421405645115200155030ustar00rootroot00000000000000#ifndef _auth_plugin_h #define _auth_plugin_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /**************************************************************************** * Client side SASL plugins. * This header is used only by the plugins. Structures and constants shared * between the plugin and the app are in auth-client.h ****************************************************************************/ typedef int (*auth_init_client_t) (void *pctx); typedef void (*auth_detsroy_client_t) (void *ctx); /* Plugins export client info through this structure */ struct auth_client_plugin { /* Plugin information */ const char *keyw; /* mechanism keyword */ const char *description; /* description of the mechanism */ /* Plugin instance */ auth_init_client_t init; /* Create plugin context */ auth_detsroy_client_t destroy; /* Destroy plugin context */ /* Authentication */ auth_response_t response; /* request response to a challenge */ int flags; /* plugin information */ /* Security Layer */ int ssf; /* security strength */ auth_recode_t encode; /* encode data for transmission */ auth_recode_t decode; /* decode received data */ }; #ifndef NULL # define NULL ((void *) 0) #endif #endif libESMTP-1.1.0/base64.c000066400000000000000000000106561405645115200143330ustar00rootroot00000000000000/* * This file is part of libESMTP, a library for submission of RFC 5322 * formatted electronic mail messages using the SMTP protocol described * in RFC 4409 and RFC 5321. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include /* Routines to encode and decode base64 text. */ #include #include #include "base64.h" /* RFC 2045 section 6.8 */ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "+/"; static const char index_64[128] = { -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, -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, -1, -1, -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, -1, -1, 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, }; /* Decode srclen bytes of base64 data contained in src and put the result in dst. Since the destination buffer may contain arbitrary binary data and it is not necessarily a string, there is no \0 byte at the end of the decoded data. */ int b64_decode (void *dst, int dstlen, const char *src, int srclen) { const unsigned char *p, *q; unsigned char *t; int c1, c2; assert (dst != NULL && dstlen > 0); if (src == NULL) return 0; if (srclen < 0) srclen = strlen (src); /* Remove leading and trailing white space */ for (p = (const unsigned char *) src; srclen > 0 && isspace (*p); p++, srclen--) ; for (q = p + srclen - 1; q >= p && isspace (*q); q--, srclen--) ; /* Length MUST be a multiple of 4 */ if (srclen % 4 != 0) return -1; /* Destination buffer length must be sufficient */ if (srclen / 4 * 3 + 1 > dstlen) return -1; t = dst; while (srclen > 0) { srclen -= 4; if (*p >= 128 || (c1 = index_64[*p++]) == -1) return -1; if (*p >= 128 || (c2 = index_64[*p++]) == -1) return -1; *t++ = (c1 << 2) | ((c2 & 0x30) >> 4); if (p[0] == '=' && p[1] == '=') break; if (*p >= 128 || (c1 = index_64[*p++]) == -1) return -1; *t++ = ((c2 & 0x0f) << 4) | ((c1 & 0x3c) >> 2); if (p[0] == '=') break; if (*p >= 128 || (c2 = index_64[*p++]) == -1) return -1; *t++ = ((c1 & 0x03) << 6) | c2; } return t - (unsigned char *) dst; } /* Return a pointer to a base 64 encoded string. The input data is arbitrary binary data, the output is a \0 terminated string. src and dst may not share the same buffer. */ int b64_encode (char *dst, int dstlen, const void *src, int srclen) { char *to = dst; const unsigned char *from; unsigned char c1, c2; int dst_needed; assert (dst != NULL && dstlen > 0 && srclen >= 0); if (src == NULL) return 0; dst_needed = (srclen + 2) / 3; dst_needed *= 4; if (dstlen < dst_needed + 1) return -1; from = src; while (srclen > 0) { c1 = *from++; srclen--; *to++ = base64[c1 >> 2]; c1 = (c1 & 0x03) << 4; if (srclen <= 0) { *to++ = base64[c1]; *to++ = '='; *to++ = '='; break; } c2 = *from++; srclen--; c1 |= (c2 >> 4) & 0x0f; *to++ = base64[c1]; c1 = (c2 & 0x0f) << 2; if (srclen <= 0) { *to++ = base64[c1]; *to++ = '='; break; } c2 = *from++; srclen--; c1 |= (c2 >> 6) & 0x03; *to++ = base64[c1]; *to++ = base64[c2 & 0x3f]; } *to = '\0'; return to - dst; } libESMTP-1.1.0/base64.h000066400000000000000000000022331405645115200143300ustar00rootroot00000000000000#ifndef _base64_h #define _base64_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ int b64_decode (void *dst, int dstlen, const char *src, int srclen); int b64_encode (char *dst, int dstlen, const void *src, int srclen); #endif libESMTP-1.1.0/concatenate.c000066400000000000000000000115771405645115200155360ustar00rootroot00000000000000/* * This file is part of libESMTP, a library for submission of RFC 5322 * formatted electronic mail messages using the SMTP protocol described * in RFC 4409 and RFC 5321. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Stuff to maintain a dynamically sized buffer for a string. I seem to keep writing code like this, so I've put it in a file by itself. Maybe I should consolidate some other string buffering code with this. NOTE: no \0 terminating strings */ #include #include #include #include #include #include #include /* declarations for missing library functions */ #include "concatenate.h" /* malloc/realloc the buffer to be the requested length. Return 0 on failure, non-zero otherwise */ static int cat_alloc (struct catbuf *catbuf, size_t length) { char *nbuf; assert (catbuf != NULL && length > 0); if (catbuf->buffer == NULL) catbuf->buffer = malloc (length); else { nbuf = realloc (catbuf->buffer, length); if (nbuf == NULL) free (catbuf->buffer); catbuf->buffer = nbuf; } catbuf->allocated = (catbuf->buffer == NULL) ? 0 : length; if (catbuf->allocated < catbuf->string_length) catbuf->string_length = catbuf->allocated; return catbuf->buffer != NULL; } /* Reset the string to zero length without freeing the allocated memory */ void cat_reset (struct catbuf *catbuf, size_t minimum_length) { assert (catbuf != NULL); catbuf->string_length = 0; if (minimum_length > catbuf->allocated) cat_alloc (catbuf, minimum_length); } /* Initialise a buffer */ void cat_init (struct catbuf *catbuf, size_t minimum_length) { assert (catbuf != NULL); memset (catbuf, 0, sizeof (struct catbuf)); if (minimum_length > 0) cat_alloc (catbuf, minimum_length); } /* Free memory allocated to the buffer */ void cat_free (struct catbuf *catbuf) { assert (catbuf != NULL); if (catbuf->buffer != NULL) free (catbuf->buffer); memset (catbuf, 0, sizeof (struct catbuf)); } /* Return a pointer to the buffer and put its length in *len. */ char * cat_buffer (struct catbuf *catbuf, int *len) { assert (catbuf != NULL); if (len != NULL) *len = catbuf->string_length; return catbuf->buffer; } /* Shrink the allocated memory to the minimum needed. Return a pointer to the buffer and put its length in *len. */ char * cat_shrink (struct catbuf *catbuf, int *len) { assert (catbuf != NULL); if (catbuf->buffer != NULL) cat_alloc (catbuf, catbuf->string_length); if (len != NULL) *len = catbuf->string_length; return catbuf->buffer; } /* Concatenate a string to the buffer. N.B. the buffer is NOT terminated by a \0. If len < 0 then string must be \0 terminated. */ char * concatenate (struct catbuf *catbuf, const char *string, int len) { size_t shortfall; assert (catbuf != NULL && string != NULL); if (len < 0) len = strlen (string); if (len > 0) { /* Ensure that the buffer is big enough to accept the string */ if (catbuf->buffer == NULL) shortfall = 512; else shortfall = len - (catbuf->allocated - catbuf->string_length); if (shortfall > 0) { if (shortfall % 128 != 0) shortfall += 128 - shortfall % 128; if (!cat_alloc (catbuf, catbuf->allocated + shortfall)) return NULL; } /* Copy the string */ memcpy (catbuf->buffer + catbuf->string_length, string, len); catbuf->string_length += len; } return catbuf->buffer; } char * vconcatenate (struct catbuf *catbuf, ...) { va_list alist; const char *string; assert (catbuf != NULL); va_start (alist, catbuf); while ((string = va_arg (alist, const char *)) != NULL) concatenate (catbuf, string, -1); va_end (alist); return catbuf->buffer; } int cat_printf (struct catbuf *catbuf, const char *format, ...) { va_list alist; char buf[1024]; int len; assert (catbuf != NULL && format != NULL); va_start (alist, format); len = vsnprintf (buf, sizeof buf, format, alist); va_end (alist); if (len <= 0) return len; if (len >= (int) sizeof buf) len = sizeof buf; concatenate (catbuf, buf, len); return len; } libESMTP-1.1.0/concatenate.h000066400000000000000000000032111405645115200155250ustar00rootroot00000000000000#ifndef _concatenate_h #define _concatenate_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ struct catbuf { char *buffer; size_t string_length; size_t allocated; }; void cat_init (struct catbuf *catbuf, size_t minimum_length); void cat_reset (struct catbuf *catbuf, size_t minimum_length); void cat_free (struct catbuf *catbuf); char *cat_shrink (struct catbuf *catbuf, int *len); char *cat_buffer (struct catbuf *catbuf, int *len); char *concatenate (struct catbuf *catbuf, const char *string, int len); char *vconcatenate (struct catbuf *catbuf, ...) __attribute__ ((sentinel)) ; int cat_printf (struct catbuf *catbuf, const char *format, ...) __attribute__ ((format (printf, 2, 3))) ; #endif libESMTP-1.1.0/crammd5/000077500000000000000000000000001405645115200144235ustar00rootroot00000000000000libESMTP-1.1.0/crammd5/client-crammd5.c000066400000000000000000000073141405645115200174000ustar00rootroot00000000000000/* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "hmacmd5.h" #include "auth-client.h" #include "auth-plugin.h" #define NELT(x) (sizeof x / sizeof x[0]) static int crammd5_init (void *pctx); static void crammd5_destroy (void *ctx); static const char *crammd5_response (void *ctx, const char *challenge, int *len, auth_interact_t interact, void *arg); const struct auth_client_plugin sasl_client = { /* Plugin information */ "CRAM-MD5", "Challenge-Response Authentication Mechanism (RFC 2195)", /* Plugin instance */ crammd5_init, crammd5_destroy, /* Authentication */ crammd5_response, 0, /* Security Layer */ 0, NULL, NULL, }; static const struct auth_client_request client_request[] = { { "user", AUTH_CLEARTEXT | AUTH_USER, "User Name", 0, }, { "passphrase", AUTH_PASS, "Pass Phrase", 0, }, }; struct crammd5_context { int state; char *response; int response_len; }; static int crammd5_init (void *pctx) { struct crammd5_context *context; context = malloc (sizeof (struct crammd5_context)); memset (context, 0, sizeof (struct crammd5_context)); *(void **) pctx = context; return 1; } static void crammd5_destroy (void *ctx) { struct crammd5_context *context = ctx; if (context->response != NULL) { memset (context->response, 0, context->response_len); free (context->response); } free (context); } static const char * crammd5_response (void *ctx, const char *challenge, int *len, auth_interact_t interact, void *arg) { struct crammd5_context *context = ctx; char *result[NELT (client_request)]; unsigned char digest[16]; char *p, *response; int response_len; size_t i; static const char hex[] = "0123456789abcdef"; switch (context->state) { case 0: /* No initial response */ context->state = 1; *len = 0; return NULL; case 1: /* Digest the challenge and compute a response. */ if (!(*interact) (client_request, result, NELT (client_request), arg)) break; hmac_md5 (challenge, *len, result[1], strlen (result[1]), digest); response_len = strlen (result[0]) + 1 + 2 * sizeof digest; response = malloc (response_len); strcpy (response, result[0]); strcat (response, " "); p = strchr (response, '\0'); for (i = 0; i < sizeof digest; i++) { *p++ = hex[(digest[i] >> 4) & 0x0F]; *p++ = hex[digest[i] & 0x0F]; } /* Note no \0 termination */ context->state = -1; context->response = response; context->response_len = response_len; *len = response_len; return response; } *len = 0; return NULL; } libESMTP-1.1.0/crammd5/hmacmd5.c000066400000000000000000000062751405645115200161170ustar00rootroot00000000000000/* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "hmacmd5.h" #define PAD_SIZE 64 /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, challenge)) * * where K is an n byte secret * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and challenge is the data being protected */ /* Precompute HMAC-MD5 contexts from a secret */ void hmac_md5_pre (const void *secret, size_t secret_len, MD5_CTX *inner, MD5_CTX *outer) { unsigned char ipad[PAD_SIZE]; unsigned char opad[PAD_SIZE]; unsigned char tk[16]; int i; /* If secret is longer than 64 bytes reset it to secret = MD5 (secret) */ if (secret_len > PAD_SIZE) { MD5_CTX tctx; MD5_Init (&tctx); MD5_Update (&tctx, secret, secret_len); MD5_Final (tk, &tctx); secret = tk; secret_len = sizeof tk; } /* start out by storing secret in pads */ memcpy (ipad, secret, secret_len); if (secret_len < sizeof ipad) memset (ipad + secret_len, 0, sizeof ipad - secret_len); memcpy (opad, secret, secret_len); if (secret_len < sizeof opad) memset (opad + secret_len, 0, sizeof opad - secret_len); /* XOR secret with ipad and opad values */ for (i = 0; i < PAD_SIZE; i++) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } /* perform inner MD5 */ MD5_Init (inner); MD5_Update (inner, ipad, sizeof ipad); /* perform outer MD5 */ MD5_Init (outer); MD5_Update (outer, opad, sizeof opad); } /* Finalise HMAC-MD5 contexts from a challenge */ void hmac_md5_post (const void *challenge, size_t challenge_len, MD5_CTX *inner, MD5_CTX *outer, unsigned char digest[16]) { unsigned char id[16]; /* perform inner MD5 */ MD5_Update (inner, challenge, challenge_len); MD5_Final (id, inner); /* perform outer MD5 */ MD5_Update (outer, id, sizeof id); MD5_Final (digest, outer); } /* Digest a challenge and a secret. */ void hmac_md5 (const void *challenge, size_t challenge_len, const void *secret, size_t secret_len, unsigned char digest[16]) { MD5_CTX inner, outer; hmac_md5_pre (secret, secret_len, &inner, &outer); hmac_md5_post (challenge, challenge_len, &inner, &outer, digest); } libESMTP-1.1.0/crammd5/hmacmd5.h000066400000000000000000000034361405645115200161200ustar00rootroot00000000000000#ifndef _hmac_md5_h #define _hmac_md5_h /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #if HAVE_LIBCRYPTO #include #else #include "md5.h" #define MD5_CTX MD5Context #define MD5_Init(c) md5_init((c)) #define MD5_Update(c,d,l) md5_update((c),(d),(l)) #define MD5_Final(md,c) md5_final((c),(md)) #endif /* Precompute HMAC-MD5 contexts from a secret. */ void hmac_md5_pre (const void *secret, size_t secret_len, MD5_CTX *inner, MD5_CTX *outer); /* Finalise HMAC-MD5 contexts from a challenge. */ void hmac_md5_post (const void *challenge, size_t challenge_len, MD5_CTX *inner, MD5_CTX *outer, unsigned char digest[16]); /* Digest a challenge and a secret. */ void hmac_md5 (const void *challenge, size_t challenge_len, const void *secret, size_t secret_len, unsigned char digest[16]); #endif libESMTP-1.1.0/crammd5/md5.c000066400000000000000000000216521405645115200152620ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to md5_init, call md5_update as * needed on buffers full of bytes, and then call md5_Final, which * will fill a supplied 16-byte array with the digest. */ /* parts of this file are: * Written March 1993 by Branko Lankester * Modified June 1993 by Colin Plumb for altered md5.c. * Modified October 1995 by Erik Troan for RPM */ /* Modified 2001 by Brian Stafford to use ISO C typedefs for various * quantities. Also eliminated convenience functions not needed for * libESMTP. */ #include #include #include #include #include "md5.h" static void md5_transform (unsigned32_t buf[4], const unsigned32_t in[16]); static unsigned32_t _ie = 0x44332211; static union _endian { unsigned32_t i; unsigned char b[4]; } *_endian = (union _endian *)&_ie; #define IS_BIG_ENDIAN() (_endian->b[0] == '\x44') #define IS_LITTLE_ENDIAN() (_endian->b[0] == '\x11') /* * Note: this code is harmless on little-endian machines. */ static void _byte_reverse (unsigned char *buf, unsigned32_t longs) { unsigned32_t t; do { t = (unsigned32_t) ((unsigned32_t) buf[3] << 8 | buf[2]) << 16 | ((unsigned32_t) buf[1] << 8 | buf[0]); *(unsigned32_t *) buf = t; buf += 4; } while (--longs); } /** * md5_init: Initialise an md5 context object * @ctx: md5 context * * Initialise an md5 buffer. * **/ void md5_init (MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; if (IS_BIG_ENDIAN()) ctx->doByteReverse = 1; else ctx->doByteReverse = 0; } /** * md5_update: add a buffer to md5 hash computation * @ctx: conetxt object used for md5 computaion * @buf: buffer to add * @len: buffer length * * Update context to reflect the concatenation of another buffer full * of bytes. Use this to progressively construct an md5 hash. **/ void md5_update (MD5Context *ctx, const void *buf, size_t len) { unsigned32_t t; const unsigned char *ucbuf = buf; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((unsigned32_t) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy (p, ucbuf, len); return; } memcpy (p, ucbuf, t); if (ctx->doByteReverse) _byte_reverse (ctx->in, 16); md5_transform (ctx->buf, (unsigned32_t *) ctx->in); ucbuf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy (ctx->in, ucbuf, 64); if (ctx->doByteReverse) _byte_reverse (ctx->in, 16); md5_transform (ctx->buf, (unsigned32_t *) ctx->in); ucbuf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy (ctx->in, ucbuf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ /** * md5_final: copy the final md5 hash to a bufer * @digest: 16 bytes buffer * @ctx: context containing the calculated md5 * * copy the final md5 hash to a bufer **/ void md5_final (MD5Context *ctx, unsigned char digest[16]) { unsigned32_t count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset (p, 0, count); if (ctx->doByteReverse) _byte_reverse (ctx->in, 16); md5_transform (ctx->buf, (unsigned32_t *) ctx->in); /* Now fill the next block with 56 bytes */ memset (ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset (p, 0, count - 8); } if (ctx->doByteReverse) _byte_reverse (ctx->in, 14); /* Append length in bits and transform */ ((unsigned32_t *) ctx->in)[14] = ctx->bits[0]; ((unsigned32_t *) ctx->in)[15] = ctx->bits[1]; md5_transform (ctx->buf, (unsigned32_t *) ctx->in); if (ctx->doByteReverse) _byte_reverse ((unsigned char *) ctx->buf, 4); memcpy (digest, ctx->buf, 16); } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. md5_Update blocks * the data and converts bytes into longwords for this routine. */ static void md5_transform (unsigned32_t buf[4], const unsigned32_t in[16]) { register unsigned32_t a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } libESMTP-1.1.0/crammd5/md5.h000066400000000000000000000030231405645115200152570ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* parts of this file are : * Written March 1993 by Branko Lankester * Modified June 1993 by Colin Plumb for altered md5.c. * Modified October 1995 by Erik Troan for RPM */ #ifndef MD5_UTILS_H #define MD5_UTILS_H #if SIZEOF_UNSIGNED_INT == 32 / 8 typedef unsigned int unsigned32_t; #elif SIZEOF_UNSIGNED_LONG == 32 / 8 typedef unsigned long unsigned32_t; #else #include typedef uint32 unsigned32_t; #endif #include typedef struct { unsigned32_t buf[4]; unsigned32_t bits[2]; unsigned char in[64]; int doByteReverse; } MD5Context ; /* raw routines */ void md5_init (MD5Context *ctx); void md5_update (MD5Context *ctx, const void *buf, size_t len); void md5_final (MD5Context *ctx, unsigned char digest[16]); #endif /* MD5_UTILS_H */ libESMTP-1.1.0/crammd5/meson.build000066400000000000000000000007411405645115200165670ustar00rootroot00000000000000sasl_crammd5_sources = [ 'client-crammd5.c', 'hmacmd5.c', 'hmacmd5.h', ] crammd5_deps = [ ] if conf.get('USE_TLS') crammd5_deps += ssldep else sasl_crammd5_sources += [ 'md5.c', 'md5.h', ] endif sasl_crammd5 = shared_module('crammd5', sasl_crammd5_sources, name_prefix : 'sasl-', dependencies : crammd5_deps, include_directories: [ include_dir, ], install : true, install_dir: auth_plugin_dir) clients += sasl_crammd5 libESMTP-1.1.0/docs/000077500000000000000000000000001405645115200140235ustar00rootroot00000000000000libESMTP-1.1.0/docs/ChangeLog.md000066400000000000000000001357551405645115200162140ustar00rootroot00000000000000# ChangeLog ``` txt 2010-08-10 Stable Version 1.0.6 released ---------------------------------------- * smtp-tls.c Each component matched by match-domain() is either a single '*' which matches anything or a case-insensitive comparison with a string of alphanumeric characters or a '-'. This is more restrictive than RFC 2818 appears to allow and replaces the previous match which was supposed to allow multiple wildcards but which just didn't work. Revised check_acceptable_security() to check subjectAltName falling back to commonName only if subjectAltName is not available. 1.0.5 never released -------------------- 2006-10-31 Brian Stafford * protocol.c The Gmail server reports enhanced status codes but then fails to provide them in some cases. The parser is now tolerant of this but warns the application using a new event flag SMTP_EV_SYNTAXWARNING that it is progressing despite the syntax error. * headers.c Fixed bug where To, Cc, Bcc etc. accepted only single values instead of a list. The comparison on the return value of gettimeofday() was reversed. 2005-12-16 Stable Version 1.0.4 released ---------------------------------------- 2005-12-16 Brian Stafford * headers.c Replaced static counter used when generating the default Message-Id header with getpid() to minimise the risk of 2 processes generating the same Message-Id. If the platform provides gettimeofday() this is used to further reduce the possibility of collision. Thanks to Dmitry Maksyoma for spotting this and suggesting the fix. * Makefile.am */Makefile.am Replace CFLAGS with AM_CFLAGS to silence warning from automake. * Makefile.am COPYING COPYING.LIB Fixed the names of the files with the GPL and LGPL. It seems the LGPL version of COPYING got zapped by autoconf at some time in the past. 2005-08-29 Brian Stafford * acinclude.m4 Fix underquoted definition of ACX_WHICH_GETHOSTBYNAME_R. Thanks to Matthias Andree . 2005-07-25 Brian Stafford * errors.c Added #ifdefs for some of the EAI_ constants used by getaddrinfo() which are not defined by OSX. Thanks to Thomas Deselaers 2005-07-21 Brian Stafford * acinclude.m4 Fix cross compiling issue when detecting snprintf as suggested by Chris Richards 2005-07-02 Brian Stafford * smtp-api.c Plug memory leaks in smtp_destroy_session() and smtp_set_server(). Thanks to Bas ten Berge for report and patch. Also reported by Heikki Lindholm 2005-02-03 Brian Stafford * protocol.c exts was set with the wrong flag (DSN) when checking if CHUNKING is a required extension. 2004-07-16 Brian Stafford * smtp-tls.c Applied OpenSSL patch from Pawel Salek when checking subjectAltName. 2004-04-20 Stable Version 1.0.3 released ---------------------------------------- 2004-04-20 Brian Stafford * memrchr.c configure.in Added memrchr() implementation for systems that don't have one. * smtp-tls.c Applied patches from Pawel Salek to check subjectAltName for wildcarded domain name when validating server certificate. 2004-01-06 Stable Version 1.0.2 released -------------------------------------- 2003-12-01 Brian Stafford * smtp-tls.c examples/mail-file.c Applied patch from Pawel Salek. * smtp-tls.c Fixed typo in check_file() which prevented it from doing quite the right thing. The domain name check for the server certificate is now implemented using the wildcard match described in RFC 2818. Check_file() and check_directory() return different values for unusable vs absent files. 2003-09-12 Stable Version 1.0.1 released -------------------------------------- 2003-09-11 Brian Stafford * protocol.c smtp-auth.c smtp-bdat.c smtp-etrn.c smtp-tls.c More thoroughly check return value from read_smtp_response(). * libesmtp.h errors.c Added new "Client error" error code. This is just a cop-out, used when an API called by libesmtp fails. * base64.c Make conversions immune to NULL source data, * examples/mail-file.c Cleaned up some compiler warnings 2003-09-02 Brian Stafford * siobuf.[hc] Added a few extra sio_ calls. Not actually used in libESMTP though. 2003-07-29 Brian Stafford * concatenate.c errors.c getaddrinfo.c headers.c htable.c * protocol.c siobuf.c Don't perform zero length operations using the memxxx() functions. This may avoid segfaults on some platforms or libraries. * siobuf.c Improved handling of flushes in sio_write() particularly in the case where data would exactly fill remaining space in the buffer. 2003-07-27 Brian Stafford * rfc2822date.c Correct leap year compensation for January and February in libesmtp_mktime(). 2003-07-27 Brian Stafford * examples/Makefile Changed compiler flags from -ansi to -std=c99 and added -W 2003-03-04 Brian Stafford * headers.c Eliminated bug where find_header() could pass -1 to the length argument of memchr() causing a core dump on some architectures. 2003-02-26 Brian Stafford * libesmtp-private.h protocol.c smtp-bdat.c M$ Exchange does not accept a chunk size of 0 in BDAT 0 LAST as explicitly permitted by RFC 3030, *sigh*. Hackish workaround implemented. 2003-01-27 Brian Stafford * configure.in Makefile.am Added DIST_SUBDIRS macro to make sure tarball gets built properly. This one slipped past 'make distcheck' last time for some reason but then autoconf & friends are totally inscruitable. * ntlm/ntlmdes.c OpenSSL 0.9.7 changes some typedefs. Changed to suit, should still be compatible with previous OpenSSL versions. 2002-11-09 Stable Version 1.0 released -------------------------------------- 2002-11-09 Brian Stafford * configure.in All version 1.0 features enabled by default. --enable-isoc now sets -std=c99 instead of -ansi * headers.c Added missing check for NULL pointer in destroy_header_table. Reversed order of freeing header structures and hash table to avoid referencing freed memory. (Wally Yau) 2002-06-24 Brian Stafford * smtp-etrn.c Compilation fails with `./configure --enable-more-warnings=picky --disable-etrn'. Added missing __attribute__ ((unused)) markers to offending function arguments to avoid this. 2002-06-24 Version 1.0rc1 released ---------------------------------- 2002-06-24 Brian Stafford * configure.in Makefile.am protocol.c protocol-states.h * smtp-api.c smtp-bdat.c libesmtp.h libesmtp-private.h Added experimental support for the SMTP CHUNKING extension. * configure.in Enable non-standard AUTH= response by default. 2002-05-31 Brian Stafford * protocol.c smtp-api.c libesmtp.h libesmtp-private.h Added API call to permit protocol timeouts to be set. * ntlm/ntlmstruct.c Replaced use of byteswap.h and bswap_{16,32} with locally defined functions. 2002-04-24 Version 0.8.12 released ---------------------------------- 2002-03-14 Brian Stafford * headers.c Setting Hdr_PROHIBIT did not work properly. Thanks to Ronald F. Guilmette for pointing this out. 2002-03-13 Brian Stafford * protocol.c smtp-api.c libesmtp.h configure.in Revoked deprecated status from smtp_option_require_all_recipients and remove the corresponding --enable-require-all-recipients parameter to configure. 2002-03-07 Brian Stafford * libesmtp.h libesmtp-private.h protocol.c smtp-tls.c RFC 2487 is obsoleted by RFC 3207. Updated references. * protocol.c The check for required STARTTLS was omitted when processing the HELO command. If a server did not implement EHLO the session would proceed instead of quitting. Check added and the event callback added to report the missing extension to the application. 2002-03-06 Version 0.8.11 released ---------------------------------- 2002-03-04 Brian Stafford * protocol.c Fix buffer overflow problem in read_smtp_response. This overflow could be exploited by a malicious SMTP server to overwrite the stack and hence a carefully crafted response could cause arbitrary code to be executed. Also took the opportunity to add a related check for a potential DoS attack which makes use of excessively long SMTP responses. Thanks to Colin Phipps for detecting this. * concatenate.[ch] New function cat_shrink to shrink-wrap the allocated buffer. * libesmtp.h errors.c New unterminated response error code and description. * ntlm/ntlmstruct.c configure.in crammd5/md5.h stdint.h does not yet seem to be widely available causing compilation to fail on some platforms. Changed uint{16,32}_t to unsigned{16,32}_t, detect correct sizes with autoconf and added typedefs in ntlmstruct.c. Changed detection types from int to unsigned int in configure.in and made corresponding changes in crammd5/md5.h. Thanks to Ronald F. Guilmette for spotting this. 2002-02-12 Brian Stafford * strcasecmp.c strncasecmp.c These now return the correct sign of result for differing strings. 2002-01-30 Version 0.8.10p1 released ------------------------------------ 2002-01-29 Brian Stafford * ntlm/Makefile.am Added ntlm.h to list of sources. This omission stopped 0.8.10 form building. 2002-01-29 Version 0.8.10 released ---------------------------------- 2002-01-26 Brian Stafford * various files Copyright messages now show the correct year. Minor tweaks to kill warnings when compiling with --enable-more-warnings=picky. In a few cases this meant adding a few casts which superficially look unnecessary. In other cases this meant adding a number of #undefs to get a vanilla ISOC environment. * missing.h Added missing.h which has declarations for Posix/SUS functions which may be missing from system libraries on some platforms. * snprintf.c configure.in Detect broken or missing snprintf() implementations and replace if necessary. N.B. the replacement snprintf.c is taken from the libmutt distro and it too, is broken. However, it *does* correctly truncate and \0 terminate output which is too long to fit in the buffer and that is the behaviour I rely on. * strdup.c Added strdup() for systems which don't have it. * examples/mail-file.c Check for errors when smtp_start_session returns. Fixed authinteract so that responses are not accidentally overwritten. 2002-01-24 Brian Stafford * htable.c configure.in strndup.c Altered code to avoid the use of strndup. strndup.c is removed from the distribution. 2002-01-16 Brian Stafford * ntlm/* configure.in Added NTLM auhentication module. 2002-01-07 Brian Stafford * concatenate.c errors.c siobuf.c Check return value from snprintf. 2002-01-03 Version 0.8.9 released --------------------------------- 2002-01-02 Brian Stafford * configure.in Added -lsocket to list of libraries searched for getaddrinfo(). 2001-12-29 Brian Stafford * protocol.c configure.in Added hack for stupid SMTP servers that advertise AUTH using non-standard syntax from an internet draft that never made it into RFC 2554. Because this feature is non-standard, it must be explicitly enabled when configuring. rsp_{helo,ehlo}() now reset the auth mechanism list before processing the result. Previously this was done only when AUTH was advertised. * smtp-auth.c set_auth_mechanisms no longer resets the mechanism list before processing. Added a test to avoid duplicates in the mechanism list. select_auth_mechanism now guarantees to select the *first* usable mechanism. The net effect of these changes is that multiple calls to set_auth_mechanisms accumulate. * auth-client.c Rearranged code in auth_set_mechanisms and load_client_plugin avoiding the need to repeat the test for plugin acceptability. 2001-12-24 Brian Stafford * configure.in Compiling with picky warnings turned on was broken. Also, recent glibc versions seem to have decided that strcasecmp and a few other functions are GNU extensions causing compiles to fail because of missing declarations. Naturally, autoconf does not detect this. Added a _GNU_SOURCE define to fix this on potentially affected systems. No, I don't like it either. * strcasecmp.c strncasecmp.c strndup.c Added these functions in case some systems don't provide them. 2001-12-21 Brian Stafford * htable.[ch] h_insert now returns a void pointer to the data instead of a struct h_node eliminating the need for the h_dptr macro and for code using hash tables to maintain two pointers instead of one. * headers.c Updated to use the simpler hash table interface. 2001-12-10 Brian Stafford * auth-client.c Use dlsym and friends directly on platforms that have it. * configure.in Makefile.am Detect dlsym, fall back to using libltdl for other platforms. libltdl is no longer distributed significantly reducing tarball size. 2001-12-10 Brian Stafford * configure.in A missing comma caused the test for getipnodebyname to fail on systems which provide it. 2001-12-06 Version 0.8.8 released --------------------------------- 2001-11-30 Brian Stafford * crammd5/md5.h The len parameter of md5_update differed in type between prototype and definition, preventing compilation if size_t is not an unsigned int. 2001-11-29 Brian Stafford * crammd5/*.[ch] Moved include of config.h from hmacmd5.h to hmacmd5.c. Make sure sys/types.h is included since size_t is used. * configure.in Added some extra nonsense for systems which redefine getaddrinfo to something else in netdb.h 2001-11-27 Brian Stafford * configure.in errors.c Add test for broken strerror_r on OSF-1. 2001-11-12 Brian Stafford * configure.in Updated the tests for pthreads. Should now supply the correct compiler flags on more systems. 2001-11-07 Version 0.8.7 released --------------------------------- 2001-11-05 Brian Stafford * errors.h libesmtp.h Improve handling of error codes from getaddrinfo. Delay mapping of codes to make debugging easier. libesmtp.h defines new error codes for the relevant EAI_XXX codes from getaddrinfo. smtp_strerror will use gai_strerror if appropriate. 2001-10-31 Brian Stafford * configure.in Added test for sun platforms and define __EXTENSIONS__ so that sun's netdb.h will declare the getaddrinfo stuff. (James McPherson) * crammd5/md5.[ch] Type sanity: change u_intXX_t to uintXX_t. Also changed the argument for the buffer and length to void * and size_t respectively in md5_update. Buffer for md5_final is now unsigned char. 2001-10-17 Brian Stafford * headers.c Fixed a core dump bug which strikes when existing headers in a message are substituted. * Makefile.am Reinstated libesmtp.spec into tarballs. 2001-08-17 Version 0.8.6 released --------------------------------- 2001-10-17 Brian Stafford * libesmtp-config.in Corrected output for --cflags. Added --numeric-version to make it simpler for configure scripts to compare version numbers. * configure.in libesmtp-spec.in Merged changes from Cristophe Lambin. Spec file now creates libesmtp and libesmtp-devel packages. If OpenSSL is used spec file will have openssl dependencies added. * Makefile.am Make sure libesmtp.spec and config.h do not make their way into tarballs. These confused the build on some platforms. 2001-10-16 Brian Stafford * configure.in Added --with-openssl[=DIR] option, removed --enable-starttls. OpenSSL dependent features are now enabled or disabled en masse using --with-openssl. * crammd5/md5.[ch] crammd5/Makefile.am Added public domain MD5 implementation to crammd5 module. This enables the CRAM-MD5 mechanism to be built, even if OpenSSL is not available. * smtp-tls.c Applied patch from James McPherson correcting __attribute to __attribute__ 2001-08-05 Version 0.8.5 released --------------------------------- 2001-10-05 Brian Stafford * libesmtp.spec.in Make sure libesmtp-config gets installed! * configure.in Removed STARTTLS's experimental status. The code works and just needs debugging. Certificate management is basic but usable. Set defines for strict iso/posix/xopen in headers only when --enable-isoc is in force. This helps avoid disabling the tm_gmtoff member in the BSD struct tm unnecessarily. * siobuf.[ch] sio_read/write use void buffers rather than char. 2001-09-28 Brian Stafford * smtp-tls.c Use the event callback to report STARTTLS in use if the security level was OK. * rfc2822date.c Provide a function to portably calculate the timezone offset when struct tm does not provide tm_gmtoff. * configure.in Don't bother to check for gmtime[_r] since it isn't used any more. 2001-09-26 Brian Stafford * headers.c Make sure set_to accepts NULL for the mailbox value. Added set_cc which is same as set_to except it fails with a NULL mailbox. * Most files. Changed references to RFC 821/822 to RFC 2821/2822 respectively. 2001-09-24 Brian Stafford * headers.c RFC 2822 requires only the originator and date headers to be present in a message. In particular, the presence of the To: header is no longer required. RFC 2822's restriction that headers may not appear multiple times in a messge is enforced respecting certain special exceptions. * examples/mail-file.c Added API call to make sure a To: header is generated if not in the message. 2001-09-14 Brian Stafford * configure.in acinclude.m4 acconfig.h Reverted to configure.in, reinstated acconfig.h and added some compatibility stuff to acinclude.m4. All this to try and be compatible with autoconf 2.5 *and* 2.13. I really hate autoconf. 2001-09-05 Brian Stafford * getaddrinfo.c Check if NO_ADDRESS is defined and different to NO_DATA 2001-08-27 Brian Stafford * protocol.c smtp-tls.c Move some detail of selecting STARTTLS to smtp-tls.c * smtp-tls.c Changed STARTTLS policy for Starttls_ENABLED. If a server offers STARTTLS, then it must be used and all security requirements must be met. If STARTTLS is not offered the session continues in cleartext. Previously, Starttls_ENABLED permitted a session to continue with possibly compromised security. 2001-08-22 Brian Stafford * smtp-tls.c libesmtp.h More certificate management. Added TLS event reporting. * smtp-auth.c Fixed behaviour for zero length responses to server challenges. * base64.c Zero length passwords caused an assertion failure in base64_encode. base64_decode did not correctly strip blanks from strings not terminated by \0. Neither did it correctly handle zero length strings. 2001-08-21 Brian Stafford * smtp-tls.c libesmtp.h Added preliminary code for client certificate management. * siobuf.[ch] Changed sio_set_tlsclient_ctx to sio_set_tlsclient_ssl. This makes things slightly more flexible for supplying different client certificates according to the remote host. 2001-08-20 Brian Stafford * message-source.c Fixed memory leak in msg_source_destroy. (Pawel Salek) 2001-08-16 Brian Stafford * configure.ac Makefile.am Change from using LIBOBJS to LTLIBOBJS. This prevents the wrong objects from being linked by libtool when building dynamic libraries. Added code to configure.ac to correctly set LTLIBOBJS and LTALLOCA. * smtp-api.c protocol.c errors.c libesmtp-private.h configure.ac Code now exclusively uses getaddrinfo. Removed #ifdef code for gethostbyname. Added conditionals for using alternative lwres library distributed with recent versions of bind. Delete --enable-gethostbyname option. Add --enable-emulate-getaddrinfo. 2001-08-14 Brian Stafford * siobuf.c Remove unnecessary socket include files. * getaddrinfo.[ch] Added emulation of the RFC 2553 getaddrinfo resolver interface for systems that don't have it. 2001-08-13 Version 0.8.4 released --------------------------------- 2001-08-13 Brian Stafford * protocol.c Completely ignore TLS extension if TLS is already in use. * smtp-tls.c Fix wrong comparison when initialising OpenSSL mutexes. Record the fact that TLS is in use. Change a numeric constant to its symbolic equivalent. * crammd5/client-crammd5.c Correct a typo which prevented the hmac computation being correctly rendered in hexadecimal. * examples/mail-file.c Added --tls and --require-tls options and supporting code. 2001-07-31 Brian Stafford * configure.ac Make plugin directory consistent with RPM. * libesmtp.spec Applied patch from Pawel Salek to run ldconfig after installing. 2001-07-30 Brian Stafford * protocol.c configure.ac Check for uname and use it in preference to gethostname which is not Posix. 2001-07-19 Brian Stafford * configure.ac Check for the presence of the OpenSSL headers as well as the libraries. Remove --enable-callbacks option. * smtp-api.c libesmtp.h Added smtp_version API call. * message-callbacks.c Removed callbacks which did \n -> CRLF translation. * examples/mail-file.c Use libESMTP provided callback unless the --crlf option is supplied. 2001-07-07 Brian Stafford * protocol.c smtp-api.c Only include netinet/in.h if it is actually needed. 2001-07-06 Version 0.8.3 released --------------------------------- 2001-07-06 Brian Stafford * examples/mail-file.c Made --help more helpful. Undocumented --no-crlf now renamed to --crlf and documented. When prompting for authentication now reads /dev/tty instead of stdin. * configure.ac Check for -lsocket. * protocol.c siobuf.c Zero errno before calling certain functions. Normally the value of errno is only tested if the preceeding system call or function wrapping the system call failed. However, in a few cases, the functions are called in a loop and the value of errno might be tested after a successful return. This meant that a test on the value of errno might yield an invalid result, sometimes causing the connection to the server to be incorrectly dropped. Unfortunately this effect depended on the amount of data buffering provided by the server! 2001-06-29 Brian Stafford * protocol.c et al. Added support for sendmail specific XUSR extension. This informs sendmail the message is a user submission instead of relay, so it makes sense to issue the command. Whether it actually does anything ... * siobuf.c Fixed return from poll in raw_read and raw_write so that EINTR is correctly handled. 2001-06-26 Brian Stafford * auth-client.c Fixed a signed/unsigned comparison that stops compilation when using -Werror. 2001-06-26 Version 0.8.2 released --------------------------------- 2001-06-26 Brian Stafford * protocol.c siobuf.c Resolved a problem related to blocking/non-blocking polling for server events. This could lead to deadlock with certain servers. 2001-06-24 Brian Stafford * configure.ac most C sources Added --disable-isoc option. When using gcc, -ansi -pedantic are now specified by default since the code compiles without warnings when using both flags. Added --enable-debug option to control DEBUG and NDEBUG definitions. Assert macros used to check arguments to most internal functions. 2001-06-23 Brian Stafford * message-source.c msg_gets now checks for both \r and \n when searching for line endings. * errors.c API function now includes ommitted the arguments check. 2001-06-22 Brian Stafford * protocol.c smtp-api.c configure.ac Now uses RFC 2553 / Posix protocol independent getaddrinfo where possible instead of gethostbyname family of resolver functions. * gethostbyname.c configure.ac Added ability to use getipnodebyname and corresponding test for configure. 2001-06-18 Brian Stafford * auth-client.c More thorough argument checking on the auth_xxx APIs. Added some missing malloc return value checking. When loading a plugin, make sure it provides a response() function. * smtp-auth.c Added some missing malloc return value checking. * various sources Changed some 'int' types to 'size_t' * message-source.c In msg_gets, an inconsistent pointer could cause a segfault after a realloc which moved the original memory block. Increased sizes of malloc/realloc so that RFC 2821 maximium line length will not cause realloc. Added missing malloc/realloc return value checking. * protocol.c If an error occurs while copying the message to the SMTP server drop the connection without terminating the message. 2001-06-15 Version 0.8.1 released --------------------------------- 2001-06-13 Brian Stafford * configure.in is now configure.ac to suit autoconf 2.5 Eliminated some redundant stuff concerned with libtool. Now uses AC_HELP_STRING macro where appropriate. Now use standard AC_FUNC_STRERROR_R macro. Improved checking for time.h and sys/time.h. * libesmtp-config.in If libltdl was installed, the list of libraries was set to the wrong thing. * errors.c Only use strerror_r if it actually works. * rfc822date.c Try sys/time for struct tm just in case! 2001-06-12 Brian Stafford * configure.in Now checks -lnsl when seraching for gethostbyname_r. Only print a warning if strerror_r is not found. Chose much more picky compiler warnings when using gcc - this has knock on effects through many files. Compiles should now be much cleaner on more platforms. * siobuf.h Gcc will now check sio_printf()'s argument types against the format string. * headers.c Eliminated a variable which was set but not used. The as yet unimplemented smtp_set_resent_headers API will succeed if `onoff' is zero. * protocol.c Eliminated variables which were set but not used. Fixed an uninitialised variable bug which might strike if the EHLO command received a 5xx status code. This is likely with older servers and may result in libESMTP dropping the connection instead of trying HELO. Fixed an uninitialised variable bug which could cause the protocol to QUIT inadvertently after processing the response to EHLO. * errors.c Rewrote handling of the thread specific data. 2001-06-12 Version 0.8.0 released --------------------------------- 2001-06-11 Brian Stafford * protocol.c smtp-api.c DELIVERBY extension done - still to test. 2001-06-09 Brian Stafford * message-callbacks.c libesmtp.h Added standard callback functions for reading messages. libesmtp.h provides macros to simplify using them. 2001-06-07 Brian Stafford * message-source.c Changed the declaration of the message callback to make it clearer that the first argument in fact points to internal state allocated by the callback. Strings returned to code reading the message are now const char *. 2001-05-31 Brian Stafford * smtp-api.c protocol.c configure,in Had another go at the smtp_require_all_recipients() API hack. The original implementation hoped the SMTP server would report failure on receiving a zero length message but this isn't reliable. This API must be explicitly enabled by ./configure. 2001-05-28 Brian Stafford * smtp-auth.c Make sure the client won't attempt to authenticate when already authenticated. This could happen if having authenticated and enables a security layer, the server offers AUTH again. * smtp-tls.c Make sure the client won't attempt to negotiate TLS when already using TLS. Also don't use TLS if already authenticated. * siobuf.c Make the code for non-blocking sockets + OpenSSL more robust. * errors.c Added default case for set_herrno(). 2001-05-25 Brian Stafford * smtp-auth.c On authentication failure the same mechanism was selected again instead of moving on to the next one. This caused an infinite loop of failing AUTH exchanges. 2001-05-24 Brian Stafford * libesmtp.spec.in Changed "-a 0" option in %setup macro to "-T -b 0" * configure.in Removed -Werror from --enable-more-warnings=yes as this can be bothersome for punters. Added --enable-more-warnings=picky to stop gcc from using internal prototypes for builtin functions; also turns on -Werror. * protocol.c free_ghbnctx() was called twice if connect() failed, potentially causing a SIGSEGV. This bug was introduced with support for gethostbyname_r. 2001-05-23 Brian Stafford * configure.in Incremented library version and reset the age. This is important because the event callback semantics have changed. Detect IPv6 sockaddr structure in . * protocol.c Added 8BITMIME support. New API call smtp_8bitmime_set_body(). Report extensions after final set is known. STARTTLS or AUTH can change the set of extensions advertised by the server. Typo meant the RET=FULL/HDRS parameter was printed as SIZE=FULL/HDRS in MAIL FROM: (D'oh!) * errors.c Changed prototype for smtp_strerror() to allow use of strerror_r. 2001-05-22 Brian Stafford * siobuf.c Fixed calls to encode/decode callbacks and added explanation of their semantics. This eliminates potential for a buffer overflow bug when decoding expands data read from the socket. * libesmtp.spec.in Fixed inconsistency between package name and tarball. Use the bz2 version of the tarball as the source. * Makefile.am Added libesmtp.spec to extra distribution files. * gethostbyname.c Added missing #include (gcc builtin prototypes again - grumble....) 2001-05-21 Brian Stafford * siobuf.c Restructuring of reading/writing and polling to permit use of non-blocking IO. * protocol.c Revised protocol outer loop makes sure the protocol engine reads data as soon as it becomes available and defers buffer flushes until after pending data from the SMTP server has been read. In conjunction with non-blocking output this avoids a potential deadlock described in RFC 2920 when PIPELINING is in use. 2001-05-20 Brian Stafford * smtp-etrn.c Added experimental support for the ETRN extension. * protocol.c smtp-api.c Check for failure to create a message source and added code to actually destroy it thus plugging a memory leak. More thorough checking of some API function arguments. * siobuf.c Added sio_mark(). When the write buffer is flushed data written beyond the mark is retained and the mark is deleted. * protocol.c Added new event types for flagging required extensions not available or reporting extensions that provide information to the application. Command boundaries are marked in the write buffer. This prevents partial commands being sent to the SMTP server. 2001-05-18 Version 0.7.1 released --------------------------------- 2001-05-18 Brian Stafford * protocol.c Added AF_INET6 support. 2001-05-17 Brian Stafford * protocol.c gethostbyname.[ch] configure.in acinclude.m4 gethostbyname_r() now in its own file which provides a consistent interface. configure selects which version of the function to compile for when building threaded code. * configure.in auth-client.h libesmtp-config.in libesmtp.spec.in Directory for installing authentication plugins is now configurable. 2001-05-15 Brian Stafford * libesmtp.spec.in Added to simplify building RPM packages. 2001-05-14 Brian Stafford * smtp-api.c Check that all messages have a callback to read the message headers and body. * tokens.c Check buffer length in read_atom(). Use of eliminated. * headers.c init_header_table() checks for NULL pointers to avoid potential SIGSEGVs. 2001-05-13 Brian Stafford * rfc822date.c configure.in Use localtime_r() or gmtime_r() when building a thread safe library. * concatenate.[ch] Fixed incorrect shortfall caclulation in concatenate() potentially leading to buffer overrun. Generally tidied up code. * auth-client.c auth_response() fails if (*context->client->init)() fails. * base64.c b64_encode() now checks the destination buffer length. 2001-05-11 Brian Stafford * libesmtp-config.in Makefile.am Added config script to simplify compiling and linking. * protocol.c configure.in Use gethostbyname_r() when building a thread safe library. 2001-05-09 Brian Stafford * Makefile.am configure.in libltdl is now part of the tarball and is installed if not already present. * protocol.c do_session() will now make use of all the addresses returned by gethostbyname(). This allows the DNS admin for the domain to specify a number of MTAs which handle mail submission. Failures trying to connect or when processing the greeting or a response to the EHLO/HELO commands will cause a fallback server to be tried. The name server will round robin the responses balancing the load among the servers. When reading the server greeting accept only 220 otherwise the connection may have been made to a non-SMTP service. 2001-05-06 Version 0.7.0 released --------------------------------- 2001-05-06 Brian Stafford * protocol.c session->auth_mechanisms was incorrectly freed in do_session(). This should have been done using destroy_auth_mechanisms(). Moved initialisation of the session variables to the start of do_session(). This allows checks for some error conditions to be done before attempting to connect to the SMTP server. Updated code to select messages and recipients. This is to permit calling smtp_start_session() more than once on a given session. Second and subsequent calls should only deliver to recipients not successful in a previous SMTP session. Removed a few FIXME comments that no longer apply. * smtp-api.c smtp_recipient_reset_status() clears the 'complete' flag so that the recipient will be retried on a subsequent smtp_start_session(). Added a new API smtp_recipient_check_complete(). This is true if a subsequent call to smtp_start_session() would *not* attempt to post the message to this recipient. smtp_destroy_session() now frees memory allocated for remote server hostname. * protocol.c libesmtp-private.h smtp-api.c Renamed 'sent' in smtp_recipient_t structure to 'complete'. Not all completed recipients might have been sent. * protocol.c headers.c smtp-api.c Only call gethostname() once and save the result. Also added new API smtp_set_hostname() to allow the application to change the default. 2001-05-03 Brian Stafford * crammd5/Makefile.am crammd5/hmacmd5.[ch] Renamed files to avoid name conflict with Cyrus SASL include/ directory. * base64.c message-source.c Added missing #include , egcs-2.91.66 didn't spot the missing prototypes. * examples/mail-file.c Ignore SIGPIPE. Means the application isn't killed accidentally when something times out during the protocol session. 2001-05-02 Brian Stafford * sasl-tls.c protocol.c Added experimental support for STARTTLS 2001-04-31 Brian Stafford * cram-md5/Makefile.am hmac-md5.h was missing from the list of sources and hence was not in the tarball. 2001-04-29 Version 0.6.1 released -------------------------------- 2001-04-30 Brian Stafford * auth-client.c Fixed incorrect SSF comparison for authentication modules that were already loaded. 2001-04-29 Version 0.6a released -------------------------------- 2001-04-28 Brian Stafford * configure.in smtp-api.c example/mail-file.c Corrected inconsistently named API from smtp_set_auth_context() to smtp_auth_set_context(). 2001-04-25 Version 0.6 released -------------------------------- 2001-04-25 Brian Stafford * configure.in Makefile.am */Makefile.am Added detection of MD5 routines in OpenSSL, to enable the CRAM-MD5 SASL mechanism. 2001-04-25 Brian Stafford * protocol.c Corrected parsing bug in parse_status_triplet(). 2001-04-16 Brian Stafford * api.h Added new header file. This currently contains macros to aid argument checking for API functions. * libesmtp.h Changed name of API function argument check macro. * most files Wrapped #include with #ifdef HAVE_CONFIG_H 2001-04-11 Brian Stafford * rfc822date.c Make sure the absolute value of minutes is used when formatting the date. * protocol.c Fixed potential segfault when DATA fails before transferring a message. * smtp-auth.c Support for client authentication plugins now working. * protocol.c Support for SMTP AUTH extension. 2001-04-05 Brian Stafford * protocol.c smtp-auth.c Removed 'want_enhanced' argument from read_smtp_response() since it was unnecessary. Added preliminary support for SMTP AUTH extension. 2001-04-04 Brian Stafford * Many files Changes to accomodate stricter error checking options to gcc. 2001-04-03 Brian Stafford * siobuf.c protocol.c Changed CONFIG_TLS to USE_TLS (not that it matters yet) Changed HAVE_LIBSASL to USE_SASL Mostly for consistency with autoconf convention. * configure.in Checks for pthreads and SASL. 2001-03-21 Brian Stafford * smtp-api.c Fixed up some missing error reporting. 2001-03-15 Brian Stafford * protocol.c Now sets timeouts reccommended in RFC 1123 when waiting for server responses. * errors.c libesmtp.h Changed prefix from ES_ to SMTP_ERR_. Edits to other files to accommodate the change. 2001-03-14 Brian Stafford * protocol.c libesmtp.h Added first lot of event monitoring callbacks. Simplified the declaration for the callback function. The callback is called with different arguments depending on the actual event. 2001-03-09 Brian Stafford * tokens.c tokens.h protocol.c Added const to a few things that should have had it. Fixed a corresponding declaration in protocol.c. * smtp-auth.c Basis of the implementation of the SMTP AUTH command. This is not complete or tested yet, pending the decision about how to best implement SASL. * siobuf.c siobuf.h Added callback functions which encode or decode data just before writing or after reading data between the buffers and the socket. This is for use by SASL security layers. 2001-03-07 Brian Stafford * concatenate.c concatenate.h Added minimum_length parameter to cat_{init,reset}(). 2001-03-07 Brian Stafford * siobuf.c siobuf.h protocol.c Allow for seperate read and write file descriptors in sio_attach(). This is for when support for opening a pipe to a program running an SMTP server on its stdin/stdout is added. * siobuf.c siobuf.h Fixed the #ifdef _buffer_h lines to #ifdef _siobuf_h (the perils of cut and paste editing). Added typedefs for the sio callback functions. Added encoder/decoder callbacks for use with security layer parts of SASL. CONFIG_SASL stuff now gone. 2001-03-02 Brian Stafford * headers.c Implemented the rest of destroy_header_table(). 2001-02-27 Version 0.5 released -------------------------------- 2001-02-26 Brian Stafford * protocol.c Now issue RSET before MAIL FROM: if a failure response is received to the DATA command. Fixed possible segfaults when resetting the status in rsp_rest() and rsp_quit(). * headers.c Partially implemented destroy_header_table(). * smtp-api.c Now calls destroy_header_table(). * htable.c Allow callback in h_destroy() to be NULL. 2001-02-26 Version 0.4 released -------------------------------- 2001-02-25 Brian Stafford * protocol.c Second state for the DATA command now does not transfer the message if there were no valid recipients. 2001-02-22 Brian Stafford * smtp-api.c Added APIs to get/set application data in each of the opaque structures. Added protocol event callback API but only for a place holder. This will be used by applications which want to monitor the progress of the session and status changes as they happen. This is different from the protocol monitor which dumps the actual data transferred on or close to the wire. * headers.c Added code to handle Sender: Fixed From: printing; continuation lines had no leading whitespace. In smtp_set_header_option() once Hdr_PROHIBIT is set, it cannot be unset. Prohibit cannot be set for headers already set. Added smtp_set_resent_headers() but only for a place holder. * protocol.c Correct parsing of enhanced status codes. These are only present for 2xx, 4xx and 5xx SMTP status codes. 2001-02-18 Version 0.3 released -------------------------------- 2001-02-19 Brian Stafford * protocol.c smtp-api.c Port number in session structure stored in host byte order instead of network byte order. This makes the port number easier to read in gdb. * protocol.c Removed white space which crept into the MAIL FROM: and RCPT TO: commands. All the servers tested with to date have accepted this but it wasn't in RFC 821. * headers.c Fixed From: and Disposition-Notification-To: headers to allow multiple mailboxes as per RFC 822. Corrected syntax for default Message-Id: generation. This should have been "addr-spec" per RFC 822 but didn't have an @. * examples/mail-file.c Corrected typo that stopped --reverse-path from working. 2001-02-18 Version 0.2 released -------------------------------- Core libESMTP API now complete. 2001-02-18 Brian Stafford * examples/mail-file.c Updated to tweak a few more APIs in libESMTP. The example now has a very basic Makefile. 2001-02-17 Brian Stafford * protocol.c Changed use of strchr() to memchr() since strings read by the message callback and header functions are *not* \0 terminated. * headers.c Changed beyond all recognition. :-) Declaration of smtp_set_header_option() has changed. * New files added to support RFC 822 header processing. 2001-02-08 Brian Stafford * siobuf.c Some additional error checking; extra thoroughness checking the return value of write(). * siobuf.c * protocol.c Added the protocol monitor callback mechanism. * libesmtp.h * libesmtp-private.h * smtp-api.c Minor changes to the monitor callback declaration and session structure for the protocol monitor. 2001-02-04 Version 0.1a released -------------------------------- 2001-04-04 Brian Stafford * message-source.c Fixed a bad bug that could cause an infinite loop if a message was not properly terminated with a \n 2001-02-04 Version 0.1 released ------------------------------- 2001-02-04 Brian Stafford * Initial Release ``` libESMTP-1.1.0/docs/NEWS.md000066400000000000000000000202511405645115200151210ustar00rootroot00000000000000# NEWS ``` * libESMTP 1.0.3 stable release. 2004-04-20 - This release contains TLS improvements from Pawel Salek See ChangeLog for details. * libESMTP 1.0.2 stable release. 2004-01-06 - See ChangeLog for details. * libESMTP 1.0.2 stable release. 2004-01-06 - See ChangeLog for details. * libESMTP 1.0.1 stable release. 2003-09-12 - See ChangeLog for details. * libESMTP 1.0 stable release. 2002-11-09 Tarball builds correctly again! - See ChangeLog for details. * libESMTP 1.0 stable release. 2002-11-09 LibESMTP is now considered stable. Version 1.0 is the best available release of libESMTP and all users are urged to upgrade as soon as is practicable. There have been some minor changes to the configure script such that ./configure with no arguments includes all non-experimental features. This means that some features formerly not enabled by default are now included and, conversely, some features formerly enabled by default must now be requested explicitly. It is intended that, with the exception of features such as setting --prefix or --with-gnu-ld, ./configure will build the correct configuration for most OS distributions. - See ChangeLog for details. This release fixes a minor compilation issue and a potentially more serious memory reference after freeing. * libESMTP 1.0rc1 stable release candidate 1. 2002-06-24 - See ChangeLog for details. o Support for the non-standard AUTH= syntax used by some broken servers is now on by default. This does not appear to interefere with correctly implemented SMTP AUTH and having it on by default is less confusing for users whose ISPs insist on deploying broken servers. o Added experimental support for RFC 3030 CHUNKING and BINARYMIME; enable with ./configure --enable-chunking. Feedback on the success or otherwise of this code is solicited. o New API function to set protocol timeouts. * libESMTP 0.8.12 development release. 2002-04-24 - See ChangeLog for details. o Added missing check for STARTTLS if server does not support ESMTP. o Revoked deprecated status from smtp_option_require_all_recipients * libESMTP 0.8.11 development release. 2002-03-06 Fixed a buffer overflow which could be exploited by a malicious SMTP server. By overwriting the stack a carefully crafted response could cause arbitrary code to be executed. * libESMTP 0.8.10 development release. 2002-01-29 - Usual autoconf stuff, see ChangeLog for details. Added an NTLM authentication module. Currently this requires OpenSSL to build. This has not seen much in the way of testing as I don't have regular access to a server which requires NTLM authentication for SMTP. However it does generate the correct responses for the test cases I have tried. Feedback on the success or otherwise of this module is solicited. Compilation with --enable-more-warnings=picky seems to be clean again. * libESMTP 0.8.9 development release. 2002-01-02 - See ChangeLog for details. Important: The use of libltdl is now deprecated in favour of dlopen(). libltdl is no longer distributed with libESMTP reducing tarball size. This change simplifies installation for the majority of users, however users with platforms which do not supply dlopen or libltdl must now obtain and install libltdl separately. Also Important: Building with --enable-more-warnings=yes/picky might prove akward. Recent glibc versions seem to have changed their mind about the status of strcasecmp and friends to being GNU extensions. Naturally, autoconf 2.13 detects the functions in the library but not that their declarations are unavailable. For this reason, _GNU_SOURCE is defined on gnu type platforms but this might cause inconsistent pointer declarations wrt. signedness, YMMV. If you have problems, try ./configure --disable-more-warnings. A horrible hack: Added tentative support/hack for the non-standard AUTH= syntax in EHLO responses. It might work. Don't complain to me if it doesn't. You need to ./configure --enable-nsauth for this support. This syntax was only ever described in internet drafts and never made it into RFC 2554. It should *never* have been deployed on the internet. Internet drafts are deleted after 6 months and after publication of RFCs. So there is *no* documentation for this syntax and I can't even begin to guess what it is supposed to be or what implementation errors there are wrt these unavailable documents. My advice is if this hack doesn't work, complain to your ISP and recommend that they deploy MTAs that are standards compliant. Documentation exists for standards and I am happy to make sure libESMTP complies with documents I can actually obtain. * libESMTP 0.8.8 development release. 2001-11-30 - See ChangeLog for details. o Fixes more autoconf issues. o Fixed a type mismatch that prevents compilation on some systems. * libESMTP 0.8.7 development release. 2001-11-7 - See ChangeLog for details. o Fixes minor build issues. o Improved error handling wrt getaddrinfo * libESMTP 0.8.6 development release. 2001-10-17 - See ChangeLog for details. o Fixes minor build issues. o SASL CRAM-MD5 builds without OpenSSL * libESMTP 0.8.5 development release. 2001-10-04 - See ChangeLog for details. o Header code no longer enforces presence of recipient fields. o Fixed some build issues related to the automake/libtool interaction. Reverted to autoconf 2.13 o Removed support for gethostbyname resolver interface. Please refer to the 'Dependencies' section in README. o Enhancements to STARTTLS support. o Calculation of current timezone's offset from GMT (UTC) is now portable and thread safe. * libESMTP 0.8.4 development release. 2001-08-13 - See ChangeLog for details. * libESMTP 0.8.3 development release. 2001-07-06 - See ChangeLog for details. o Support for sendmail's XUSR extension. o Fixed a bad bug which caused connections to the server to be dropped depending on the amount of buffering provided by the server. * libESMTP 0.8.2 development release. 2001-06-26 - See ChangeLog for details. o Added lots of assertions in the code. o Fixed a bad dangling pointer bug that could strike when sending messages with lines > 510 characters. o Fixed a polling bug that could cause deadlock. o Resolver interface now uses Posix standard getaddrinfo. Use of gethostbyname is deprecated. Please note that the current RFC 2822 header API is adequate but incomplete; for example, interactions between certain headers are not implemented. This will not change for a while. The current priority is to make the protocol engine robust. * libESMTP 0.8.1 development release. 2001-06-15 - See ChangeLog for details. Fixed two uninitialised variable bugs that might cause the protocol to quit without sending anything to the server. Enabled many more compiler warnings when compiling with gcc. Compiles should now be much cleaner. * libESMTP 0.8.0 development release. 2001-06-12 - See ChangeLog for details. The libESMTP feature set and API for version 1.0 is more or less complete. There have been minor changes to the arguments or semantics of some of the API functions, particularly wrt. the callback functions. Applications using previous libESMTP versions will need to be recompiled or relinked. From this point on no new features will be added and, as far as possible, API changes will be resisted. Having said that, the range of error codes will likely be expanded. Effort will now be directed at bug fixes and improving the documentation and web site, though this is likely to be a slow process. Many of the supported SMTP extensions have had only superficial testing mainly due to lack of access to servers supporting them. Developers using libESMTP are encouraged to test extensions against servers to which they have access and to submit bug reports to . The libESMTP web site will be updated in the near future to set up (finally!) mailing lists and bug tracking. In addition the web site will link to projects using libESMTP. If you would like a mention for your project, drop a line to with the details. ``` libESMTP-1.1.0/docs/authors.md000066400000000000000000000013431405645115200160330ustar00rootroot00000000000000# Author libESMTP's primary author is Brian Stafford \. Support for verifying X.509 certificates was contributed by Pawel Salek. ## Contributors Over time, particularly in libESMTP's early development, many have reported and contributed bug-fixes for which I am grateful. Some are listed below; apologies to any who have been missed. * Bas ten Berge \ * Chris Richards \ * Colin Phipps * Dmitry Maksyoma \ * Heikki Lindholm \ * Matthias Andree \ * Pawel Salek \ * Ronald F. Guilmette * Thomas Deselaers \ libESMTP-1.1.0/docs/bugreport.md000066400000000000000000000136401405645115200163620ustar00rootroot00000000000000# Reporting Bugs libESMTP will not be changed without good justification. SMTP and mail related documents in general have been subject to rigorous peer review in public by the [IETF](https://www.ietf.org/) before being accepted as standard. Since mail is possibly the most mission critical internet application of them all, it is vital that the infrastructure is not compromised by buggy implementations. The SMTP protocol is described in [RFC 5321][1]. The message format is described in [RFC 5322][2]. Various other RFCs describe the SMTP extension mechanism and specific SMTP extensions. References to the appropriate documents may be found in comments within the source code. These guidelines are intended to help distinguish features from genuine bugs. In SMTP, as with many internet protocols, the distinction is subtle at times. The following paragraphs are examples of what might constitute a bug. The list is by no means exhaustive. ## GitHub Issue Tracker Bug reports should be made using the GitHub issue tracker. Please do not use GitHub issues for bug reports against the legacy tarballs, they should be referenced against the appropriate tag in the repository, e.g. *v1.1.0*. Priority will always be given to issues in the current release. ## What to Report If you are convinced that libESMTP does not do something it should, or vice-versa, raise an issue referencing the relevant RFC. Usually behaviour that conforms to RFCs will not be changed, however, mistakes do occur in standards so you may need to also check the errata on the [RFC Editor][3] site. ### Coding Errors If you spot a mistake in the code, such as failing to check the return value of a function for an error condition, please report it. ### Missing Library Calls If libESMTP uses a C library function that is not provided by a platform then the distribution should contain a replacement for that function and Meson should detect that the replacement is needed. If neither condition is true, that is a bug. ### Broken Library Calls If libESMTP uses a C library function that is broken on a given platform then the distribution should contain a replacement for that function and Meson should detect that the replacement is needed. If neither condition is true, that is a bug. A library call is considered broken if its behaviour differs from that described in the appropriate publicly available standard. Normally, the appropriate standard is Posix or the Single Unix Specification. Remember that Unix man pages or other manufacturer specific documentation of C library functions describe an implementation and do not constitute a standard. ### SMTP Protocol Errors If libESMTP sends SMTP protocol commands which differ from those described in the appropriate RFCs, or fails to respond correctly to valid SMTP responses from a server, that is a bug that should be reported. ### Obsolete Behaviour If libESMTP implements behaviour described in an obsoleted standard and the replacement describes different behaviour, that is a bug in libESMTP. Particular care is needed when referring to RFCs as these may be obsoleted or updated at any time and the new document will have a new and unrelated number. For example, do not refer to RFC 821 or RFC 1123 since these are obsoleted by RFC 5321. -------------- ## What Not to Report Its amazing how often correct behaviour is reported as a bug. Familiarise yourself with the appropriate documentation. Also read the [libESMTP API](reference) document. Many people trip up on the subtleties of SMTP and often the documents will answer your question saving your time and mine. ### Can't Connect to Server Do not complain that libESMTP can't connect to port 25. The default port for mail submission is 587. This is a deliberate design choice and will not change. Refer to RFC 4409 for more information. ### The headers come out after the message You got the line endings wrong. libESMTP strictly adheres to the RFC 5322 message format. RFC 5322 requires that lines in a message are terminated with the sequence CR-LF (0x0D 0x0A or \r\n). ### Standards Compliance Do not report behaviour that conforms to normative requirements in a standard as a bug, even if you don't like what happens or you find it inconvenient in some way. ### It's Different to ... Do not assume that behaviour which differs from your favourite mail client is a bug. Just because Mozilla or Outlook or whatever might do something differently does not necessarily mean they are correct and libESMTP is wrong. ### Obsolete Behaviour Do not report behaviour that differs from requirements in obsolete standards as bugs. For example, RFC 821 does not permit the syntax `MAIL FROM <>` but RFC 5321 does. ### Server Bugs Do not report bugs in SMTP servers or server misconfiguration as libESMTP bugs. However, if a server is so broken that libESMTP requires a workaround to operate with it at all I am interested in hearing about it. A good example of this sort of thing was the broken SMTP AUTH extension deployed by Yahoo!. This server uses a syntax described in an obsolete and unobtainable internet draft and did not implement the syntax described in the standard. Fortunately, in this case, the workaround was easy to implement and did not disrupt interoperation with correctly implemented servers. ### Behaviour Behind a Firewall Don't report libESMTP's use of hostnames or IP addresses that are not visible on the internet side of a firewall. Don't report that NAT makes these unusable. When a firewall is in use, especially one that does NAT, it is normal to submit mail via a local MTA that knows how to translate and/or qualify domain names and how to enforce site policy. If the firewall permits access to port 25 on the internet for hosts without publicly known hostnames and IP addresses, any mail client will eventually encounter problems with some servers. [1]: https://www.rfc-editor.org/info/rfc5321 [2]: https://www.rfc-editor.org/info/rfc5322 [3]: https://www.rfc-editor.org/ libESMTP-1.1.0/docs/certificates.md000066400000000000000000000140341405645115200170140ustar00rootroot00000000000000# TLS Certificates ## Server Certificate Validation When libESMTP connects to an upstream MTA and is configured to use TLS it checks the server certificate for acceptable security. First the certificate is checked for validity against the CA list. Next, libESMTP checks that the cipher is sufficeintly strong. In this case *sufficiently strong* means that the cipher has at least a 40 bit key. Recent versions of the TLS protocol never negotiate such a weak key, however an application supplied SSL_CTX may support obsolete SSL versions. If the server certificate has a subjectAltName field, libESMTP checks that the server's domain name matches one of the subjectAltNames. If a subjectAltName is not present, the certificate's commonName is used. It is expected that the MTA's server certificate will be configured with the host's canonic domain name. Therefore when libESMTP connects to the MTA, it retrieves the server's canonic domain name which is used to check the certificate. The host's canonic name will differ only if the host name refers to a CNAME record in the DNS. Domain names are compared using the wildcard match described in RFC 2818. ## Client Certificate During connection, libESMTP also checks if a client certificate is available which is presented to the MTA on request. The client certificate can be specific to a host or a fallback certificate presented. It is not normally necessary to provide a client certificate. If client certificates are protected with a password, OpenSSL requests passwords on the standard input unless a password callback is provided. Therefore it is recommended that all applications set a callback using `smtp_starttls_set_password_cb()`. Alternatively an application SSL_CTX can be configured for libESMTP to use via `smtp_starttls_set_ctx()`. ## Initialisation Unless an application provides an OpenSSL SSL_CTX using `smtp_starttls_set_ctx()` libESMTP initialises one when necessary. From version 1.1.0, libESMTP follows [Open Desktop XDG][3] file layout conventions; certificates and private keys are loaded as follows: File or sub-directory | Description ----------------------|------------ $CONFIG/ca/ | user's hashed CA directory $CONFIG/ca.pem | user's trusted CA list $CONFIG/private/smtp-starttls.pem | user's certificate and private key $CONFIG/private/$HOST.pem | host-specific certificate and private key where `$CONFIG` is defined as if ``` sh CONFIG=${XDG_CONFIG_HOME:-$HOME/.config}/libesmtp ``` were specified to the shell and `$HOST` is the canonic host name of the MTA. Use the [`openssl rehash`][4] command to create the hashed CA directory symbolic links if required. ### Legacy Convention The deprecated libESMTP legacy file layout convention is as follows: File or sub-directory | Description ----------------------|------------ $CONFIG/ca/ | user's hashed CA directory $CONFIG/ca.pem | user's trusted CA list $CONFIG/private/smtp-starttls.pem | user's certificate and private key $CONFIG/$HOST/private/smtp-starttls.pem | host-specific certificate and private key where `$CONFIG` is defined as if ``` sh CONFIG=$HOME/.authenticate ``` were specified to the shell and `$HOST` is the canonic host name of the MTA. libESMTP may be configured to follow the legacy convention at compile time. Note that other than the location of `$CONFIG` the legacy and XDG conventions differ in the filenames for host-specific client certificates. APIs and their semantics are identical for both legacy and XDG layouts. ## OpenSSL Default Paths If neither the `ca` directory nor `ca.pem` exist, the OpenSSL default locations are used instead. This is recommended practice since the host system will usually have an up-to-date list of Certificate Authorities installed as part of its OpenSSL configuration. ## Certificate Passwords If the user's certificate is protected by a password, it is requested when the SSL_CTX is initialised. It is not necessary to provide a client certificate, however if one is supplied it is presented to the server only if requested. Note that certain servers may refuse to accept mail unless a client certificate is available. The SSL_CTX created by libESMTP supports only TLSv1 protocols and higher. ## Permissions Certificate files and the `ca` directory must be owned and readable only by their real owner; group and other permissions must not be set, that is, `ca` must have mode __0700__ or __0500__ and certificate files should be regular with mode __0400__ or __0600__. File status is checked using the `stat()` system call so symbolic or hard links may be used to avoid duplication where necessary. It is strongly recommended that other directories, in particular `private` should have the mode __0700__ or __0500__. If permissions and file ownership do not follow these rules, libESMTP ignores the affected files. If certificate files are protected by passwords, libESMTP will request the password using a callback function when needed. ## Connection When libESMTP is about to switch to TLS when processing the STARTTLS verb, it checks if a host-specific client certificate exists with a pathname as defined above. If it exists, it is used instead of the default user certificate. Note that some servers may require further authentication, even if a certificate is presented. libESMTP supports the EXTERNAL SASL mechanism using the server certificate's commonName. ## Alternative SSL_CTX Initialisation An application may wish to supply its own SSL_CTX instead of using the one automatically created by libESMTP, for example to use SSL or TLS protocols not supported by libESMTP. This may done using [`smtp_starttls_set_ctx()`][1] which must be called before [`smtp_start_session()`][2]. Note that when using an application supplied SSL_CTX, libESMTP does not load CA certificate chains or a default client certificate, however, it still checks for host-specific client certificates as described above. [1]: smtp-tls.html#c.smtp_starttls_set_ctx [2]: smtp-api.html#c.smtp_start_session [3]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [4]: https://www.openssl.org/docs/man1.1.1/man1/c_rehash.html libESMTP-1.1.0/docs/changes-since-v1.0.6.md000066400000000000000000000073551405645115200177140ustar00rootroot00000000000000# Changes since v1.0.6 libESMTP v1.1.0 is an interim release, pending some roadmap items currently in development. While libESMTP 1.0.6 has been stable for some time, bit-rot inevitably occurs as the state-of-the-art and system conventions change over time and therefore libESMTP must be updated. It is hoped that these updates will provide a more modern base for future development and improve the quality of the associated documentation. --- [CVE-2019-19977][3] is fixed. A linker map is now used to ensure only libESMTP's API symbols are made publicly available. This should prevent the possibility that a libESMTP internal symbol collides with an application or other library. Existing interfaces and semantics are unchanged; existing applications should link correctly with the new libESMTP binary, however applications which rely on internal symbols will no longer link. libESMTP is updated to use the current [OpenSSL][4] API. Therefore OpenSSL v1.1.0 or later is now required. The GNU autotools build has been completely removed and replaced by [Meson][1]. Meson builds are easy to maintain and Meson is particularly effective when used in conjunction with [Ninja][2] offering dramatically reduced build times. [Open Desktop XDG][5] conventions are now used when searching for files. Currently this affects the name and location of X.509 certificate files. This change should be transparent to applications, however users may need to relocate client certificates. A configuration option allows the legacy layout to be selected at build time. API documentation is migrated to [kernel-doc][6] style comments in source files and Markdown files for non-API sections. Because of this many of the changes to source files look more drastic than they actually are, an impression somewhat amplified by corrections or updates to RFC numbers to match current standards. The MTA's canonic hostname is used to check certificate validity, this may differ from the specified hostname if it references a CNAME record in the DNS. The new 'smtp\_get\_server\_name()' API may be used to retrieve this. The 'application data' interface has been improved. The updated API accepts a 'release' callback argument which libESMTP will call when necessary. This relieves the application from releasing allocated resources and should eliminate one class of potential memory leaks. The 'getaddrinfo()' replacement implementation has been removed since that interface is ubiquitous in modern C and resolver libraries and since the replacement was never a complete implementation. ## Summary * CVE-2019-19977: avoid potential stack overflow in NTLM authenticator. * Migrate build system to Meson * Remove GNU libltdl support, assume dlopen() always available. * Use a linker map to restrict public symbols to API only. * Add sentinel and 'format printf' attributes to function declarations. * Remove getaddrinfo() implementation. * Use strlcpy() for safer string copies, provide implementation for systems that need it. * Update 'application data' APIs * Add 'smtp\_get\_server\_name()' API. * Collect replacement functions into missing.c * Prohibit Resent-Reply-To: header. * Use canonic domain name of MTA where known (e.g. due to CNAME record in DNS). * Implement rfc2822date() with strftime() if available. * add option for XDG file layout convention instead of ~/.authenticate * OpenSSL - Remove support for OpenSSL versions before v1.1.0 - Update OpenSSL API calls used for modern versions - Require TLS v1 or higher [1]: https://mesonbuild.com/ [2]: https://ninja-build.org/ [3]: https://nvd.nist.gov/vuln/detail/CVE-2019-19977 [4]: https://www.openssl.org/ [5]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [6]: https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html libESMTP-1.1.0/docs/conf.py000066400000000000000000000124061405645115200153250ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- project = 'libESMTP' copyright = '2021, Brian Stafford' author = 'Brian Stafford' # The short X.Y version version = '1.1' # The full version, including alpha/beta/rc tags release = '1.1.0' # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'recommonmark', 'sphinx.ext.githubpages', 'sphinx_markdown_tables', 'sphinx_rtd_theme', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = ['.rst', '.md'] # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. # language = 'c' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} html_logo = 'pillarbox.png' # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'libESMTPdoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'libESMTP.tex', 'libESMTP Documentation', 'Brian Stafford', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'libesmtp', 'libESMTP Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'libESMTP', 'libESMTP Documentation', author, 'libESMTP', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- libESMTP-1.1.0/docs/critique.md000066400000000000000000000543751405645115200162100ustar00rootroot00000000000000# API Critique Recently I have been revisiting aspects of libESMTP and considering what may or may not be needed to bring the library up to date, since it is more than a decade since it has had any development. I felt it might be useful to lay out my observations and rationale for any changes. I will also consider creating language bindings since implementing these often gives some clarity on what might be missing from a C API. I feel that libESMTP has remained free of any significant bitrot but there is definitely room for improvement. ---- ## API Design I wanted libESMTP to have a small API. I reasoned that since sending an email should be a simple thing to do, the API should be small. Very early on I realised that an SMTP interaction with an MSA (Message Submission Agent) decomposed into one or more messages each with one or more recipients. This mapped very nicely into three objects representing each of these concepts and formed the basis of the API, each object being functionally distinct with their own methods to configure them. Furthermore it was very natural that the SMTP interaction, or *session* as I called it was a container for messages which in turn were containers for their recipients. Another benefit that became clear was that this approach allowed the entire interaction to be controlled with a single API call. At this point in the design the API consisted of functions to create and configure each of the objects. As an objective of libESMTP was to support a comprehensive set of SMTP extensions, it transpired that quite a few APIs were required to configure each of the libESMTP objects. So far, so good. Originally I had intended that when a session was finished the application could iterate the messages and recipients within the SMTP session and discover whether messages had been transmitted successfully or whether any or off the of the recipients were rejected of failed for any reason. This proved to be satisfactory for simple command line type programs but not so good for interactive programs that might wish to present some sort of progress indication or report status as the session progressed. Therefore I introduced a callback mechanism to report events as the protocol progressed. A further callback was added so that the SMTP interaction could be monitored while omitting the actual message transfer itself. Another consideration was that although RFC 821 and RFC 822 and their successors are orthogonal to each other, that is message format is independent of the transmission protocol, there is slight crossover because an MTA is required to add a Received: header to messages in transit, and certain headers are required or prohibited in newly submitted messages. While libESMTP can handle most of this transparently to the application, it proved useful to add API calls to provide finer control of this. The number of calls in the API was starting to grow. This had bothered me as it meant that the API would be harder to learn and went against the philosophy that sending a mail sould be a simple thing to do. Nowadays, this aspect bothers me less than it used to do, libESMTP still has a fairly small API by modern standards and each API has a specific purpose with few arguments. ### ABI One of my earliest decisions was that the ABI should be unaffected by internal changes in libESMTP, such as bug fixes or new features. The easiest way to achieve this was to make all libESMTP's structures opaque so that their content was affected or accessed only through API calls. The actual structure definitions could be kept private to libESMTP's code. This was easily achieved since C allows structure declarations without defining their content, as long as you only manipulate pointers to the structures. Since they are still treated as distinct types, errors in usage can be detected at compile time rather than by faulting at runtime. It still surprises me two decades later that I still occasionally find libraries that fail to hide their structures as well as libESMTP, although there are cases where this is not possible. ### Extensibility The API has proven extensible since the associated objects can be modified, if necessary, without breaking the ABI. New methods are easily added by following the naming patterns for their respective API. ### Ease of Use I feel that libESMTP's API is easy to use. Each object is logically distinct and directly relates to SMTP concepts and each method has a single well defined function acting on its object. Basic use cases require only a fraction of the full API to implement, in that respect I feel the original design goal is achieved. As originally designed, the libESMTP API created objects and configured them as required, however few accessors were provided as it was expected that applications would only query status after the fact when a session completed. This has proven to be inconvenient in certain circumstances, for example, it is difficult to query a recipient object for its mailbox address. The lack of accessors also complicates the event callback interface. When writing a binding for languages whose objects support properties, the lack of accessors means properties are difficult to implement. This is discussed below for Python. ---- ## Naming Conventions ### Namespace Since C has no concept of namespaces for functions or variables, all the API calls are prefixed with `smtp_`. I thought about using `esmtp_` but that seemed too long! ### Objects and Methods As with namespaces, C has no concept of objects or classes. structs being the most similar construct available. libESMTP's objects are implemented as structs allocated and initialised by certain API calls, returning a pointer to the application. Pointers for the three struct types were declared as `smtp_session_t`, `smtp_message_t` and `smtp_recipient_t` (an additional type was created for the ETRN extension). On reflection, I feel I made a mistake in the API naming convention for the object methods. I think I was trying to get them to read easily, since the `namespace_object_method` convention tends to read backwards at times, nevertheless this would probably have resulted in a more intuitive and more easily memorised API. These deficiencies make a simple mapping of API names to method names in object oriented language bindings particularly difficult and non-obvious. Had I designed the API nowadays, I would follow the more rigorous approach used in frameworks like GObject. ## Internal Interfaces Unfortunately, libESMTP did not hide its internal interfaces from public access, it is possible to link against any of its symbols at global scope. It is important to prevent linking against internal interfaces, since there may be unintended conflicts with symbols in third-party libraries or application code. The use of undocumented internal APIs can be a major barrier to development, especially if significant applications rely on them. Using a consistent prefix for public symbols makes it easy, using wildcards, to create a linker map file to remove public references to internal calls, which do not use the namespace prefix. Without a consistent prefix, each publicly available symbol must be explicitly listed, this is error prone since it is easy to forget or misspell a name and there is no easy way to automatically check this. ---- ## Application Data The application data API is problematic. The idea was to set an arbitrary pointer to data maintained by an application and associated with one of the libESMTP objects. I followed a design pattern which set a pointer and returned the old pointer which could then be deallocated or passed back to the application. Unfortunately this approach requires an application to iterate all the libESMTP structures fetching back the pointer and deallocating it prior to destroying the libESMTP session. This significantly complicates use of libESMTP, is error prone and subject to memory leaks if not executed correctly. A better design would provide a *release* function to free or otherwise release the application data. libESMTP can guarantee to call this at the correct time, significantly easing the application design. A well designed application data interface is important for many applications and is especially so for implementing language bindings, particluarly as neither side can control the other's memory management strategy and since weak bindings may also be necessary. ---- ## Error Handling Where API calls might fail they consistently return either zero or a NULL pointer on failure, and non-zero/NULL values on success. The actual reason for failure is set in a global (or thread local) variable. This was modelled after the standard C library's `errno` variable. I'm not sure whether this is a satisfactory design but it does have precedent so it is a familiar pattern. A second category of error occurs during a protocol exchange. This occurs when the peer reports a problem via a status code, for example, a recipient mailbox may not exist. libESMTP does not consider this an API failure, instead it provides APIs to allow the application to query status after the protocol session completes. As noted above the event callback may be used to report protocol status on-the-fly. ---- ## Type Safety Although C is not a strongly typed language the libESMTP API is reasonably type-safe. There are, however, two parts of the public API and a few internal interfaces that use variadic functions, the event callback and the message header API. The latter is discussed further below. Unfortunately these interfaces cannot be validated for type-correct arguments either at compile time or runtime. The internal interfaces may be verified by careful code review and static analysis, or by the compiler for the printf-like interfaces. Unfortunately this must also be done for every project using libESMTP. Since the variadic functions in the header API have only a few variations, a possible solution is simply to provide a variant for each function for each combination of types. ---- ## Callback Design Ideally callbacks should be function closures, however C does not provide closures. This is resolved by providing an extra closure argument when the callback is registered and supplying that argument back to the callback. This is conventional in many C language APIs. ### Event Callback Type Safety Unfortunately the event callback's function is somewhat overloaded. Similar events often have inconsistent arguments and semantics and the remaining events are special cases. This design flaw is compounded since the varargs macros must be used to process the callback arguments which is error prone, and impossible to check either at compile time or run time. Errors introduced writing the event callback might only be detected when the application crashes. This is particularly evident when trying to implement language bindings -- translating the event callback into something appropriate to the host language becomes significantly more complex than it perhaps need to be, even for a closely related language like C++. Fortunately callbacks other than the event callback do not suffer this issue. ### Message Callback I feel that I made my worst design decisions when implementing the message callback. Memory management in the message callback is poor. The first argument to the callback is a pointer which can reference any arbitrary state the applicaton maintains while reading the message. However when libESMTP is finished reading the message if that pointer is not NULL it is passed to 'free()'. This obliges the callback to use 'malloc()' but what if the application wants to reference its own private structures? Furthermore the application must use the malloc that pairs with the free libESMTP is linked against; sometimes this can be problematic and usually only discovered when the application faults. Another problem is that the message callback design means the callback must allocate any state it requires on first call and so must check for first call on every call. Although the overhead of doing this is small, it complicates the code and makes it harder to read, doubly so since this behaviour was never properly documented. This is a pity because libESMTP's internal logic knows both when it is about to use the callback for the first time and when it has finished reading the message. Worse still, one of the arguments in the message callback is set to NULL to signal that the input stream should be rewound to the beginning of input; once more this strange behaviour is undocumented. All of these objections could be improved by expanding the message callback into three *open*, *read* and *close* phases and eliminating the implicit free. The original API can be layered over this interface for backward compatibility. ### File and String Reader Callbacks libESMTP provides two standard callbacks for reading messages from a string or a FILE pointer. On reflection, I think the APIs to set these callbacks should have been provided as real functions in the library rather than as macros. Had they been functions, it would have been possible to remedy the objections discussed above in a new message API design and existing applications using an updated libESMTP would automatically use the new interface. The macros have made this impossible. ---- ### Iterators It is a pity that libESMTP did not implement iterators in its API. In the libESMTP API, messages and recipients (and ETRN) may be iterated using the 'enumerate' APIs. These take a callback function to process each item. For example, because C does not provide function closures, a callback function has no access to variables within the scope of the calling function. One way to work around this limitation is to put variables from the outer scope in a struct and pass a pointer to the struct as the callback argument. It works but it is always an ugly hack. On reflection, a callback based design for iterating structures is really only a good approach in languages that provide function closures, particularly those that allow anonymous or lambda functions. Iterators are almost always more convenient and intuitive to use and easier to use in language bindings. ---- ## Language Bindings I think it is useful to consider providing language bindings for libESMTP. Doing so, it became obvious that certain aspects of libESMTP's API design makes this more difficult than it needs to be. ### Callbacks The deficiencies in the event callback noted previously make binding to a language's event mechanism more verbose than necessary and type safety is lost in the process; typically this would have to be implemented as a 'big switch' on the event type which selects the correct varargs statements to convert the arguments. ### Host Language Objects Because there is typically a one-to-one mapping between the bound language and libESMTP's objects, they must be associated with each other. The application data APIs may be used to do this. The deficiencies in the application data API described above make this more difficult as the bound language's objects may be reference counted or must be otherwise released to a garbage collector. ### Names Interfacing the libESMTP objects to the host language equivalents should be simple enough however, as previously noted, the lack of a rigorous naming convention means that the mapping from API name to the host language's method or property names for each object may not always be clear. ## Python Python provides a comprehensive C API to integrate C libraries or code into applications either directly or via its module system. I feel that if all the issues described are addressed this would be much simpler to implement. In particular iterators and accessors, if available, would enable a much more Pythonic result. Interfacing callbacks should not be problematic, even with libESMTP's current API, however the glue code would face issues with correctly handling variadic callbacks. For example the sequence ``` c smtp_session_t session; smtp_message_t message; smtp_recipient_t recipient; session = smtp_create_session (); smtp_set_server (session, "example.org:587"); /* ... */ message = smtp_add_message (session); smtp_set_reverse_path (message, "brian@example.org"); recipient = smtp_add_recipient (message, "douglas@h2g2.info"); /* ... */ smtp_start_session (session); ``` might be rendered in Python as ``` python from libESMTP import Session, Message, Recipient session = Session() session.set_server ('example.org:587') # ... message = Message(session) message.set_reverse_path("brian@example.org") recipient = Recipient(message, 'douglas@h2g2.info') # ... session.start() ``` Unfortunately the constructors bear little relation to the C equivalents nor do the method API names have a clear mapping. Providing factory methods might be a good idea, for example ``` python message = session.add_message() ``` which has the benefit of being closer to the C API, and therefore more intuitive, and requires fewer imports. If libESMTP provided more accessors for some of its internal variables the reverse path mailbox for a message could be more naturally expressed as a property. Even without accessors, this would still be possible but would require the glue code to shadow the appropriate value which is both wasteful and error prone. ``` python message.reverse_path = 'brian@example.org' print(message.reverse_path) ``` The lack of iterators makes adding Python iterators or generator expressions difficult or impossible. For instance, it should be possible to check recipient status something like this: ``` python session.start() for message in session.messages(): print('From:', message.reverse_path) for recipient in message.recipients(): print('To:', recipient.mailbox, recipient.status) ``` or even use a comprehension ``` python status = {recipient.mailbox: recipient.status for recipient in message.recipients()} ``` Interfacing a Python *file like* object to a revised message callback should be a good test that the design is correct. With these changes the example could be rewritten to be more Pythonic. ``` python from libESMTP import Session session = Session() session.server = 'example.org:587' # ... message = session.add_message() message.reverse_path = 'brian@example.org' with open('message.txt','r') as filp: message.fromfile(filp) recipient = message.add_recipient('douglas@h2g2.info') # ... session.start() for message in session.messages(): print('From:', message.reverse_path) for recipient in message.recipients(): print('To:', recipient.mailbox, recipient.status) ``` ### C++ While the libESMTP API can be used directly in C++, a proper language binding would offer some benefits, especially since C++11 and later are arguably quite different to earlier versions of the language. Following some of the design patterns in the STL would provide a much more natural API for modern C++, especially as libESMTP's objects share some characteristics with STL containers. Two STL patterns that come to mind are iterators and callbacks. libESMTP's session and message objects share characteristics of *std::forward_list* an should follow their APIs. Allowing callbacks to use *std::function* values would permit use of lambda functions or any compatible object which overrides the '()' operator. Finally a C++ API could be created so that modern memory management practice is observed, such as construction in-place and the no naked new or delete rule. ### Lua Lua is an interesting case since it is a purely procedural language, however its data structure, the table, adds extraordinary flexibility in the choice of programming methodology. Lua also natively supports iterators. Using Lua's C API it would be almost trivial to add a one-to-one mapping of C APIs to Lua APIs but this would be a suboptimal approach. Lua tables can act both as an object and a type, via the use of metatables. Therefore Lua conventions are also better served by an object oriented approach but once again the difficulties outlined above become apparent. ### GObject GObject is a C framework rather than a language however it is a useful case to consider. When integrating libESMTP into a GTK+ program, having GObject APIs would be of some benefit. For example, making object state available as properties, mapping the libESMTP callbacks to GObject's signal mechanism or taking advantage of GObject reference counting, introspection mechanisms and language bindings, such as Vala. libESMTP sessions could even be constructed using GBuilder XML files. ### Other Languages Resolving issues for C++, Python and Lua should simplify writing bindings for other languages, such as PHP, Ruby or D, especially if the basic set of bindings were provided as a standard part of the libESMTP release. ---- ## Conclusion I feel it is useful to be self-critical of design decisions in various projects. On reflection I think I got libESMTP mostly right but there are deficiencies that are usefully remedied. This critique therefore serves as a loose plan for further development. All the topics above can be resolved by extending the libESMTP API to create a strict superset and without having to alter the semantics of the existing API. Accessors for the libESMTP object state, where missing, are easily added and have no impact on the existing API. The event callback can be refactored into a set of type safe callbacks. An improved application data API has already been designed and implemented. Where features are updated, the original APIs can be retained with deprecated status. This means the shared library can continue to work with existing applications but use of deprecated features in new programs can be flagged with compiler warnings or errors. Although the API naming could be redesigned for better consistency and this could be done retaining the original names with deprecated status, I don't think it is worth the effort. It would be confusing to have two names for many APIs and documentation, always a weak spot in many projects, would be overly complicated by this. I feel that an important aspect of contemporary libraries is bindings for multiple languages. It should be straightforward, having addressed the issues outlined here, to provide official bindings for C++, Python, Lua and GObject. These should also serve as effective models for further bindings. None of these are large or difficult changes to implement but should considerably enhance the API as libESMTP enters its third decade. ---- Brian Stafford, April 2021. libESMTP-1.1.0/docs/download.md000066400000000000000000000060141405645115200161550ustar00rootroot00000000000000# Download LibESMTP is considered stable. Source code is available from [GitHub](https://github.com/libesmtp/libESMTP). The current version of libESMTP is 1.1.0. Earlier versions are not recommended. Clone the repository as follows: ``` sh $ git clone https://github.com/libesmtp/libESMTP.git ``` ## Dependencies libESMTP has the following optional dependencies. ### OpenSSL [OpenSSL v1.1.0](https://www.openssl.org/) or later is required to build the SMTP STARTTLS extension and to build the SASL NTLM authentication module. libESMTP may be built without OpenSSL, however most contemporary mail submission agents require TLS connections. ### ISC Bind 9 libESMTP supports the Lightweight Resolver (lwres), provided by the [ISC BIND 9](https://www.isc.org/), which may be used in preference to the standard resolver. BIND 9 also provides getaddrinfo() as part of the standard resolver should it be unavailable on the target platform's C library. ## Installation LibESMTP uses the [Meson build system](https://mesonbuild.com/Getting-meson.html). Refer to the Meson manual for standard configuration options. Meson supports multiple build system backends. To build with [Ninja](https://ninja-build.org/) do the following: ``` sh $ meson [options] --buildtype=release builddir $ ninja -C builddir install ``` Note that the meson/ninja installer does not require an explicit `sudo`, instead it will prompt for a password during install. This avoids polluting builddir with files owned by root. As well as the standard meson options, the following are supported: Option | Values | Description -------|--------|------------ xdg | **true**, false | use XDG directory layout instead of ~/.authenticate pthreads | enabled, disabled, **auto** | build with support for Posix threads tls | enabled, disabled, **auto** | support the STARTTLS extension and NTLM authentication lwres | enabled, **disabled**, auto | use the ISC lightweight resolver bdat | **true**, false | enable SMTP BDAT extension etrn | **true**, false | enable SMTP ETRN extension xusr | **true**, false | enable sendmail XUSR extension Options are specified as `-D