pax_global_header00006660000000000000000000000064126146277530014527gustar00rootroot0000000000000052 comment=e0aaf811fc2cd0d368759f3e6c26251a63d42a29 jabberd2-jabberd-2.3.4/000077500000000000000000000000001261462775300145775ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/.gitignore000066400000000000000000000010411261462775300165630ustar00rootroot00000000000000.libs/ .deps/ *.o *.lo *.la *.so *~ *.swp Makefile Makefile.in aclocal.m4 ac-stdint.h autom4te.cache config.guess config.h config.h.in config.log config.status config.sub configure depcomp Doxyfile INSTALL install-sh libtool ltmain.sh missing stamp-h1 compile c2s/c2s etc/*.conf etc/*.cfg.dist etc/*.xml.dist etc/*.service etc/templates/*.xml.dist man/c2s.8 man/jabberd.8 man/resolver.8 man/router.8 man/s2s.8 man/sm.8 router/router s2s/s2s sm/sm tools/jabberd tests/config/configtest docs/code /tests/check_config /tests/check_nad /test-driver jabberd2-jabberd-2.3.4/AUTHORS000066400000000000000000000114651261462775300156560ustar00rootroot00000000000000The main culprits for this release are: Ryan Eatmon - Much of the early work on jadc2s, which fed into the design of SX and the components. Also the startup script, and some excellent design work which helped to set the long term goals for the project (router meshing, distributed components, etc). Jeremie Miller - Getting the project off the ground in the first place. MIO, much of the SM core (formerly jadlsm), most of the utilties (which came from the 1.4 server), and of course the NAD subsystem, which is the boon and the bane of a j2 developers' life ;) Thomas Muldowney - The original Autotools-based build system, some early jadc2s work (rate limiting), utilities, and lots of good testing and debugging advice. Robert Norris - Overall system design, pretty much all the other code. Stephen Marquard - Uber bug fixer. Many new features. Tomasz Sterna - Maintenance, new features, bug fixing, merging. Current coordinator of the project. Adam Strzelecki - Win32 porting, installer and MIO Other people who chipped in: Casey Crabb - Original DB4.1 support - Original private XML storage module Matthias Wimmer - IPv6 support - Misc bugfixes and testing William Uther - Base64 passwords for pipe-auth Wim Lewis - SX partial write support - Numerous fixes for BSD Mike Prince - SQL templates for MySQL/PostgreSQL authreg modules Jamin W. Collins - Command line parsing fixes Jacek Konieczny - Misc bugfixes maqi - Doxygen bootstrapping Karsten Huneycutt - Patch to get PAM working on non-Linux systems Shane DeRidder - Patch for configurable syslog facility Magnus Henoch - Patch for proper router connect retry on OpenBSD Dudley Carr - Patches to bring mod_privacy in line with XMPP-IM Patrick Bihan-Faou - Patch to use PAM account management functions Peter Hinz - Original Win32 port - Misc bugfixes Karsten Petersen - Misc bugfixes, leak fixes and cleanups Etan Reisner - Patch to configure c2s to require TLS before auth Albert Chin - Various fixes to get things running on Solaris, AIX & Tru64 Tomasz Sieprawski - XMPP Ping module Priit Laes - code cleanups Simon Wilkinson - Cyrus SASL backend - security level dependant authorisation methods Oles Hnatkevych - MySQL backend fixes Andrew Klang - LDAP backend fixes Klara Mall - SSL fix Kaspar Brand - SSL fix Gonzalo Barrio - LDAP backend features - Oracle backend fixes Reinhard Max - PostgreSQL backend fixes - SQLite storage module Stefan Huehner - compilation fixes Michael Moeller - FS storage module Nicolas Pouillon - SQLite backend fixes Mark Doliner - roster handling fixes Christof Meerwald - SQLite fixes - epoll MIO backend Maxim Britov - using system expat library Cedric Vivier - PostgreSQL schema changes - AMP module - offline storage message and presence dropping option Russ Schnapp - MOTD date fix Lucas Nussbaum - mod_status saving statuses in DB Robert Quattlebaum - full vCard support Michael Krelin - PostgreSQL related fixes Nikita Smirnov - LDAPfull and LDAPvCard backends Michael John Wensley - XEP-0054 completness, server vcards Simon Arlott - asynchronous DNS resolver for s2s - TLS certificates for each vhost - misc fixes Christopher Parker - SQLite3 backend Oleksiy Kramarenko - Oracle DB backend fixes Thanks also go to the testers and bug reporters out there - you know who you are. Special thanks in this capacity to Justin Kirby, whose many failed efforts to compile j2 helped get much of the build system to where it is today. If you're have questions or problems, please check the README file for places you can go for help. Expect to be ignored if you contact the authors directly. jabberd2-jabberd-2.3.4/COPYING000066400000000000000000000433211261462775300156350ustar00rootroot00000000000000 As a special exception, the authors give permission to link this program with the OpenSSL library and distribute the resulting binary. 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. jabberd2-jabberd-2.3.4/ChangeLog000066400000000000000000000000611261462775300163460ustar00rootroot00000000000000See https://github.com/jabberd2/jabberd2/commits jabberd2-jabberd-2.3.4/Doxyfile.in000066400000000000000000001263451261462775300167250ustar00rootroot00000000000000# Doxyfile 1.3.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = jabberd2 # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = docs/code # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en # (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, # Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = . # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 10 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = mio scod sx util c2s resolver router sm s2s # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs FILE_PATTERNS = *.c *.h *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = . # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output dir. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superceded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similiar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO # The CGI_NAME tag should be the name of the CGI script that # starts the search engine (doxysearch) with the correct parameters. # A script with this name will be generated by doxygen. CGI_NAME = search.cgi # The CGI_URL tag should be the absolute URL to the directory where the # cgi binaries are located. See the documentation of your http daemon for # details. CGI_URL = # The DOC_URL tag should be the absolute URL to the directory where the # documentation is located. If left blank the absolute path to the # documentation, with file:// prepended to it, will be used. DOC_URL = # The DOC_ABSPATH tag should be the absolute path to the directory where the # documentation is located. If left blank the directory on the local machine # will be used. DOC_ABSPATH = # The BIN_ABSPATH tag must point to the directory where the doxysearch binary # is installed. BIN_ABSPATH = /usr/local/bin/ # The EXT_DOC_PATHS tag can be used to specify one or more paths to # documentation generated for other projects. This allows doxysearch to search # the documentation for these projects as well. EXT_DOC_PATHS = jabberd2-jabberd-2.3.4/Makefile.am000066400000000000000000000010011261462775300166230ustar00rootroot00000000000000EXTRA_DIST = Doxyfile.in README.md README.win32 README.protocol README.config contrib docs win32 LIBTOOL += --quiet SUBDIRS = etc man if USE_LIBSUBST SUBDIRS += subst endif SUBDIRS += tools mio sx util c2s router s2s storage sm if ENABLE_TESTS SUBDIRS += tests endif .PHONY: docs docs: Doxyfile @doxygen dist-hook: if grep 'AC_INIT.*dev' configure.ac ; then echo "Remove 'dev' version flag first!"; exit 1; else : ; fi find $(distdir) -depth \( -name CVS -o -name .svn -o -name .git \) -exec rm -rf {} \; jabberd2-jabberd-2.3.4/NEWS000066400000000000000000000462761261462775300153150ustar00rootroot00000000000000This file contains news, important changes and upgrade instructions between different versions of jabberd2. * 2.3.3 to 2.3.4 upgrade: What changed: - Rewrite TLS ephemeral key + cipher handling - Recover Berkeley DB before opening it - bcrypt support for PostgreSQL - Option to set authreg module per realm - AuthReg ANONYMOUS does not offer password check - Answer to disco#info queries to user JID - WebSocket C2S SX plugin ANONYMOUS login was extended and fixed, so make sure it still works for you if you were using it in its semi-broken state before. See sm.xml for notes on configuring ANONYMOUS login and apply accordingly. Notice additional module in pkt-user chain in sm.xml. C2S support for WebSocket connections is documented in c2s.xml. Notice changes to HTTP-Forward option - it requires enabled WebSocket support. * 2.3.2 to 2.3.3 upgrade: What changed: - Support for RSA/DH/ECDH key agreement - bcrypt support for MySQL storage - C2S per session user data & authreg auth API extensions for custom authreg backends - Option to provide a custom the openssl library path * 2.3.1 to 2.3.2 upgrade: What changed: - Removed unmaintained CyrusSASL backend - Option to add realm to username in ldapvcard module - systemd unit files * 2.3.0 to 2.3.1 upgrade: What changed: - Marked "TLS-Everywhere" as EXPERIMENTAL feature - default EXPERIMENTAL to 'no' - default SUPERSEDED to 'no' - moved STANZA-ACK and MY-IP-ADDRESS XEPs and IQ-PRIVATE push out of experimental status * 2.2.17 to 2.3.0 upgrade: What changed: - Renamed non-standard UPGRADE file overwriting outdated NEWS file - Semantic Versioning: http://semver.org/ - TLS Everywhere: https://github.com/stpeter/manifesto - Required GSASL >=1.1 - jabberd should compile without warnings - out-of-source builds should work - pgsql: authreg password_type support - pgsql: schema support - ldapvcard: groupattr works even if no groupattr_regex defined - ldapfull: checks for ldap group membership on login - vCard: Assume tel phone is voice phone - MySQL: default password hashing algorithm changed to SHA512 - out-conn-reuse s2s.xml option naming unified - XML parse error will log buffer details - CRAM-MD5 auth support - router private key cachain and password support - hashed passwords support in SQLite3 storage * 2.2.16 to 2.2.17 upgrade: What changed: - cppunit was replaced by check framework - Fixed build with debug disabled * 2.2.15 to 2.2.16 upgrade: What changed: - Debug logging into file implemented See etc/*.xml.dist for instructions - Unit tests are not mandatory See --enable-tests/--disable-tests option for ./configure - Fix for invalid default router.xml (Unterminated XML comment tag) * 2.2.14 to 2.2.15 upgrade: What changed: - Merged config variables expansion - Group extraction by RegExp from LDAP - A1HASH passwords support for MySQL - PBX integration pipe implementation - Enable/disable debug output with signals USR1/USR2 - '-i ID' command line option - DB query rate limitting - Domain whitelisting support - Support enforcing TLS secured S2S connections only - Simple message logging to a directory - MIO kqueue implementation - Support for see-other-host stream redirects - Unit tests You will need cppunit(-devel) installed to get the tests built. See example configuration files on how to enable new features. * 2.2.13 to 2.2.14 upgrade: What changed: - There are example upstart configuration files in etc/ you may use. * 2.2.12 to 2.2.13 upgrade: What changed: - New authentication option 'bind' for authreg_ldapfull See etc/c2s.xml.dist for instructions - Stream Compression for S2S connections See etc/c2s.xml.dist for instructions * 2.2.11 to 2.2.12 upgrade: What changed: - published-roster Uses displayName to populate published-roster name and fallbacks to cn. * 2.2.10 to 2.2.11 upgrade: What changed: - only bugfixes * 2.2.9 to 2.2.10 upgrade: What changed: - removed mod_disco_publish (it was removed from XEP-0030) Remove disco-publish lines from your sm.xml. * 2.2.8 to 2.2.9 upgrade: What changed: - Implemented component clustering - Many virtual hosts in one SM process - FreeBSD kqueue support - Implemented PBX integration interface - crypt() password support for LDAP backend There is new section in sm.xml. You may use it to configure domains serviced by the SM process. Old style domain name in section still works for backward compatibility, but the section overrides it. You need to give different names to SM instances participating in clustering. Router needs a way to differenciate these. There is new section in c2s.xml configuration file. Please see it if you want to use the PBX integration. * 2.2.7 to 2.2.8 upgrade: What changed: - User can message/query own resources - Settable size for vCard image field - Proper server disco#info answer - Support for /etc/hosts lookup (as a last resort) - Workaround for Java SSL bug (Google servers connection problems) You may configure the vCard field size limit in sm.xml. Look at sm.xml.dist for example. * 2.2.6 to 2.2.7.1 upgrade: What changed: - Fixed issue with not supported but advertised SASL integrity protection - Workaround for buggy Java TLS implementation affecting OpenFire and GTalk There is nothing for you to do. * 2.2.5 to 2.2.6 upgrade: What changed: - added ip.origin option to s2s.xml - Implemented GSASL qop-int integrity checks - Implemented router-filter packet logging See etc/s2s.xml and etc/router-filter.xml for new options. * 2.2.4 to 2.2.5 upgrade: This is a bugfix release. There are almost none visible changes. NAD caching was removed. This should reduce memory usage and memory growth (at a cost of little more CPU usage). A key was added to the 'status' table in MySQL. This improves performance for queries to that table. The is recommended for everyone, but will have the biggest impact for installations with a large number of signons and signoffs. It only affects installations with mod_status enabled. You can add the key by running this statement: ALTER TABLE status ADD KEY (`collection-owner`(255)); * 2.2.3 to 2.2.4 upgrade: What changed: - [WIN32] libidn & gsasl downloads are now at GNU servers - Detecting unrecoverable stream errors on establishing an outgoing s2s connection - Do not offer compression if STARTTLS is required and not enabled - Return better error on STARTTLS required failure - [WIN32] Don't override server.pem on upgrade - [WIN32] Add TLS server certificate for default win32 c2s config - [WIN32] Don't fail when service fails to start (Should popup ignore box) - Implemented logging of compressed conection established - Implemented My IP Address extension Fortunately you do not need to configure anything to observe these changes, but you should be aware of them to not get surprised. * 2.2.2 to 2.2.3 upgrade: What changed: - GnuSASL 0.2.27 is required - GSSAPI support Upgrade gsasl to 0.2.27. You may use GSSAPI if you have it configured. Add to c2s.xml mechanizms. * 2.2.1 to 2.2.2 upgrade: What changed: - SCOD is gone (again) - implemented rate limiting throtling - option to limit stanzas per second See io.limits.stanzas section in etc/c2s.xml.dist and copy to yours c2s.xml. Now, when you rate limit your clients, they are throttled instead of disconnected. * 2.2.0 to 2.2.1 upgrade: What changed: - new ./configure option --without-subst - fixed router-filter - fixed rate limiting - removed "leaking" caches etc. You may disable the "license unsure" subst/ function replacements library with --without-subst. This allows Debian to include jabberd. Please see example router-filter.xml for additional notes how it works. (Please note that filter does not match resources as suggested before.) You may now expect rate limiting to actually work. Jabberd should now grow memory usage like before, but may eat a bit more CPU power. * 2.1.24 to 2.2.0 upgrade: What changed: - UDNS library required - GnuSASL 0.2.26 or higher version required - resolver component removed - fixed SSL handling Install UDNS http://www.corpit.ru/mjt/udns.html and upgrade GSASL to at least 0.2.26 version. Resolver is now built in S2S component, so you need to add section to your s2s.xml config. Then remove resolver component from your configuration. Please check your verify-mode setting in c2s.xml, and make sure it is what you wanted. See SSL_CTX_set_verify(3) manual page. * 2.1.23 to 2.1.24 upgrade: What changed: - server component presences Look at etc/sm.xml.dist to see how 'pkt-sm' chain should look now. * 2.1.22 to 2.1.23 upgrade: What changed: - XEP-0232: Software Information implemented - BerkeleyDB dump and 2-MySQL migrations scripts in tools - Updated sources to build on win32 again See sm.xml.dist config for disco-extend chain snippet for software information to add to your sm.xml. See tools/db-update.sqlite for win32 database upgrade script for win32. * 2.1.21 to 2.1.22 upgrade: What changed: - MySQL 5.0+ dependency - moved --enable-sasl configure option to --with-sasl * 2.1.20 to 2.1.21 upgrade: What changed: - LDAP backend option See c2s.xml.dist for example, how to use news option, that allows you to customize the query sent to LDAP server. * 2.1.19 to 2.1.20 upgrade: What changed: - added missing XEP-0054 fields - server vcard support - new authreg ldapfull, storage ldapvcard and sm roster-publish modules - implemented maximum stanza size limit - disabled CyrusSASL backend compilation You need to add missing columns to "vcard" table: ALTER TABLE vcard ADD "jabberid" text, ADD "mailer" text, ADD "uid" text; See c2s.xml and sm.xml for options of new modules and stanzasize. * 2.1.18 to 2.1.19 upgrade: What changed: - mod_status stores full last presence stanza - so called "offline status" support (sending last unavailable presence stanza for unavailable users) You need to add "xml" column to "status" table: ALTER TABLE "status" ADD COLUMN "xml" TEXT; * 2.1.17 to 2.1.18 upgrade: What changed: - implemented /webstatus service If you want to allow users of other servers to store their presence information in your "status" database table, add status.resource section and status module in 'pkt-sm' chain in sm.xml. See sm.xml.dist for reference. * 2.1.16 to 2.1.17 upgrade: What changed: - s2s maximum fds option implemented If you want to configure maximum file descriptors for s2s, look in s2s.xml.dist for io/max_fds option, that mirrors the same option from c2s.xml. * 2.1.15 to 2.1.16 upgrade: What changed: - Offline storage does not store headline messages by default - XEP-0157: Contact Addresses for XMPP Services - --enable-superseded ./configure option - Messages are delivered to all resources with highest priority number in accordance to RFC3921bis changes - XEP-0138: Stream Compression - XEP-0198: Stanza Acknowledgements - Dynamic virtual hosts support - Packet througput counters implemented - XEP-0202: Entity Time, XEP-0203: Delayed Delivery If you want to store headline messages in offlinestorage, enable in sm.xml. See etc/sm.xml.dist for reference. If you want to set XEP-0157: Contact Addresses please see etc/sm.xml.dist discovery.serverinfo section for example configuration to include in sm.xml. You need to add new chain 'disco-extend' section and discovery/sserverinfo section to configuration. If you wish, you may use --disable-superseded option during ./configure to disable all features, that was superseded by newer ones. If you want to enable stream compression, please uncomment proper section in c2s.xml. If you want to enable XEP-0198, please give --enable-experimental parameter to ./configure script. If you configure an in c2s.xml with no hostname, it will be used as a fallback default configuration for running SM with no configured . See sections in c2s.xml and s2s.xml for reference how to configure packet counters. * 2.1.14 to 2.1.15 upgrade: Only bug and compilation fixes. No configuration changes needed. * 2.1.13 to 2.1.14 upgrade: What changed: - Oracle authreg backend You may use Oracle backend to store your user data too. See c2s.xml.dist. * 2.1.12 to 2.1.13 upgrade: Only bug and compilation fixes. No configuration changes needed. * 2.1.11 to 2.1.12 upgrade: What changed: - PQconnectdb PostgreSQL connection method - using pg_config to find PostgreSQL For the PQconnectdb see in etc/c2s.xml.dist and etc/sm.xml.dist. You may add --enable-pgsql=/path/to/pg_config to ./configure to get PostgreSQL paths using pg_config. * 2.1.10 to 2.1.11 upgrade: Only bug and compliance fixes. No configuration changes needed. * 2.1.9 to 2.1.10 upgrade: What changed: - configure SASL backend fallback removed - user roster items limit support If you want to use other than GnuSASL backend for SASL, you need to enforce it by --with-sasl=BACKEND option to ./configure. There is no fallback anymore, because other backends are not supported and mostly do not work. If you want to limit user roster items, please see etc/sm.xml.dist for reference. * 2.1.8 to 2.1.9 upgrade: What changed: - logging formats - oob redirection during registration If you use log analysers please note that c2s and s2s connect messages have now a "TLS negotiated" indicator at the end. For s2s it was "SSL negotiated". c2s disconnection message now has user JID included. If you want to use oob redirection during registration, please see etc/c2s.xml.dist for reference. * 2.1.7 to 2.1.8 upgrade: What changed: - SASL backend selection method During ./configure use --with-sasl=BACKEND instead of --enable-gsasl and --enable-cyrus. * 2.1.6 to 2.1.7 upgrade: What changed: - MySQL connection defaults to UTF-8 now - Removed support for ZeroK authentication Please make sure that the encoding of the data in your MySQL DB is UTF-8 or is convertable by MySQL to UTF-8. You may remove the 'token', 'sequence' and 'hash' columns in authreg table. * 2.1.5 to 2.1.6 upgrade: What changed: - implemented XEP-0199: XMPP ping - sysconfdir isn't changed to .../etc/jabberd anymore - SASL backend is now GnuSASL by default with Cyrus as an alternative - configure.in was renamed to configure.ac - strndup() and timegm() implementations in subst/ - PATH_MAX definition added when necessary Add iq-ping to in-sess and pkt-sm chains in sm.xml. You need to explicitly set --sysconfdir with jabberd subdir if you want to. You need to --disable-gsasl and --enable-cyrus if you need to use Cyrus SASL. Remove all source dependant patches for missing functions if you have ones. * 2.1.4 to 2.1.5 upgrade: What changed: - auth/reg/storage modules are now loaded dynamically at runtime - MySQL storage backend is not enabled by default Dynamic modules should run out of box once installed (make install). If you need to configure other than the compiled-in path for it, please refer to the c2s.xml.dist and sm.xml.dist for a proper option. You will need to explicitly --enable-mysql during ./configure if you want to use MySQL backends. * 2.1.3 to 2.1.4 upgrade: What changed: - full SQLite support - PostgreSQL NULL parameters handling - more than one LDAP server support - new LDAP append-realm setting - correct CA chain handling Please refer to sm.xml.dist and c2s.xml.dist for new config sections and add them to your config files. Please read these example files to see how to setup your CA chain correctly. You may also remove cachain option from c2s.xml. You may remove hostname form PostgreSQL setup to access it via unix socket. * 2.1 to 2.1.3 upgrade: What changed: - c2s.xml added section - c2s PAM authenticator now handles realm setting - libjabberd moved from /usr/lib to /usr/lib/jabberd - removed bootstrap script - use: autoreconf --install if you build from sources If you want to use new SSL aware auth mechanizms please merge section of c2s.xml.dist into your c2s.xml config file. Remove any realm setting for PAM authenticated domains or setup your PAM system to handle additional realms. If you use modules.path in sm.xml, add .../jabberd/ at the end. * 2.0 to 2.1 upgrade: What changed: - c2s.xml local/id syntax: - DB schema - amp and status modules - CyrusSASL usage Upgrade: Basically all subitems and registration options from section are configurable per-realm now. So you need to move pemfile, verify-mode, require-starttls to attributes. You may also use subitems of as before, and these will be used for legacy port 5223 SSL wrapper. Options require-starttls, register-enable and password-change ale boolean. These are enabled if set to anything. 'true' seems reasonable for clarity. WARNING: Setting 'false' doesn't disable it!!! When you disabled new registrations for a realm not setting register-enable, you may wish to set password-change to enable users to change password. For new options like httpforward, see example c2s.xml for reference. DB changes: You need to add the following fields to the "vcard" table: ALTER TABLE vcard ADD COLUMN "tz" text; ALTER TABLE vcard ADD COLUMN "n-middle" text; ALTER TABLE vcard ADD COLUMN "n-prefix" text; ALTER TABLE vcard ADD COLUMN "n-suffix" text; ALTER TABLE vcard ADD COLUMN "n-prefx" text; ALTER TABLE vcard ADD COLUMN "n-suffix" text; ALTER TABLE vcard ADD COLUMN "adr-street" text; ALTER TABLE vcard ADD COLUMN "adr-extadd" text; ALTER TABLE vcard ADD COLUMN "adr-pobox" text; ALTER TABLE vcard ADD COLUMN "adr-locality" text; ALTER TABLE vcard ADD COLUMN "adr-region" text; ALTER TABLE vcard ADD COLUMN "adr-pcode" text; ALTER TABLE vcard ADD COLUMN "adr-country" text; ALTER TABLE vcard ADD COLUMN "geo-lat" text; ALTER TABLE vcard ADD COLUMN "geo-lon" text; ALTER TABLE vcard ADD COLUMN "org-orgname" text; ALTER TABLE vcard ADD COLUMN "agent-extval" text; ALTER TABLE vcard ADD COLUMN "sort-string" text; ALTER TABLE vcard ADD COLUMN "desc" text; ALTER TABLE vcard ADD COLUMN "note" text; ALTER TABLE vcard ADD COLUMN "photo-type" text; ALTER TABLE vcard ADD COLUMN "photo-binval" text; ALTER TABLE vcard ADD COLUMN "photo-extval" text; ALTER TABLE vcard ADD COLUMN "logo-type" text; ALTER TABLE vcard ADD COLUMN "logo-binval" text; ALTER TABLE vcard ADD COLUMN "logo-extval" text; ALTER TABLE vcard ADD COLUMN "sound-phonetic" text; ALTER TABLE vcard ADD COLUMN "sound-binval" text; ALTER TABLE vcard ADD COLUMN "sound-extval" text; ALTER TABLE vcard ADD COLUMN "key-type" text; ALTER TABLE vcard ADD COLUMN "key-cred" text; ALTER TABLE vcard ADD COLUMN "rev" text; and create table "status": CREATE TABLE "status" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint, "status" text NOT NULL, "show" text, "last-login" int DEFAULT '0', "last-logout" int DEFAULT '0' ); NOTE: PostgreSQL schema was greatly improved as a whole. It might be a good idea to dump your data (as INSERTS), recreate DB from new schema and import data back again. New modules: amp and status In order for amp and status session manager modules to work, you need to add them to appropriate chains in sm.xml and set their configuration options. Chains needed to be updated: sess-start, sess-end, in-sess, pkt-sm, pkt-user and user-delete. For details see sm.xml.dist. CyrusSASL You need working CyrusSASL installation. Please take care to include all required auth modules. Especially cyrus-sasl-md5 and cyrus-sasl-plain. Please report all errors of this howto to: http://bugs.xiaoka.com/proj3 Tomasz Sterna jabberd2-jabberd-2.3.4/README000066400000000000000000000000161261462775300154540ustar00rootroot00000000000000See README.md jabberd2-jabberd-2.3.4/README.config000066400000000000000000000017101261462775300167220ustar00rootroot00000000000000 *** Configuration values substitution *** Node data in config is refernced as ${node.name}, for example ${id} wil be replaced with value of node - First occurence of node is used for substitution. For instance,value of 'asd' wil be 'value1', not 'value2' in following sample: value1 value2 ${qqq} - Multiple variable substitution is supported '${qqq}_${qqq}' from example above will be substituted as 'value1_value1' - Nested substitution is supported. var3 will contain 'prefix_value-of-v_suffix' in sample below: value-of-v prefix_${var1}_suffix ${var2} - ${..} is replaced with node's content defined above only. ${some.node} must be used after val otherwise warning will be logged. The following config will cause warning upon loading: ${var1} value-of-v jabberd2-jabberd-2.3.4/README.md000066400000000000000000000121641261462775300160620ustar00rootroot00000000000000# jabberd2 Jabber Open Source Server (2.x) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/jabberd2/jabberd2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Thanks for downloading jabberd2. Below are some basic instructions to get you started. Complete documentation is available at http://jabberd2.org/ -- the jabberd team ## Required packages: - expat - XML parsing libraries http://expat.sourceforge.net/ - GnuSASL (1.1 or higher) - Simple Authentication and Security Layer library http://www.gnu.org/software/gsasl/ - UDNS - asynchronous DNS resolver library http://www.corpit.ru/mjt/udns.html ### Optional packages: - GNU Libidn (0.3.0 or higher) - needed for JID canonicalisation http://www.gnu.org/software/libidn/ - OpenSSL (0.9.6b or higher) - needed for SSL/TLS support http://www.openssl.org/news/ - zlib (1.2.3 or higher) - needed for stream compression http://www.zlib.net/ - Berkeley DB (4.1.24 or higher) http://www.sleepycat.com/download/ - OpenLDAP (2.1.0 or higher) http://www.openldap.org/software/download/ - PostgresSQL (8.0 or higher; development libraries and headers) http://www.postgresql.org/ - MySQL (5.0 or higher; development libraries and headers) http://www.mysql.com/ - PAM http://www.linux-pam.org/ (for Linux) - SQLite (3.0 or higher) http://www.sqlite.org/ ## Build: % ./configure % make % make install ### Options to ./configure: % ./configure --help [...] ## Configure: Edit $prefix/etc/(router|sm|c2s|s2s).xml to taste. In particular, make sure you setup for your choice of data storage correctly. If you're using the Berkeley DB backend, you'll need to create /var/run/jabberd and sets its permissions so that the server processes can find it. If you're using a SQL backend, you'll need to create an account for the server to use, and create the tables. Load db-setup.mysql or db-setup.pgsql from the tools/ directory into your database to do this. If you plan to use the jabberd wrapper script, make sure you look at the paths in the $prefix/etc/jabber/jabberd.cfg. ## Run: You can either run all of the pieces separately: % $prefix/bin/router & % $prefix/bin/s2s & % $prefix/bin/sm & % $prefix/bin/c2s & Or you can run them all from the jabberd wrapper script: % $prefix/jabberd & All the processes can take the following switches: -c use an alternate config file -D output lots of debugging info (if compiled with --enable-debug) ## Upgrade: Please see NEWS file. ## Support: - Webpage: http://jabberd2.org/ - Mailinglist: jabberd2@lists.xiaoka.com (Subscribe by sending mail to jabberd2-subscribe@lists.xiaoka.com) When requesting assistance, please note that the following things can provide useful information which may assist with finding your problem: - debug logs (compile with --enable-debug and run with -D) - running components seperately (ie without the wrapper script) - config.log Please try to provide as much relevant information as possible when reporting problems - it will make helping you much easier. ## Copyright & License: jabberd - Jabber Open Source Server Copyright (c) 2002-2012 Jeremie Miller, Thomas Muldowney, Ryan Eatmon, Robert Norris, Tomasz Sterna. 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, MA02111-1307USA As a special exception, the authors give permission to link this program with the OpenSSL library and distribute the resulting binary. subst/snprintf.c and util/base64.c were originally taken from the Apache web server project. Originally copyright (c) 1995-2003 Apache Software Foundation. util/md5.c was taken from Ghostscript. Originally copyright (c) 1999-2002 Aladdin Enterprises. util/sha1.c was taken from Mozilla. Originally copyright (c) 1995-1999 Cryptography Research, Inc. subst/getopt.[ch] was taken from GNU Libc. Originally copyright (c) 1987-1993 Free Software Foundation, Inc. subst/gettimeofday.c was taken from PostgreSQL. Originally copyright (c) 2003 SRA, Inc. & SKC, Inc. subst/syslog.[ch] was taken from Bind. Originally copyright (c) 2001 Internet Software Consortium. subst/inet_aton.c Originally copyright (c) 1995-1997 Kungliga Teniska Hogskolan subst/ip6_misc.h Originally copyright (c) 1993,1994,1997 The Regents of the University of California. subst/dirent.[ch] Originally copyright (c) 1997,2003 Kevlin Henney. jabberd2-jabberd-2.3.4/README.protocol000066400000000000000000000141011261462775300173140ustar00rootroot00000000000000Protocol support ---------------- jabberd 2.x is a server implementation of the eXtensible Messaging and Presence Protocol (XMPP), as published by the IETF. It also implements several XMPP extensions documented by the XMPP Software Foundation (XSF), and some legacy extensions that were implemented by its predecessor, jabberd 1.4. This document lists the protocols supported by the server, and any notes relating to the implementation. This is current as of 2008-01-24 (jabberd 2.1.22). RFC 3920 XMPP Core supported RFC 3921 XMPP IM supported RFC 3920bis XMPP Core supported RFC 3921bis XMPP IM supported XEP-0004 Data Forms - XEP-0011 Jabber Browsing supported XEP-0012 Last Activity supported XEP-0013 Flexible Offline Message Retrieval - XEP-0016 Privacy Lists supported XEP-0018 Invisible Presence removed XEP-0022 Message Events supported XEP-0023 Message Expiration supported XEP-0030 Service Discovery supported XEP-0033 Extended Stanza Addressing - XEP-0045 Multi-User Chat (by add-on) XEP-0048 Bookmark Storage supported XEP-0049 Private XML Storage supported XEP-0050 Ad-Hoc Commands - XEP-0054 vcard-temp supported XEP-0055 Jabber Search (by add-on) XEP-0059 Result Set Management - XEP-0060 Publish-Subscribe (by add-on) XEP-0065 SOCKS5 Bytestreams (by add-on) XEP-0073 Basic IM Protocol Suite supported XEP-0077 In-Band Registration supported XEP-0078 Non-SASL Authentication supported XEP-0079 Advanced Message Processing partial XEP-0083 Nested Roster Groups supported XEP-0086 Error Condition Mappings supported XEP-0090 Entity Time supported XEP-0091 Delayed Delivery supported XEP-0092 Software Version supported XEP-0093 Agent Information supported XEP-0114 Jabber Component Protocol supported XEP-0117 Intermediate IM Protocol Suite (by add-on) XEP-0124 HTTP Binding (by add-on) XEP-0128 Service Discovery Extensions supported XEP-0133 Service Administration - XEP-0136 Message Archiving - XEP-0138 Stream Compression supported XEP-0142 Workgroups - XEP-0145 Annotations supported XEP-0150 Use of Entity Tags in XMPP Extensions - XEP-0153 vCard-Based Avatars supported XEP-0154 User Profile - XEP-0157 Contact Addresses for XMPP Services supported XEP-0159 SPIM-Blocking Control - XEP-0160 Best Practices for Handling Offline Messages supported XEP-0163 Personal Eventing via Pubsub - XEP-0168 Resource Application Priority - XEP-0170 Recommended Order of Stream Feature Negotiation supported XEP-0172 User Nickname XEP-0175 Best Practices of Use of SASL ANONYMOUS supported XEP-0178 Best Practices of Use of SASL EXTERNAL partial XEP-0185 Dialback Key Generation and Validation supported XEP-0186 Invisible Command - XEP-0190 Best Practice for Closing Idle Streams supported XEP-0191 Simple Communications Blocking supported XEP-0192 Proposed Stream Feature Improvements supported XEP-0193 Proposed Resource Binding Improvements supported XEP-0198 Stanza Acknowledgements supported XEP-0199 XMPP Ping supported XEP-0202 Entity Time supported XEP-0203 Delayed Delivery supported XEP-0205 Best Practices to Discourage Denial of Service Attacks partial XEP-0206 XMPP Over BOSH (by add-on) XEP-0209 Metacontacts supported XEP-0212 XMPP Basic Server 2008 supported XEP-0215 External Service Discovery - XEP-0216 XMPP Intermediate IM Server 2008 partial XEP-0219 Hop Check - XEP-0220 Server Dialback supported XEP-0225 Component Connections supported Additional features supported by jabberd 2.1.22 (without plugins): - Server admin address - Echo address - Server MOTD - Offline message storage - Message archiving - Authorization with: BerkeleyDB, LDAP, MySQL, NTLogon, Oracle, PAM, PostgreSQL, Pipe, SQLite, SSPI - Storage in: BerkeleyDB, files, LDAP(vCard), MySQL, Oracle, PostreSQL, SQLite - jabberd2 Component Protocol Implementation Notes -------------------- XMPP RFCs --------- XMPP Core (RFC 3920 and RFC 3920bis) Implemented, except for: - SASL (External) for s2s streams - Language support via xml:lang XMPP IM (RFC 3921 and RFC 3921bis) Implemented. XMPP Extension Protocols ------------------------ Jabber Browsing (XEP-0011) Implemented by the session manager (mod_disco) as a wrapper around the service list used for Service Discovery. The configuration required to enable browsing is undocumented as browse is considered to be deprecated. Last Activity (XEP-0012) Implemented by the session manager (mod_iq_last). Message Events (XEP-0022) Offline event implemented by the session manager (mod_offline). Message Expiration (XEP-0023) Implemented by the session manager (mod_offline). Service Discovery (XEP-0030) Implemented by the session manager (mod_disco). Administrative users will see extra nodes when doing a #items query - these nodes provide information about active users and sessions. New components becoming available are probed automatically, and if they are disco-aware, their information is added to the service list. Sub-entity item publishing is implemented seperately by mod_disco_publish. Private XML Storage (XEP-0049) Implemented by the session manager (mod_iq_private). vcard-temp (XEP-0054) Implemented by the session manager (mod_iq_vcard). In-band Registration (XEP-0077) Implemented by c2s. Non-SASL Authentication (XEP-0078) Implemented by c2s. Entity Time (XEP-0090) Implemented by the session manager (mod_iq_time). Delayed Delivery (XEP-0091) Implemented by the session manager. Software Version (XEP-0092) Implemented by the session manager (mod_iq_version). Agent Information (XEP-0094) Implemented by the session manager (mod_disco) as a wrapper around the service list used for Service Discovery. External Component Protocol (XEP-0114) Implemented by the router as a wrapper around the more featureful jabberd 2.x component protocol. Legacy extensions (jabberd 1.4) ------------------------------- Invisible presence (XEP-0018) This extension was implemented by the session manager. It was intentionally removed. This is very legacy, causes problems, we have better ways of doing so called invisibility, etc. jabberd2-jabberd-2.3.4/README.win32000066400000000000000000000111041261462775300164150ustar00rootroot00000000000000jabberd2 for win32 guide ======================== This guide describes briefly how to build jabberd2 on Windows platforms. NOTE: Windows platforms prior to Windows 2000 are NOT supported, so this won't work on Windows 95/98/ME/NT. Building jabberd2 win32 with Visual Studio 2008 (SP1) ----------------------------------------------------- Starting from revision #229 complete win32 support with Visual Studio 2005 project files is present and maintained in the repository "win32" folder. Starting from revision #751 project files require Visual Studio 2008 (SP1). All libraries shall be installed locally and added to VC Include files and Library files paths using: Tools->Options->Project and Solutions->VC++ Directories. All libraries' DLL files shall be copied to win32/bin folder and win32/bin/sasl folder for SASL plugins respectively. Prerequisites: 1. http://alpha.gnu.org/gnu/libidn/ libidn source build using win32/libidn.sln, provides: libidn.lib 2. http://alpha.gnu.org/gnu/gsasl/ libgsasl source build using win32/libgsasl.sln, provides: libgsasl.lib 3. http://www.openssl.org/source/ OpenSSL source build, provides: libeay32.lib ssleay32.lib 4. http://sourceforge.net/projects/expat/ Expat XML Parser source build using expat.dsw, provides: libexpat.lib 5. http://www.corpit.ru/mjt/udns.html udns source build, provides: udns.lib, since there are no VC project files provided along with sources, please use patch files provided at: http://www.nanoant.com/projects/jabberd2-win32#download 6. http://www.zlib.net/ zlib source build, provides: zlib1.lib, convert & use VC project files at: projects/visualc6, link to Win32_DLL_ASM_Release. If you encounter MASM error: .\inffas32.asm(647) : error A2070: invalid instruction operands Add a "dword ptr" type qualifier before "[esp]" as described here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=166511 7. http://dev.mysql.com/downloads/mysql/5.0.html MySQL (auth & storage module) binary, provides: libmysql.lib 8. http://www.sqlite.org/download.html SQLite (auth & storage module) source build, provides: sqlite3.lib. Since there are no libraries for VC except DLLs you shall make one using sqlite-amalgamation-3.x.zip from SQLite downloads. sqlite3 command present in PATH, needed for initial database. 9. http://tortoisesvn.tigris.org/ SubWCRev command present in PATH to generate version.h and version.wxi. Comes with TortoiseSVN bin folder, added to PATH by TortoiseSVN installer. 10. http://wix.sourceforge.net/releases/ WiX 3.0.4401.0 or newer for building MSI jabberd2 setup inside VS2008 IDE 11. http://www.activestate.com/store/activeperl/download/ ActivePerl (or any Perl distribution) perl command present in PATH (optional for generation of default configuration XML files) After all prerequisite libraries are configured for use within VC open win32/jabberd2.sln and build all projects. You should have now fresh & ready Windows build of jabberd2 at win32/bin folder! Building jabberd2 win32 with MinGW ---------------------------------- NOTE: MinGW is NOT supported by the jabberd2 project team. If you have problems, you're welcome to post to jabberd@jabberstudio.org, but thats all. If you file a bug that can't be reproduced under Unix or MSVC, then the bug will be assumed not to exist. If anyone would like to step up to maintain this port properly, please contact us. You'll need MinGW and MSys installed to get this going, available here: http://www.mingw.org/ At the time of writing, the latest MinGW is 3.1.0-1. If you get this version, you'll need to also get w32api 2.5 (to get the aforementioned DNS resolution APIs). Later versions of MinGW should include these. Once all this kit is up and running, its business as usual: % ./configure % make % make install Note that you'll still need the various external packages as stated at Visual Studio 2008 section (eg MySQL dev packages) available in order to build a working server. Getting these up and running under MinGW is outside the scope of this short guide. Thanks ------ I'd like to thank Robert Norris for former win32 guide & support. Also huge thanks go out to Peter Hinz for the original port that was cannibalised pretty seriously by my predecessor that wouldn't have had a chance if he hadn't seen his code. Also I'm sending thanks to Tomasz Sterna (current project maintainer) for letting me in with my win32 modifications and support. -- Adam Strzelecki jabberd2-jabberd-2.3.4/TODO000066400000000000000000000052331261462775300152720ustar00rootroot00000000000000TODO for 2.0 ------------ Roster templates may not be working properly (esp. with multiple items). Check and fix if necessary. Make sure that available presence in response to a s10n accept arrives after the type='subscribed' (see chat with Nathan Walp) c2s may not be properly detecting client connections dropping. I feel like I've checked this numerous times, so check once more, once and for all. Modify user-load chain calls to indicate if the user is being loaded for a session, or just for delivery. Don't load rosters (and other large things) in that case. ========== The requirement for this is that large presence broadcasts (for the same host) result in many users being loaded for delivery, only to find out that they have no sessions online, and then being unloaded again. If we could stop some parts of the user data being loaded when the user is loaded only for packet delivery, then the overhead could be kept to a minimum. Privacy lists make this hard, if not impossible. Privacy lists must be loaded at packet delivery time, because the user may have a default list. That default list may have rules based on roster group, so the roster must be loaded. A partial solution might be to have a module that runs in in-router before mod_privacy, that watches for presence packets and drops them if the user is not online. This should work, because even if the presence packet was allowed by the default privacy list, it'll get dropped anyway because mod_deliver would find later that there are no sessions online. This doesn't fix the problem completely though because mod_privacy needs the user's roster loaded in order to process a default list with rules based on roster group. There's no way for mod_privacy to call into mod_roster to get it to load the roster on demand. Long term, there's a couple of possibilities. In general, I believe its reasonable to either have all user data loaded, or none of it - anything in between requires a measure of the "importance" of certain data (which doesn't scale and is highly subjective) or a on-demand system of loading data, which requires dependency graphs and inter-module communication. This stuff isn't impossible, but I don't want to go there if I can help it. It might be better to simply implement a (configurable) delay before unused user data is unloaded. This will still mean that the first presence broadcast can get sluggish, but after this things should chug along nicely. A patch for the partial soltuion mentioned above has been implemented, as _presence_in_router(). This is not a complete fix, but does workaround the most common case. ========== jabberd2-jabberd-2.3.4/acinclude.m4000066400000000000000000000400401261462775300167660ustar00rootroot00000000000000dnl ******** AC_COMPILE_CHECK_SIZEOF dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/ac_compile_check_sizeof.html dnl AC_DEFUN([AC_COMPILE_CHECK_SIZEOF], [changequote(<<, >>)dnl dnl The name to #define. define(<>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl dnl The cache variable name. define(<>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl changequote([, ])dnl AC_MSG_CHECKING(size of $1) AC_CACHE_VAL(AC_CV_NAME, [for ac_size in 4 8 1 2 16 $2 ; do # List sizes in rough order of prevalence. AC_TRY_COMPILE([#include "confdefs.h" #include $2 ], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size) if test x$AC_CV_NAME != x ; then break; fi done ]) if test x$AC_CV_NAME = x ; then AC_MSG_ERROR([cannot determine a size for $1]) fi AC_MSG_RESULT($AC_CV_NAME) AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1]) undefine([AC_TYPE_NAME])dnl undefine([AC_CV_NAME])dnl ]) dnl ******** AC_CREATE_STDINT_H dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/ac_create_stdint_h.html dnl AC_DEFUN([AC_CREATE_STDINT_H], [# ------ AC CREATE STDINT H ------------------------------------- AC_MSG_CHECKING([for stdint-types....]) ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` if test "$ac_stdint_h" = "stdint.h" ; then AC_MSG_RESULT("(are you sure you want them in ./stdint.h?)") elif test "$ac_stdint_h" = "inttypes.h" ; then AC_MSG_RESULT("(are you sure you want them in ./inttypes.h?)") else AC_MSG_RESULT("(putting them into $ac_stdint_h)") fi inttype_headers=`echo inttypes.h sys/inttypes.h sys/inttypes.h $2 \ | sed -e 's/,/ /g'` ac_cv_header_stdint_x="no-file" ac_cv_header_stdint_o="no-file" ac_cv_header_stdint_u="no-file" for i in stdint.h $inttype_headers ; do unset ac_cv_type_uintptr_t unset ac_cv_type_uint64_t _AC_CHECK_TYPE_NEW(uintptr_t,[ac_cv_header_stdint_x=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(uint64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our uintptr_t in $i $and64) break; done if test "$ac_cv_header_stdint_x" = "no-file" ; then for i in stdint.h $inttype_headers ; do unset ac_cv_type_uint32_t unset ac_cv_type_uint64_t AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(uint64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our uint32_t in $i $and64) break; done if test "$ac_cv_header_stdint_o" = "no-file" ; then for i in sys/types.h $inttype_headers ; do unset ac_cv_type_u_int32_t unset ac_cv_type_u_int64_t AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],dnl continue,[#include <$i>]) AC_CHECK_TYPE(uint64_t,[and64="(u_int64_t too)"],[and64=""],[#include<$i>]) AC_MSG_RESULT(... seen our u_int32_t in $i $and64) break; done fi fi # ----------------- DONE inttypes.h checks MAYBE C basic types -------- if test "$ac_cv_header_stdint_x" = "no-file" ; then AC_COMPILE_CHECK_SIZEOF(char) AC_COMPILE_CHECK_SIZEOF(short) AC_COMPILE_CHECK_SIZEOF(int) AC_COMPILE_CHECK_SIZEOF(long) AC_COMPILE_CHECK_SIZEOF(void*) ac_cv_header_stdint_test="yes" else ac_cv_header_stdint_test="no" fi # ----------------- DONE inttypes.h checks START header ------------- _ac_stdint_h=AS_TR_CPP(_$ac_stdint_h) AC_MSG_RESULT(creating $ac_stdint_h : $_ac_stdint_h) echo "#ifndef" $_ac_stdint_h >$ac_stdint_h echo "#define" $_ac_stdint_h "1" >>$ac_stdint_h echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint_h echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint_h if test "$GCC" = "yes" ; then echo "/* generated using a gnu compiler version" `$CC --version` "*/" \ >>$ac_stdint_h else echo "/* generated using $CC */" >>$ac_stdint_h fi echo "" >>$ac_stdint_h if test "$ac_cv_header_stdint_x" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_x" elif test "$ac_cv_header_stdint_o" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_o" elif test "$ac_cv_header_stdint_u" != "no-file" ; then ac_cv_header_stdint="$ac_cv_header_stdint_u" else ac_cv_header_stdint="stddef.h" fi # ----------------- See if int_least and int_fast types are present unset ac_cv_type_int_least32_t unset ac_cv_type_int_fast32_t AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) if test "$ac_cv_header_stdint" != "stddef.h" ; then if test "$ac_cv_header_stdint" != "stdint.h" ; then AC_MSG_RESULT(..adding include stddef.h) echo "#include " >>$ac_stdint_h fi ; fi AC_MSG_RESULT(..adding include $ac_cv_header_stdint) echo "#include <$ac_cv_header_stdint>" >>$ac_stdint_h echo "" >>$ac_stdint_h # ----------------- DONE header START basic int types ------------- if test "$ac_cv_header_stdint_x" = "no-file" ; then AC_MSG_RESULT(... need to look at C basic types) dnl ac_cv_header_stdint_test="yes" # moved up before creating the file else AC_MSG_RESULT(... seen good stdint.h inttypes) dnl ac_cv_header_stdint_test="no" # moved up before creating the file fi if test "$ac_cv_header_stdint_u" != "no-file" ; then AC_MSG_RESULT(... seen bsd/sysv typedefs) cat >>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h < 199901L #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #elif !defined __STRICT_ANSI__ #if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif #elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ dnl /* note: all ELF-systems seem to have loff-support which needs 64-bit */ #if !defined _NO_LONGLONG #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long long int64_t; typedef unsigned long long uint64_t; #endif #endif #elif defined __alpha || (defined __mips && defined _ABIN32) #if !defined _NO_LONGLONG #ifndef _HAVE_UINT64_T #define _HAVE_UINT64_T typedef long int64_t; typedef unsigned long uint64_t; #endif #endif /* compiler/cpu type ... or just ISO C99 */ #endif #endif EOF # plus a default 64-bit for systems that are likely to be 64-bit ready case "$ac_cv_sizeof_x:$ac_cv_sizeof_voidp:$ac_cv_sizeof_long" in 1:2:8:8) AC_MSG_RESULT(..adding uint64_t default, normal 64-bit system) cat >>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h <>$ac_stdint_h < #include int getpeername (int, $arg2 *, $t *); ],[ $t len; getpeername(0,0,&len); ],[ ac_cv_socklen_t_equiv="$t" break ]) done done if test "x$ac_cv_socklen_t_equiv" = x; then AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) fi ]) AC_MSG_RESULT($ac_cv_socklen_t_equiv) AC_DEFINE_UNQUOTED(socklen_t, $ac_cv_socklen_t_equiv, [type to use in place of socklen_t if not defined])], [#include #include ]) ]) dnl quote from SunOS-5.8 sys/inttypes.h: dnl Use at your own risk. As of February 1996, the committee is squarely dnl behind the fixed sized types; the "least" and "fast" types are still being dnl discussed. The probability that the "fast" types may be removed before dnl the standard is finalized is high enough that they are not currently dnl implemented. jabberd2-jabberd-2.3.4/c2s/000077500000000000000000000000001261462775300152665ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/c2s/Makefile.am000066400000000000000000000010041261462775300173150ustar00rootroot00000000000000LIBTOOL += --quiet bin_PROGRAMS = c2s c2s_SOURCES = authreg.c bind.c c2s.c main.c sm.c pbx.c pbx_commands.c address.c c2s_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -DLIBRARY_DIR=\"$(pkglibdir)\" -I@top_srcdir@ c2s_LDFLAGS = -export-dynamic noinst_HEADERS = c2s.h c2s_LDADD = $(top_builddir)/sx/libsx.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la if USE_LIBSUBST c2s_LDADD += $(top_builddir)/subst/libsubst.la endif if USE_WEBSOCKET c2s_LDADD += -lhttp_parser endif jabberd2-jabberd-2.3.4/c2s/address.c000066400000000000000000000027351261462775300170660ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Tomasz Sterna * * 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; version 2 of the License * * 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, MA02111-1307USA */ /* * this sx plugin implements My IP Address extension * as described in http://delta.affinix.com/specs/xmppstream.html#myip */ #include "c2s.h" /** sx features callback */ static void _address_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; /* offer feature only when not authenticated yet */ if(s->state >= state_OPEN) return; _sx_debug(ZONE, "adding address feature"); ns = nad_add_namespace(nad, uri_ADDRESS_FEATURE, NULL); nad_append_elem(nad, ns, "address", 1); nad_append_cdata(nad, s->ip, strlen(s->ip), 2); } /** args: none */ int address_init(sx_env_t env, sx_plugin_t p, va_list args) { log_debug(ZONE, "initialising address sx plugin"); p->features = _address_features; return 0; } jabberd2-jabberd-2.3.4/c2s/authreg.c000066400000000000000000000634701261462775300171030ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "c2s.h" #include #ifdef _WIN32 #include #define LIBRARY_DIR "." #else #include #endif /* authreg module manager */ typedef struct _authreg_error_st { char *class; char *name; char *code; char *uri; } *authreg_error_t; /** get a handle for the named module */ authreg_t authreg_init(c2s_t c2s, const char *name) { char mod_fullpath[PATH_MAX]; const char *modules_path; ar_module_init_fn init_fn = NULL; authreg_t ar; void *handle; /* return if already loaded */ ar = xhash_get(c2s->ar_modules, name); if (ar) { return ar->initialized ? ar : NULL; } /* load authreg module */ modules_path = config_get_one(c2s->config, "authreg.path", 0); if (modules_path != NULL) log_write(c2s->log, LOG_NOTICE, "modules search path: %s", modules_path); else log_write(c2s->log, LOG_NOTICE, "modules search path undefined, using default: "LIBRARY_DIR); log_write(c2s->log, LOG_INFO, "loading '%s' authreg module", name); #ifndef _WIN32 if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s/authreg_%s.so", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "%s/authreg_%s.so", LIBRARY_DIR, name); handle = dlopen(mod_fullpath, RTLD_LAZY); if (handle != NULL) init_fn = dlsym(handle, "ar_init"); #else if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s\\authreg_%s.dll", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "authreg_%s.dll", name); handle = (void*) LoadLibrary(mod_fullpath); if (handle != NULL) init_fn = (ar_module_init_fn)GetProcAddress((HMODULE) handle, "ar_init"); #endif if (handle != NULL && init_fn != NULL) { log_debug(ZONE, "preloaded module '%s' (not initialized yet)", name); } else { #ifndef _WIN32 log_write(c2s->log, LOG_ERR, "failed loading authreg module '%s' (%s)", name, dlerror()); if (handle != NULL) dlclose(handle); #else log_write(c2s->log, LOG_ERR, "failed loading authreg module '%s' (errcode: %x)", name, GetLastError()); if (handle != NULL) FreeLibrary((HMODULE) handle); #endif return NULL; } /* make a new one */ ar = (authreg_t) pmalloco(xhash_pool(c2s->ar_modules), sizeof(struct authreg_st)); if(!ar) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new authreg, aborting"); exit(1); } ar->c2s = c2s; xhash_put(c2s->ar_modules, name, ar); /* call the initialiser */ if((init_fn)(ar) != 0) { log_write(c2s->log, LOG_ERR, "failed to initialize auth module '%s'", name); authreg_free(ar); return NULL; } /* we need user_exists(), at the very least */ if(ar->user_exists == NULL) { log_write(c2s->log, LOG_ERR, "auth module '%s' has no check for user existence", name); authreg_free(ar); return NULL; } /* its good */ ar->initialized = TRUE; log_write(c2s->log, LOG_NOTICE, "initialized auth module '%s'", name); return ar; } /** shutdown the authreg system */ void authreg_free(authreg_t ar) { if (ar && ar->initialized) { if(ar->free != NULL) (ar->free)(ar); } } /** auth logger */ inline static void _authreg_auth_log(c2s_t c2s, sess_t sess, const char *method, const char *username, const char *resource, int success) { log_write(c2s->log, LOG_NOTICE, "[%d] %s authentication %s: %s@%s/%s %s:%d %s", sess->s->tag, method, success ? "succeeded" : "failed", username, sess->host->realm, resource, sess->s->ip, sess->s->port, _sx_flags(sess->s) ); } /** auth get handler */ static void _authreg_auth_get(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, attr, err; char username[1024], id[128]; int ar_mechs; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* sort out the username */ ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL); elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth get with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth get username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } ar_mechs = c2s->ar_mechanisms; if (sess->s->ssf>0) ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms; /* no point going on if we have no mechanisms */ if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST | AR_MECH_TRAD_CRAMMD5))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((sess->host->ar->user_exists)(sess->host->ar, sess, username, sess->host->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_free(nad); /* build a result packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "iq", 0); nad_append_attr(nad, -1, "type", "result"); if(attr >= 0) nad_append_attr(nad, -1, "id", id); ns = nad_add_namespace(nad, uri_AUTH, NULL); nad_append_elem(nad, ns, "query", 1); nad_append_elem(nad, ns, "username", 2); nad_append_cdata(nad, username, strlen(username), 3); nad_append_elem(nad, ns, "resource", 2); /* fill out the packet with available auth mechanisms */ if(ar_mechs & AR_MECH_TRAD_PLAIN && (sess->host->ar->get_password != NULL || sess->host->ar->check_password != NULL)) nad_append_elem(nad, ns, "password", 2); if(ar_mechs & AR_MECH_TRAD_DIGEST && sess->host->ar->get_password != NULL) nad_append_elem(nad, ns, "digest", 2); if (ar_mechs & AR_MECH_TRAD_CRAMMD5 && sess->host->ar->create_challenge != NULL) { err = (sess->host->ar->create_challenge)(sess->host->ar, sess, (char *) username, sess->host->realm, (char *) sess->auth_challenge, sizeof(sess->auth_challenge)); if (0 == err) { /* operation failed */ sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } else if (1 == err) { /* operation succeeded */ nad_append_elem(nad, ns, "crammd5", 2); nad_append_attr(nad, -1, "challenge", sess->auth_challenge); } else ; /* auth method unsupported for user */ } /* give it back to the client */ sx_nad_write(sess->s, nad); return; } /** auth set handler */ static void _authreg_auth_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, attr, authd = 0; char username[1024], resource[1024], str[1024], hash[280]; int ar_mechs; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL); /* sort out the username */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } /* make sure we have the resource */ elem = nad_find_elem(nad, 1, ns, "resource", 1); if(elem < 0) { log_debug(ZONE, "auth set with no resource, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(resource, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_resourceprep(resource, 1024) != 0) { log_debug(ZONE, "auth set resource failed resourceprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } ar_mechs = c2s->ar_mechanisms; if (sess->s->ssf > 0) ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms; /* no point going on if we have no mechanisms */ if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST | AR_MECH_TRAD_CRAMMD5))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((sess->host->ar->user_exists)(sess->host->ar, sess, username, sess->host->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* handle CRAM-MD5 response */ if(!authd && ar_mechs & AR_MECH_TRAD_CRAMMD5 && sess->host->ar->check_response != NULL) { elem = nad_find_elem(nad, 1, ns, "crammd5", 1); if(elem >= 0) { snprintf(str, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if((sess->host->ar->check_response)(sess->host->ar, sess, username, sess->host->realm, sess->auth_challenge, str) == 0) { log_debug(ZONE, "crammd5 auth (check) succeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.cram-md5", username, resource, TRUE); } else { _authreg_auth_log(c2s, sess, "traditional.cram-md5", username, resource, FALSE); } } } /* digest auth */ if(!authd && ar_mechs & AR_MECH_TRAD_DIGEST && sess->host->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "digest", 1); if(elem >= 0) { if((sess->host->ar->get_password)(sess->host->ar, sess, username, sess->host->realm, str) == 0) { snprintf(hash, 280, "%s%s", sess->s->id, str); shahash_r(hash, hash); if(strlen(hash) == NAD_CDATA_L(nad, elem) && strncmp(hash, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "digest auth succeeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.digest", username, resource, TRUE); } else { _authreg_auth_log(c2s, sess, "traditional.digest", username, resource, FALSE); } } } } /* plaintext auth (compare) */ if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && sess->host->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem >= 0) { if((sess->host->ar->get_password)(sess->host->ar, sess, username, sess->host->realm, str) == 0 && strlen(str) == NAD_CDATA_L(nad, elem) && strncmp(str, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "plaintext auth (compare) succeeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.plain(compare)", username, resource, TRUE); } else { _authreg_auth_log(c2s, sess, "traditional.plain(compare)", username, resource, FALSE); } } } /* plaintext auth (check) */ if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && sess->host->ar->check_password != NULL) { elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem >= 0) { snprintf(str, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if((sess->host->ar->check_password)(sess->host->ar, sess, username, sess->host->realm, str) == 0) { log_debug(ZONE, "plaintext auth (check) succeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.plain", username, resource, TRUE); } else { _authreg_auth_log(c2s, sess, "traditional.plain", username, resource, FALSE); } } } /* now, are they authenticated? */ if(authd) { /* create new bound jid holder */ if(sess->resources == NULL) { sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); } /* our local id */ sprintf(sess->resources->c2s_id, "%d", sess->s->tag); /* the full user jid for this session */ sess->resources->jid = jid_new(sess->s->req_to, -1); jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, resource); log_write(sess->c2s->log, LOG_NOTICE, "[%d] requesting session: jid=%s", sess->s->tag, jid_full(sess->resources->jid)); /* build a result packet, we'll send this back to the client after we have a session for them */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* start a session with the sm */ sm_start(sess, sess->resources); /* finished with the nad */ nad_free(nad); return; } _authreg_auth_log(c2s, sess, "traditional", username, resource, FALSE); /* auth failed, so error */ sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /** register get handler */ static void _authreg_register_get(c2s_t c2s, sess_t sess, nad_t nad) { int attr, ns; char id[128]; /* registrations can happen if reg is enabled and we can create users and set passwords */ if(sess->active || !(sess->host->ar->set_password != NULL && sess->host->ar->create_user != NULL && (sess->host->ar_register_enable || sess->host->ar_register_oob))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_free(nad); /* build a result packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "iq", 0); nad_append_attr(nad, -1, "type", "result"); if(attr >= 0) nad_append_attr(nad, -1, "id", id); ns = nad_add_namespace(nad, uri_REGISTER, NULL); nad_append_elem(nad, ns, "query", 1); nad_append_elem(nad, ns, "instructions", 2); nad_append_cdata(nad, sess->host->ar_register_instructions, strlen(sess->host->ar_register_instructions), 3); if(sess->host->ar_register_enable) { nad_append_elem(nad, ns, "username", 2); nad_append_elem(nad, ns, "password", 2); } if(sess->host->ar_register_oob) { int ns = nad_add_namespace(nad, uri_OOB, NULL); nad_append_elem(nad, ns, "x", 2); nad_append_elem(nad, ns, "url", 3); nad_append_cdata(nad, sess->host->ar_register_oob, strlen(sess->host->ar_register_oob), 4); } /* give it back to the client */ sx_nad_write(sess->s, nad); } /** register set handler */ static void _authreg_register_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns = 0, elem, attr; char username[1024], password[1024]; /* if we're not configured for registration (or pw changes), or we can't set passwords, fail outright */ if(!(sess->host->ar_register_enable || sess->host->ar_register_password) || sess->host->ar->set_password == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL); /* removals */ if(sess->active && nad_find_elem(nad, 1, ns, "remove", 1) >= 0) { /* only if full reg is enabled */ if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } log_debug(ZONE, "user remove requested"); /* make sure we can delete them */ if(sess->host->ar->delete_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, delete them */ if((sess->host->ar->delete_user)(sess->host->ar, sess, sess->resources->jid->node, sess->host->realm) != 0) { log_debug(ZONE, "user delete failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_write(c2s->log, LOG_NOTICE, "[%d] deleted user: user=%s; realm=%s", sess->s->tag, sess->resources->jid->node, sess->host->realm); log_write(c2s->log, LOG_NOTICE, "[%d] registration remove succeeded, requesting user deletion: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); nad_free(nad); sx_nad_write(sess->s, sess->result); sess->result = NULL; /* get the sm to delete them (it will force their sessions to end) */ sm_delete(sess, sess->resources); return; } /* username is required */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "register set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "register set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem < 0) { log_debug(ZONE, "register set with no password, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } /* if they're already auth'd, its a password change */ if(sess->active) { /* confirm that the username matches their auth id */ if(strcmp(username, sess->resources->jid->node) != 0) { log_debug(ZONE, "%s is trying to change password for %s, bouncing it", jid_full(sess->resources->jid), username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } } /* can't go on if we're not doing full reg */ else if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* if they exist, bounce */ else if((sess->host->ar->user_exists)(sess->host->ar, sess, username, sess->host->realm)) { log_debug(ZONE, "attempt to register %s, but they already exist", username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_CONFLICT), 0)); return; } /* make sure we can create them */ else if(sess->host->ar->create_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, create them */ else if((sess->host->ar->create_user)(sess->host->ar, sess, username, sess->host->realm) != 0) { log_debug(ZONE, "user create failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } else log_write(c2s->log, LOG_NOTICE, "[%d] created user: user=%s; realm=%s", sess->s->tag, username, sess->host->realm); /* extract the password */ snprintf(password, 257, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); /* change it */ if((sess->host->ar->set_password)(sess->host->ar, sess, username, sess->host->realm, password) != 0) { log_debug(ZONE, "password store failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_debug(ZONE, "updated auth creds for %s", username); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* if they're active, then this was just a password change, and we're done */ if(sess->active) { log_write(c2s->log, LOG_NOTICE, "[%d] password changed: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); sx_nad_write(sess->s, sess->result); sess->result = NULL; return; } /* create new bound jid holder */ if(sess->resources == NULL) { sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); } /* our local id */ sprintf(sess->resources->c2s_id, "%d", sess->s->tag); /* the user jid for this transaction */ sess->resources->jid = jid_new(sess->s->req_to, -1); jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, sess->resources->jid->resource); log_write(c2s->log, LOG_NOTICE, "[%d] registration succeeded, requesting user creation: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* get the sm to create them */ sm_create(sess, sess->resources); nad_free(nad); return; } /** * processor for iq:auth and iq:register packets * return 0 if handled, 1 if not handled */ int authreg_process(c2s_t c2s, sess_t sess, nad_t nad) { int ns, query, type, authreg = -1, getset = -1; /* need iq */ if(NAD_ENAME_L(nad, 0) != 2 || strncmp("iq", NAD_ENAME(nad, 0), 2) != 0) return 1; /* only want auth or register packets */ if((ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0) authreg = 0; else if((ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0) authreg = 1; else return 1; /* if its to someone else, pass it */ if(nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "to", sess->s->req_to) < 0) return 1; /* need a type */ if((type = nad_find_attr(nad, 0, -1, "type", NULL)) < 0 || NAD_AVAL_L(nad, type) != 3) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return 0; } /* get or set? */ if(strncmp("get", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0) getset = 0; else if(strncmp("set", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0) getset = 1; else { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return 0; } /* hand to the correct handler */ if(authreg == 0) { /* can't do iq:auth after sasl auth */ if(sess->sasl_authd) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return 0; } if(getset == 0) { log_debug(ZONE, "auth get"); _authreg_auth_get(c2s, sess, nad); } else if(getset == 1) { log_debug(ZONE, "auth set"); _authreg_auth_set(c2s, sess, nad); } } if(authreg == 1) { if(getset == 0) { log_debug(ZONE, "register get"); _authreg_register_get(c2s, sess, nad); } else if(getset == 1) { log_debug(ZONE, "register set"); _authreg_register_set(c2s, sess, nad); } } /* handled */ return 0; } jabberd2-jabberd-2.3.4/c2s/bind.c000066400000000000000000000047361261462775300163600ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file c2s/bind.c * @brief xmpp resource binding * @author Robert Norris * $Date: 2005/06/02 04:48:24 $ * $Revision: 1.9 $ */ #include "c2s.h" /** sx features callback */ static void _bind_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; if(s->auth_id == NULL) { c2s_t c2s; host_t host; log_debug(ZONE, "not auth'd, offering auth and register"); ns = nad_add_namespace(nad, uri_IQAUTH, NULL); nad_append_elem(nad, ns, "auth", 1); c2s = (c2s_t) p->private; host = xhash_get(c2s->hosts, s->req_to); if(! host) host = c2s->vhost; if(host && host->ar_register_enable) { ns = nad_add_namespace(nad, uri_IQREGISTER, NULL); nad_append_elem(nad, ns, "register", 1); } } else { log_debug(ZONE, "auth'd, offering resource bind and session"); ns = nad_add_namespace(nad, uri_BIND, NULL); nad_append_elem(nad, ns, "bind", 1); nad_append_elem(nad, -1, "required", 2); nad->scope = ns; nad_append_elem(nad, ns, "unbind", 1); #ifdef ENABLE_SUPERSEDED ns = nad_add_namespace(nad, uri_XSESSION, NULL); nad_append_elem(nad, ns, "session", 1); #endif ns = nad_add_namespace(nad, uri_ROSTERVER, NULL); nad_append_elem(nad, ns, "ver", 1); } } /** plugin initialiser */ /** args: c2s */ int bind_init(sx_env_t env, sx_plugin_t p, va_list args) { c2s_t c2s; log_debug(ZONE, "initialising resource bind sx plugin"); c2s = va_arg(args, c2s_t); p->features = _bind_features; p->private = (void *) c2s; return 0; } jabberd2-jabberd-2.3.4/c2s/c2s.c000066400000000000000000001475741261462775300161430ustar00rootroot00000000000000/* vim: set et ts=4 sw=4: */ /* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "c2s.h" #include static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { sess_t sess = (sess_t) arg; sx_buf_t buf = (sx_buf_t) data; int rlen, len, ns, elem, attr; sx_error_t *sxe; nad_t nad; char root[9]; bres_t bres, ires; stream_redirect_t redirect; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(sess->c2s->mio, sess->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(sess->c2s->mio, sess->fd); break; case event_READ: log_debug(ZONE, "reading from %d", sess->fd->fd); /* check rate limits */ if(sess->rate != NULL) { if(rate_check(sess->rate) == 0) { /* inform the app if we haven't already */ if(!sess->rate_log) { if(s->state >= state_STREAM && sess->resources != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] is being byte rate limited", sess->fd->fd, jid_user(sess->resources->jid)); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] is being byte rate limited", sess->fd->fd, sess->ip, sess->port); sess->rate_log = 1; } return -1; } /* find out how much we can have */ rlen = rate_left(sess->rate); if(rlen > buf->len) rlen = buf->len; } /* no limit, just read as much as we can */ else rlen = buf->len; /* do the read */ len = recv(sess->fd->fd, buf->data, rlen, 0); /* update rate limits */ if(sess->rate != NULL) rate_add(sess->rate, len); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } if(s->state >= state_STREAM && sess->resources != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] read error: %s (%d)", sess->fd->fd, jid_user(sess->resources->jid), MIO_STRERROR(MIO_ERROR), MIO_ERROR); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", sess->fd->fd, sess->ip, sess->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", sess->fd->fd); len = send(sess->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; if(s->state >= state_OPEN && sess->resources != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] write error: %s (%d)", sess->fd->fd, jid_user(sess->resources->jid), MIO_STRERROR(MIO_ERROR), MIO_ERROR); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s. port=%d] write error: %s (%d)", sess->fd->fd, sess->ip, sess->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; if(sess->resources != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] error: %s (%s)", sess->fd->fd, jid_user(sess->resources->jid), sxe->generic, sxe->specific); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", sess->fd->fd, sess->ip, sess->port, sxe->generic, sxe->specific); break; case event_STREAM: if(s->req_to == NULL) { log_debug(ZONE, "no stream to provided, closing"); sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header"); sx_close(s); return 0; } /* send a see-other-host error if we're configured to do so */ redirect = (stream_redirect_t) xhash_get(sess->c2s->stream_redirects, s->req_to); if (redirect != NULL) { log_debug(ZONE, "redirecting client's stream using see-other-host for domain: '%s'", s->req_to); len = strlen(redirect->to_address) + strlen(redirect->to_port) + 1; char *other_host = (char *) malloc(len+1); snprintf(other_host, len+1, "%s:%s", redirect->to_address, redirect->to_port); sx_error_extended(s, stream_err_SEE_OTHER_HOST, other_host); free(other_host); sx_close(s); return 0; } /* setup the host */ sess->host = xhash_get(sess->c2s->hosts, s->req_to); if(sess->host == NULL && sess->c2s->vhost == NULL) { log_debug(ZONE, "no host available for requested domain '%s'", s->req_to); sx_error(s, stream_err_HOST_UNKNOWN, "service requested for unknown domain"); sx_close(s); return 0; } if(xhash_get(sess->c2s->sm_avail, s->req_to) == NULL) { log_debug(ZONE, "sm for domain '%s' is not online", s->req_to); sx_error(s, stream_err_HOST_GONE, "session manager for requested domain is not available"); sx_close(s); return 0; } if(sess->host == NULL) { /* create host on-fly */ sess->host = (host_t) pmalloc(xhash_pool(sess->c2s->hosts), sizeof(struct host_st)); memcpy(sess->host, sess->c2s->vhost, sizeof(struct host_st)); sess->host->realm = pstrdup(xhash_pool(sess->c2s->hosts), s->req_to); xhash_put(sess->c2s->hosts, pstrdup(xhash_pool(sess->c2s->hosts), s->req_to), sess->host); } #ifdef HAVE_SSL if(sess->host->host_pemfile != NULL) sess->s->flags |= SX_SSL_STARTTLS_OFFER; if(sess->host->host_require_starttls) sess->s->flags |= SX_SSL_STARTTLS_REQUIRE; #endif break; case event_PACKET: /* we're counting packets */ sess->packet_count++; sess->c2s->packet_count++; /* check rate limits */ if(sess->stanza_rate != NULL) { if(rate_check(sess->stanza_rate) == 0) { /* inform the app if we haven't already */ if(!sess->stanza_rate_log) { if(s->state >= state_STREAM && sess->resources != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] is being stanza rate limited", sess->fd->fd, jid_user(sess->resources->jid)); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] is being stanza rate limited", sess->fd->fd, sess->ip, sess->port); sess->stanza_rate_log = 1; } } /* update rate limits */ rate_add(sess->stanza_rate, 1); } nad = (nad_t) data; /* we only want (message|presence|iq) in jabber:client, everything else gets dropped */ snprintf(root, 9, "%.*s", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); if(NAD_ENS(nad, 0) != nad_find_namespace(nad, 0, uri_CLIENT, NULL) || (strcmp(root, "message") != 0 && strcmp(root, "presence") != 0 && strcmp(root, "iq") != 0)) { nad_free(nad); return 0; } /* resource bind */ if((ns = nad_find_scoped_namespace(nad, uri_BIND, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "bind", 1)) >= 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) { bres_t bres; jid_t jid = jid_new(sess->s->auth_id, -1); /* get the resource */ elem = nad_find_elem(nad, elem, ns, "resource", 1); /* user-specified resource */ if(elem >= 0) { char resource_buf[1024]; if(NAD_CDATA_L(nad, elem) == 0) { log_debug(ZONE, "empty resource specified on bind"); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } snprintf(resource_buf, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); /* Put resource into JID */ if (jid == NULL || jid_reset_components(jid, jid->node, jid->domain, resource_buf) == NULL) { log_debug(ZONE, "invalid jid data"); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } /* check if resource already bound */ for(bres = sess->resources; bres != NULL; bres = bres->next) if(strcmp(bres->jid->resource, jid->resource) == 0){ log_debug(ZONE, "resource /%s already bound - generating", jid->resource); jid_random_part(jid, jid_RESOURCE); } } else { /* generate random resource */ log_debug(ZONE, "no resource given - generating"); jid_random_part(jid, jid_RESOURCE); } /* attach new bound jid holder */ bres = (bres_t) calloc(1, sizeof(struct bres_st)); bres->jid = jid; if(sess->resources != NULL) { for(ires = sess->resources; ires->next != NULL; ires = ires->next); ires->next = bres; } else sess->resources = bres; sess->bound += 1; log_write(sess->c2s->log, LOG_NOTICE, "[%d] bound: jid=%s", sess->s->tag, jid_full(bres->jid)); /* build a result packet, we'll send this back to the client after we have a session for them */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); ns = nad_add_namespace(sess->result, uri_BIND, NULL); nad_append_elem(sess->result, ns, "bind", 1); nad_append_elem(sess->result, ns, "jid", 2); nad_append_cdata(sess->result, jid_full(bres->jid), strlen(jid_full(bres->jid)), 3); /* our local id */ sprintf(bres->c2s_id, "%d", sess->s->tag); /* start a session with the sm */ sm_start(sess, bres); /* finished with the nad */ nad_free(nad); /* handled */ return 0; } /* resource unbind */ if((ns = nad_find_scoped_namespace(nad, uri_BIND, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "unbind", 1)) >= 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) { char resource_buf[1024]; bres_t bres; /* get the resource */ elem = nad_find_elem(nad, elem, ns, "resource", 1); if(elem < 0 || NAD_CDATA_L(nad, elem) == 0) { log_debug(ZONE, "no/empty resource given to unbind"); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } snprintf(resource_buf, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_resourceprep(resource_buf, 1024) != 0) { log_debug(ZONE, "cannot resourceprep"); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } /* check if resource bound */ for(bres = sess->resources; bres != NULL; bres = bres->next) if(strcmp(bres->jid->resource, resource_buf) == 0) break; if(bres == NULL) { log_debug(ZONE, "resource /%s not bound", resource_buf); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_ITEM_NOT_FOUND)); return 0; } /* build a result packet, we'll send this back to the client after we close a session for them */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* end a session with the sm */ sm_end(sess, bres); /* finished with the nad */ nad_free(nad); /* handled */ return 0; } /* pre-session requests */ if(!sess->active && sess->sasl_authd && sess->result == NULL && strcmp(root, "iq") == 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) { log_debug(ZONE, "unrecognised pre-session packet, bye"); log_write(sess->c2s->log, LOG_NOTICE, "[%d] unrecognized pre-session packet, closing stream", sess->s->tag); sx_error(s, stream_err_NOT_AUTHORIZED, "unrecognized pre-session stanza"); sx_close(s); nad_free(nad); return 0; } #ifdef HAVE_SSL /* drop packets if they have to starttls and they haven't */ if((sess->s->flags & SX_SSL_STARTTLS_REQUIRE) && sess->s->ssf == 0) { log_debug(ZONE, "pre STARTTLS packet, dropping"); log_write(sess->c2s->log, LOG_NOTICE, "[%d] got pre STARTTLS packet, dropping", sess->s->tag); sx_error(s, stream_err_POLICY_VIOLATION, "STARTTLS is required for this stream"); nad_free(nad); return 0; } #endif /* handle iq:auth packets */ if(authreg_process(sess->c2s, sess, nad) == 0) return 0; /* drop it if no session */ if(!sess->active) { log_debug(ZONE, "pre-session packet, bye"); log_write(sess->c2s->log, LOG_NOTICE, "[%d] packet sent before session start, closing stream", sess->s->tag); sx_error(s, stream_err_NOT_AUTHORIZED, "stanza sent before session start"); sx_close(s); nad_free(nad); return 0; } /* validate 'from' */ assert(sess->resources != NULL); if(sess->bound > 1) { bres = NULL; if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) for(bres = sess->resources; bres != NULL; bres = bres->next) if(strncmp(jid_full(bres->jid), NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0) break; if(bres == NULL) { if(attr >= 0) { log_debug(ZONE, "packet from: %.*s that has not bound the resource", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); } else { log_debug(ZONE, "packet without 'from' on multiple resource stream"); } sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_UNKNOWN_SENDER)); return 0; } } else bres = sess->resources; /* pass it on to the session manager */ sm_packet(sess, bres, nad); break; case event_OPEN: /* only send a result and bring us online if this wasn't a sasl auth */ if(strlen(s->auth_method) < 4 || strncmp("SASL", s->auth_method, 4) != 0) { /* return the auth result to the client */ sx_nad_write(s, sess->result); sess->result = NULL; /* we're good to go */ sess->active = 1; } /* they sasl auth'd, so we only want the new-style session start */ else { log_write(sess->c2s->log, LOG_NOTICE, "[%d] %s authentication succeeded: %s %s:%d %s", sess->s->tag, &sess->s->auth_method[5], sess->s->auth_id, sess->s->ip, sess->s->port, _sx_flags(sess->s) ); sess->sasl_authd = 1; } break; case event_CLOSED: mio_close(sess->c2s->mio, sess->fd); sess->fd = NULL; return -1; } return 0; } static int _c2s_client_accept_check(c2s_t c2s, mio_fd_t fd, const char *ip) { rate_t rt; if(access_check(c2s->access, ip) == 0) { log_write(c2s->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd->fd, ip); return 1; } if(c2s->conn_rate_total != 0) { rt = (rate_t) xhash_get(c2s->conn_rates, ip); if(rt == NULL) { rt = rate_new(c2s->conn_rate_total, c2s->conn_rate_seconds, c2s->conn_rate_wait); xhash_put(c2s->conn_rates, pstrdup(xhash_pool(c2s->conn_rates), ip), (void *) rt); pool_cleanup(xhash_pool(c2s->conn_rates), (void (*)(void *)) rate_free, rt); } if(rate_check(rt) == 0) { log_write(c2s->log, LOG_NOTICE, "[%d] [%s] is being connect rate limited", fd->fd, ip); return 1; } rate_add(rt, 1); } return 0; } static int _c2s_client_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { sess_t sess = (sess_t) arg; c2s_t c2s = (c2s_t) arg; bres_t bres; struct sockaddr_storage sa; socklen_t namelen = sizeof(sa); int port, nbytes, flags = 0; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); /* they did something */ sess->last_activity = time(NULL); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(sess->s); return 0; } return sx_can_read(sess->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(sess->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect jid=%s, packets: %i, bytes: %d", sess->fd->fd, sess->ip, sess->port, ((sess->resources)?((char*) jid_full(sess->resources->jid)):"unbound"), sess->packet_count, sess->s->rbytes_total); /* tell the sm to close their session */ if(sess->active) for(bres = sess->resources; bres != NULL; bres = bres->next) sm_end(sess, bres); /* call the session end callback to allow for authreg * module to cleanup private data */ if(sess->host && sess->host->ar->sess_end != NULL) (sess->host->ar->sess_end)(sess->host->ar, sess); /* force free authreg_private if pointer is still set */ if (sess->authreg_private != NULL) { free(sess->authreg_private); sess->authreg_private = NULL; } jqueue_push(sess->c2s->dead, (void *) sess->s, 0); xhash_zap(sess->c2s->sessions, sess->skey); jqueue_push(sess->c2s->dead_sess, (void *) sess, 0); break; case action_ACCEPT: log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connect", fd->fd, (char *) data, port); if(_c2s_client_accept_check(c2s, fd, (char *) data) != 0) return 1; sess = (sess_t) calloc(1, sizeof(struct sess_st)); sess->c2s = c2s; sess->fd = fd; sess->ip = strdup((char *) data); sess->port = port; /* they did something */ sess->last_activity = time(NULL); sess->s = sx_new(c2s->sx_env, fd->fd, _c2s_client_sx_callback, (void *) sess); mio_app(m, fd, _c2s_client_mio_callback, (void *) sess); if(c2s->stanza_size_limit != 0) sess->s->rbytesmax = c2s->stanza_size_limit; if(c2s->byte_rate_total != 0) sess->rate = rate_new(c2s->byte_rate_total, c2s->byte_rate_seconds, c2s->byte_rate_wait); if(c2s->stanza_rate_total != 0) sess->stanza_rate = rate_new(c2s->stanza_rate_total, c2s->stanza_rate_seconds, c2s->stanza_rate_wait); /* give IP to SX */ sess->s->ip = sess->ip; sess->s->port = sess->port; /* find out which port this is */ getsockname(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); /* remember it */ sprintf(sess->skey, "%d", fd->fd); xhash_put(c2s->sessions, sess->skey, (void *) sess); flags = SX_SASL_OFFER; #ifdef HAVE_SSL /* go ssl wrappermode if they're on the ssl port */ if(port == c2s->local_ssl_port) flags |= SX_SSL_WRAPPER; #endif #ifdef HAVE_LIBZ if(c2s->compression && !(sess->s->flags & SX_WEBSOCKET_WRAPPER)) flags |= SX_COMPRESS_OFFER; #endif sx_server_init(sess->s, flags); break; } return 0; } static void _c2s_component_presence(c2s_t c2s, nad_t nad) { int attr; char from[1024]; sess_t sess; union xhashv xhv; if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) < 0) { nad_free(nad); return; } strncpy(from, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); from[NAD_AVAL_L(nad, attr)] = '\0'; if(nad_find_attr(nad, 0, -1, "type", NULL) < 0) { log_debug(ZONE, "component available from '%s'", from); log_debug(ZONE, "sm for serviced domain '%s' online", from); xhash_put(c2s->sm_avail, pstrdup(xhash_pool(c2s->sm_avail), from), (void *) 1); nad_free(nad); return; } if(nad_find_attr(nad, 0, -1, "type", "unavailable") < 0) { nad_free(nad); return; } log_debug(ZONE, "component unavailable from '%s'", from); if(xhash_get(c2s->sm_avail, from) != NULL) { log_debug(ZONE, "sm for serviced domain '%s' offline", from); if(xhash_iter_first(c2s->sessions)) do { xhv.sess_val = &sess; xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val); if(sess->resources != NULL && strcmp(sess->resources->jid->domain, from) == 0) { log_debug(ZONE, "killing session %s", jid_user(sess->resources->jid)); sess->active = 0; if(sess->s) sx_close(sess->s); } } while(xhash_iter_next(c2s->sessions)); xhash_zap(c2s->sm_avail, from); } } int c2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { c2s_t c2s = (c2s_t) arg; sx_buf_t buf = (sx_buf_t) data; sx_error_t *sxe; nad_t nad; int len, elem, from, c2sid, smid, action, id, ns, attr, scan, replaced; char skey[44]; sess_t sess; bres_t bres, ires; char *smcomp; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(c2s->mio, c2s->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(c2s->mio, c2s->fd); break; case event_READ: log_debug(ZONE, "reading from %d", c2s->fd->fd); /* do the read */ len = recv(c2s->fd->fd, buf->data, buf->len, 0); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(c2s->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", c2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", c2s->fd->fd); len = send(c2s->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_write(c2s->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", c2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(c2s->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific); if(sxe->code == SX_ERR_AUTH) sx_close(s); break; case event_STREAM: break; case event_OPEN: log_write(c2s->log, LOG_NOTICE, "connection to router established"); /* set connection attempts counter */ c2s->retry_left = c2s->retry_lost; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "bind", 0); nad_append_attr(nad, -1, "name", c2s->id); log_debug(ZONE, "requesting component bind for '%s'", c2s->id); sx_nad_write(c2s->router, nad); return 0; case event_PACKET: nad = (nad_t) data; /* drop unqualified packets */ if(NAD_ENS(nad, 0) < 0) { nad_free(nad); return 0; } /* watch for the features packet */ if(s->state == state_STREAM) { if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) { log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping"); nad_free(nad); return 0; } #ifdef HAVE_SSL /* starttls if we can */ if(c2s->sx_ssl != NULL && c2s->router_pemfile != NULL && s->ssf == 0) { ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); if(ns >= 0) { elem = nad_find_elem(nad, 0, ns, "starttls", 1); if(elem >= 0) { if(sx_ssl_client_starttls(c2s->sx_ssl, s, c2s->router_pemfile, c2s->router_private_key_password) == 0) { nad_free(nad); return 0; } log_write(c2s->log, LOG_ERR, "unable to establish encrypted session with router"); } } } #endif /* !!! pull the list of mechanisms, and choose the best one. * if there isn't an appropriate one, error and bail */ /* authenticate */ sx_sasl_auth(c2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", c2s->router_user, c2s->router_pass); nad_free(nad); return 0; } /* watch for the bind response */ if(s->state == state_OPEN && !c2s->online) { if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4) != 0) { log_debug(ZONE, "got a packet from router, but we're not online, dropping"); nad_free(nad); return 0; } /* catch errors */ attr = nad_find_attr(nad, 0, -1, "error", NULL); if(attr >= 0) { log_write(c2s->log, LOG_ERR, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); exit(1); } log_debug(ZONE, "coming online"); /* if we're coming online for the first time, setup listening sockets */ #ifdef HAVE_SSL if(c2s->server_fd == 0 && c2s->server_ssl_fd == 0) { #else if(c2s->server_fd == 0) { #endif if(c2s->local_port != 0) { c2s->server_fd = mio_listen(c2s->mio, c2s->local_port, c2s->local_ip, _c2s_client_mio_callback, (void *) c2s); if(c2s->server_fd == NULL) log_write(c2s->log, LOG_ERR, "[%s, port=%d] failed to listen", c2s->local_ip, c2s->local_port); else log_write(c2s->log, LOG_NOTICE, "[%s, port=%d] listening for connections", c2s->local_ip, c2s->local_port); } else c2s->server_fd = NULL; #ifdef HAVE_SSL if(c2s->local_ssl_port != 0 && c2s->local_pemfile != NULL) { c2s->server_ssl_fd = mio_listen(c2s->mio, c2s->local_ssl_port, c2s->local_ip, _c2s_client_mio_callback, (void *) c2s); if(c2s->server_ssl_fd == NULL) log_write(c2s->log, LOG_ERR, "[%s, port=%d] failed to listen", c2s->local_ip, c2s->local_ssl_port); else log_write(c2s->log, LOG_NOTICE, "[%s, port=%d] listening for SSL connections", c2s->local_ip, c2s->local_ssl_port); } else c2s->server_ssl_fd = NULL; #endif } #ifdef HAVE_SSL if(c2s->server_fd == NULL && c2s->server_ssl_fd == NULL && c2s->pbx_pipe == NULL) { log_write(c2s->log, LOG_ERR, "both normal and SSL ports are disabled, nothing to do!"); #else if(c2s->server_fd == NULL && c2s->pbx_pipe == NULL) { log_write(c2s->log, LOG_ERR, "server port is disabled, nothing to do!"); #endif exit(1); } /* open PBX integration FIFO */ if(c2s->pbx_pipe != NULL) c2s_pbx_init(c2s); /* we're online */ c2s->online = c2s->started = 1; log_write(c2s->log, LOG_NOTICE, "ready for connections", c2s->id); nad_free(nad); return 0; } /* need component packets */ if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) { log_debug(ZONE, "wanted component packet, dropping"); nad_free(nad); return 0; } /* component presence */ if(NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) { _c2s_component_presence(c2s, nad); return 0; } /* we want route */ if(NAD_ENAME_L(nad, 0) != 5 || strncmp("route", NAD_ENAME(nad, 0), 5) != 0) { log_debug(ZONE, "wanted {component}route, dropping"); nad_free(nad); return 0; } /* only handle unicasts */ if(nad_find_attr(nad, 0, -1, "type", NULL) >= 0) { log_debug(ZONE, "non-unicast packet, dropping"); nad_free(nad); return 0; } /* need some payload */ if(nad->ecur == 1) { log_debug(ZONE, "no route payload, dropping"); nad_free(nad); return 0; } ns = nad_find_namespace(nad, 1, uri_SESSION, NULL); if(ns < 0) { log_debug(ZONE, "not a c2s packet, dropping"); nad_free(nad); return 0; } /* figure out the session */ c2sid = nad_find_attr(nad, 1, ns, "c2s", NULL); if(c2sid < 0) { log_debug(ZONE, "no c2s id on payload, dropping"); nad_free(nad); return 0; } snprintf(skey, sizeof(skey), "%.*s", NAD_AVAL_L(nad, c2sid), NAD_AVAL(nad, c2sid)); /* find the session, quietly drop if we don't have it */ sess = xhash_get(c2s->sessions, skey); if(sess == NULL) { /* if we get this, the SM probably thinks the session is still active * so we need to tell SM to free it up */ log_debug(ZONE, "no session for %s", skey); /* check if it's a started action; otherwise we could end up in an infinite loop * trying to tell SM to close in response to errors */ action = nad_find_attr(nad, 1, -1, "action", NULL); if(action >= 0 && NAD_AVAL_L(nad, action) == 7 && strncmp("started", NAD_AVAL(nad, action), 7) == 0) { int target; bres_t tres; sess_t tsess; log_write(c2s->log, LOG_NOTICE, "session %s does not exist; telling sm to close", skey); /* we don't have a session and we don't have a resource; we need to forge them both * to get SM to close stuff */ target = nad_find_attr(nad, 1, -1, "target", NULL); smid = nad_find_attr(nad, 1, ns, "sm", NULL); if(target < 0 || smid < 0) { const char *buf; int len; nad_print(nad, 0, &buf, &len); log_write(c2s->log, LOG_NOTICE, "sm sent an invalid start packet: %.*s", len, buf ); nad_free(nad); return 0; } /* build temporary resource to close session for */ tres = NULL; tres = (bres_t) calloc(1, sizeof(struct bres_st)); tres->jid = jid_new(NAD_AVAL(nad, target), NAD_AVAL_L(nad, target)); strncpy(tres->c2s_id, skey, sizeof(tres->c2s_id)); snprintf(tres->sm_id, sizeof(tres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid)); /* make a temporary session */ tsess = (sess_t) calloc(1, sizeof(struct sess_st)); tsess->c2s = c2s; tsess->result = nad_new(); strncpy(tsess->skey, skey, sizeof(tsess->skey)); /* end a session with the sm */ sm_end(tsess, tres); /* free our temporary messes */ nad_free(tsess->result); jid_free(tres->jid); //TODO will this crash? free(tsess); free(tres); } nad_free(nad); return 0; } /* if they're pre-stream, then this is leftovers from a previous session */ if(sess->s && sess->s->state < state_STREAM) { log_debug(ZONE, "session %s is pre-stream", skey); nad_free(nad); return 0; } /* check the sm session id if they gave us one */ smid = nad_find_attr(nad, 1, ns, "sm", NULL); /* get the action attribute */ action = nad_find_attr(nad, 1, -1, "action", NULL); /* first user created packets - these are out of session */ if(action >= 0 && NAD_AVAL_L(nad, action) == 7 && strncmp("created", NAD_AVAL(nad, action), 7) == 0) { nad_free(nad); if(sess->result) { /* return the result to the client */ sx_nad_write(sess->s, sess->result); sess->result = NULL; } else { log_write(sess->c2s->log, LOG_WARNING, "user created for session %s which is already gone", skey); } return 0; } /* route errors */ if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) { log_debug(ZONE, "routing error"); if(sess->s) { sx_error(sess->s, stream_err_INTERNAL_SERVER_ERROR, "internal server error"); sx_close(sess->s); } nad_free(nad); return 0; } /* all other packets need to contain an sm ID */ if (smid < 0) { log_debug(ZONE, "received packet from sm without an sm ID, dropping"); nad_free(nad); return 0; } /* find resource that we got packet for */ bres = NULL; if(smid >= 0) for(bres = sess->resources; bres != NULL; bres = bres->next){ if(bres->sm_id[0] == '\0' || (strlen(bres->sm_id) == NAD_AVAL_L(nad, smid) && strncmp(bres->sm_id, NAD_AVAL(nad, smid), NAD_AVAL_L(nad, smid)) == 0)) break; } if(bres == NULL) { jid_t jid = NULL; bres_t tres = NULL; /* if it's a failure, just drop it */ if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) { nad_free(nad); return 0; } /* build temporary resource to close session for */ tres = (bres_t) calloc(1, sizeof(struct bres_st)); if(sess->s) { jid = jid_new(sess->s->auth_id, -1); sprintf(tres->c2s_id, "%d", sess->s->tag); } else { /* does not have SX - extract values from route packet */ int c2sid, target; c2sid = nad_find_attr(nad, 1, ns, "c2s", NULL); target = nad_find_attr(nad, 1, -1, "target", NULL); if(c2sid < 0 || target < 0) { log_debug(ZONE, "needed ids not found - c2sid:%d target:%d", c2sid, target); nad_free(nad); free(tres); return 0; } jid = jid_new(NAD_AVAL(nad, target), NAD_AVAL_L(nad, target)); snprintf(tres->c2s_id, sizeof(tres->c2s_id), "%.*s", NAD_AVAL_L(nad, c2sid), NAD_AVAL(nad, c2sid)); } tres->jid = jid; snprintf(tres->sm_id, sizeof(tres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid)); if(sess->resources) { log_debug(ZONE, "expected packet from sm session %s, but got one from %.*s, ending sm session", sess->resources->sm_id, NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid)); } else { log_debug(ZONE, "no resource bound yet, but got packet from sm session %.*s, ending sm session", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid)); } /* end a session with the sm */ sm_end(sess, tres); /* finished with the nad */ nad_free(nad); /* free temp objects */ jid_free(jid); free(tres); return 0; } /* session control packets */ if(NAD_ENS(nad, 1) == ns && action >= 0) { /* end responses */ /* !!! this "replaced" stuff is a hack - its really a subaction of "ended". * hurrah, another control protocol rewrite is needed :( */ replaced = 0; if(NAD_AVAL_L(nad, action) == 8 && strncmp("replaced", NAD_AVAL(nad, action), NAD_AVAL_L(nad, action)) == 0) replaced = 1; if(sess->active && (replaced || (NAD_AVAL_L(nad, action) == 5 && strncmp("ended", NAD_AVAL(nad, action), NAD_AVAL_L(nad, action)) == 0))) { sess->bound -= 1; /* no more resources bound? */ if(sess->bound < 1){ sess->active = 0; if(sess->s) { /* return the unbind result to the client */ if(sess->result != NULL) { sx_nad_write(sess->s, sess->result); sess->result = NULL; } if(replaced) sx_error(sess->s, stream_err_CONFLICT, NULL); sx_close(sess->s); } else { // handle fake PBX sessions if(sess->result != NULL) { nad_free(sess->result); sess->result = NULL; } } nad_free(nad); return 0; } /* else remove the bound resource */ if(bres == sess->resources) { sess->resources = bres->next; } else { for(ires = sess->resources; ires != NULL; ires = ires->next) if(ires->next == bres) break; assert(ires != NULL); ires->next = bres->next; } log_write(sess->c2s->log, LOG_NOTICE, "[%d] unbound: jid=%s", sess->s->tag, jid_full(bres->jid)); jid_free(bres->jid); free(bres); /* and return the unbind result to the client */ if(sess->result != NULL) { sx_nad_write(sess->s, sess->result); sess->result = NULL; } return 0; } id = nad_find_attr(nad, 1, -1, "id", NULL); /* make sure the id matches */ if(id < 0 || bres->sm_request[0] == '\0' || strlen(bres->sm_request) != NAD_AVAL_L(nad, id) || strncmp(bres->sm_request, NAD_AVAL(nad, id), NAD_AVAL_L(nad, id)) != 0) { if(id >= 0) { log_debug(ZONE, "got a response with id %.*s, but we were expecting %s", NAD_AVAL_L(nad, id), NAD_AVAL(nad, id), bres->sm_request); } else { log_debug(ZONE, "got a response with no id, but we were expecting %s", bres->sm_request); } nad_free(nad); return 0; } /* failed requests */ if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) { /* handled request */ bres->sm_request[0] = '\0'; /* we only care about failed start and create */ if((NAD_AVAL_L(nad, action) == 5 && strncmp("start", NAD_AVAL(nad, action), 5) == 0) || (NAD_AVAL_L(nad, action) == 6 && strncmp("create", NAD_AVAL(nad, action), 6) == 0)) { /* create failed, so we need to remove them from authreg */ if(NAD_AVAL_L(nad, action) == 6 && sess->host->ar->delete_user != NULL) { if((sess->host->ar->delete_user)(sess->host->ar, sess, bres->jid->node, sess->host->realm) != 0) log_write(c2s->log, LOG_NOTICE, "[%d] user creation failed, and unable to delete user credentials: user=%s, realm=%s", sess->s->tag, bres->jid->node, sess->host->realm); else log_write(c2s->log, LOG_NOTICE, "[%d] user creation failed, so deleted user credentials: user=%s, realm=%s", sess->s->tag, bres->jid->node, sess->host->realm); } /* error the result and return it to the client */ sx_nad_write(sess->s, stanza_error(sess->result, 0, stanza_err_INTERNAL_SERVER_ERROR)); sess->result = NULL; /* remove the bound resource */ if(bres == sess->resources) { sess->resources = bres->next; } else { for(ires = sess->resources; ires != NULL; ires = ires->next) if(ires->next == bres) break; assert(ires != NULL); ires->next = bres->next; } jid_free(bres->jid); free(bres); nad_free(nad); return 0; } log_debug(ZONE, "weird, got a failed session response, with a matching id, but the action is bogus *shrug*"); nad_free(nad); return 0; } /* session started */ if(NAD_AVAL_L(nad, action) == 7 && strncmp("started", NAD_AVAL(nad, action), 7) == 0) { /* handled request */ bres->sm_request[0] = '\0'; /* copy the sm id */ if(smid >= 0) snprintf(bres->sm_id, sizeof(bres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid)); /* and remember the SM that services us */ from = nad_find_attr(nad, 0, -1, "from", NULL); smcomp = malloc(NAD_AVAL_L(nad, from) + 1); snprintf(smcomp, NAD_AVAL_L(nad, from) + 1, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from)); sess->smcomp = smcomp; nad_free(nad); /* bring them online, old-skool */ if(!sess->sasl_authd && sess->s) { sx_auth(sess->s, "traditional", jid_full(bres->jid)); return 0; } if(sess->result) { /* return the auth result to the client */ if(sess->s) sx_nad_write(sess->s, sess->result); /* or follow-up the session creation with cached presence packet */ else sm_packet(sess, bres, sess->result); } sess->result = NULL; /* we're good to go */ sess->active = 1; return 0; } /* handled request */ bres->sm_request[0] = '\0'; log_debug(ZONE, "unknown action %.*s", NAD_AVAL_L(nad, id), NAD_AVAL(nad, id)); nad_free(nad); return 0; } /* client packets */ if(NAD_NURI_L(nad, NAD_ENS(nad, 1)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 1)), strlen(uri_CLIENT)) == 0) { if(!sess->active || !sess->s) { /* its a strange world .. */ log_debug(ZONE, "Got packet for %s - dropping", !sess->s ? "session without stream (PBX pipe session?)" : "inactive session"); nad_free(nad); return 0; } /* sm is bouncing something */ if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) { if(s) { /* there's really no graceful way to handle this */ sx_error(s, stream_err_INTERNAL_SERVER_ERROR, "session manager failed control action"); sx_close(s); } nad_free(nad); return 0; } /* we're counting packets */ sess->packet_count++; sess->c2s->packet_count++; /* remove sm specifics */ nad_set_attr(nad, 1, ns, "c2s", NULL, 0); nad_set_attr(nad, 1, ns, "sm", NULL, 0); /* forget about the internal namespace too */ if(nad->elems[1].ns == ns) nad->elems[1].ns = nad->nss[ns].next; else { for(scan = nad->elems[1].ns; nad->nss[scan].next != -1 && nad->nss[scan].next != ns; scan = nad->nss[scan].next); /* got it */ if(nad->nss[scan].next != -1) nad->nss[scan].next = nad->nss[ns].next; } sx_nad_write_elem(sess->s, nad, 1); return 0; } /* its something else */ log_debug(ZONE, "unknown packet, dropping"); nad_free(nad); return 0; case event_CLOSED: mio_close(c2s->mio, c2s->fd); c2s->fd = NULL; return -1; } return 0; } int c2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { c2s_t c2s = (c2s_t) arg; int nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(c2s->router); return 0; } return sx_can_read(c2s->router); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(c2s->router); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); log_write(c2s->log, LOG_NOTICE, "connection to router closed"); c2s_lost_router = 1; /* we're offline */ c2s->online = 0; break; case action_ACCEPT: break; } return 0; } jabberd2-jabberd-2.3.4/c2s/c2s.h000066400000000000000000000301271261462775300161310ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifdef HAVE_CONFIG_H # include #endif #include #include "mio/mio.h" #include "sx/sx.h" #include "util/util.h" #ifdef HAVE_SIGNAL_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef _WIN32 #ifdef _USRDLL #define DLLEXPORT __declspec(dllexport) #define C2S_API __declspec(dllimport) #else #define DLLEXPORT __declspec(dllimport) #define C2S_API __declspec(dllexport) #endif #else #define DLLEXPORT #define C2S_API #endif /* forward declarations */ typedef struct host_st *host_t; typedef struct c2s_st *c2s_t; typedef struct bres_st *bres_t; typedef struct sess_st *sess_t; typedef struct authreg_st *authreg_t; /** list of resources bound to session */ struct bres_st { /** full bound jid */ jid_t jid; /** session id for this jid for us and them */ char c2s_id[44], sm_id[41]; /** this holds the id of the current pending SM request */ char sm_request[41]; bres_t next; }; /** * There is one instance of this struct per user who is logged in to * this c2s instance. */ struct sess_st { c2s_t c2s; mio_fd_t fd; char skey[44]; const char *smcomp; /* sm component servicing this session */ const char *ip; int port; sx_t s; /** host this session belongs to */ host_t host; rate_t rate; int rate_log; rate_t stanza_rate; int stanza_rate_log; time_t last_activity; unsigned int packet_count; /* count of bound resources */ int bound; /* list of bound jids */ bres_t resources; int active; /* session related packet waiting for sm response */ nad_t result; int sasl_authd; /* 1 = they did a sasl auth */ /** Apple: session challenge for challenge-response authentication */ char auth_challenge[65]; /* Per user session authreg private data */ void *authreg_private; }; /* allowed mechanisms */ #define AR_MECH_TRAD_PLAIN (1<<0) #define AR_MECH_TRAD_DIGEST (1<<1) #define AR_MECH_TRAD_CRAMMD5 (1<<2) struct host_st { /** our realm (SASL) */ const char *realm; /** starttls pemfile */ const char *host_pemfile; /** certificate chain */ const char *host_cachain; /** private key password */ char *host_private_key_password; /** verify-mode */ int host_verify_mode; /** require starttls */ int host_require_starttls; /** list of TLS ciphers */ const char *host_ciphers; /* authreg module if different than default */ const char *ar_module_name; authreg_t ar; /** registration */ int ar_register_enable; const char *ar_register_instructions; const char *ar_register_oob; int ar_register_password; }; struct c2s_st { /** our id (hostname) with the router */ const char *id; /** how to connect to the router */ const char *router_ip; int router_port; const char *router_user; const char *router_pass; const char *router_pemfile; const char *router_cachain; const char *router_private_key_password; const char *router_ciphers; /** mio context */ mio_t mio; /** sessions */ xht sessions; /** sx environment */ sx_env_t sx_env; sx_plugin_t sx_ssl; sx_plugin_t sx_sasl; /** router's conn */ sx_t router; mio_fd_t fd; /** listening sockets */ mio_fd_t server_fd; #ifdef HAVE_SSL mio_fd_t server_ssl_fd; #endif /** config */ config_t config; /** logging */ log_t log; /** log data */ log_type_t log_type; const char *log_facility; const char *log_ident; /** packet counter */ long long int packet_count; const char *packet_stats; /** connect retry */ int retry_init; int retry_lost; int retry_sleep; int retry_left; /** ip to listen on */ const char *local_ip; /** unencrypted port */ int local_port; /** encrypted port */ int local_ssl_port; /** encrypted port pemfile */ const char *local_pemfile; /** encrypted port cachain file */ const char *local_cachain; /** private key password */ const char *local_private_key_password; /** verify-mode */ int local_verify_mode; /** list of TLS ciphers */ const char *local_ciphers; /** http forwarding URL */ const char *http_forward; /** websocket support */ int websocket; /** PBX integration named pipe */ const char *pbx_pipe; int pbx_pipe_fd; mio_fd_t pbx_pipe_mio_fd; /** stream redirection (see-other-host) on session connect */ xht stream_redirects; /** max file descriptors */ int io_max_fds; /** enable Stream Compression */ int compression; /** time checks */ int io_check_interval; int io_check_idle; int io_check_keepalive; time_t next_check; /** default auth/reg module */ const char *ar_module_name; authreg_t ar; /** loaded auth/reg modules */ xht ar_modules; /** allowed mechanisms */ int ar_mechanisms; int ar_ssl_mechanisms; /** connection rates */ int conn_rate_total; int conn_rate_seconds; int conn_rate_wait; xht conn_rates; /** byte rates (karma) */ int byte_rate_total; int byte_rate_seconds; int byte_rate_wait; /** stanza rates */ int stanza_rate_total; int stanza_rate_seconds; int stanza_rate_wait; /** maximum stanza size */ int stanza_size_limit; /** access controls */ access_t access; /** list of sx_t on the way out */ jqueue_t dead; /** list of sess on the way out */ jqueue_t dead_sess; /** this is true if we've connected to the router at least once */ int started; /** true if we're bound in the router */ int online; /** hosts mapping */ xht hosts; host_t vhost; /** availability of sms that we are servicing */ xht sm_avail; }; extern sig_atomic_t c2s_lost_router; C2S_API int c2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); C2S_API int c2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); C2S_API void sm_start(sess_t sess, bres_t res); C2S_API void sm_end(sess_t sess, bres_t res); C2S_API void sm_create(sess_t sess, bres_t res); C2S_API void sm_delete(sess_t sess, bres_t res); C2S_API void sm_packet(sess_t sess, bres_t res, nad_t nad); C2S_API int bind_init(sx_env_t env, sx_plugin_t p, va_list args); C2S_API void c2s_pbx_init(c2s_t c2s); /* My IP Address plugin */ JABBERD2_API int address_init(sx_env_t env, sx_plugin_t p, va_list args); struct authreg_st { c2s_t c2s; int initialized; /** module private data */ void *private; /** returns 1 if the user exists, 0 if not */ int (*user_exists)(authreg_t ar, sess_t sess, const char *username,const char *realm); /** return this users cleartext password in the array (digest auth, password auth) */ int (*get_password)(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]); /** check the given password against the stored password, 0 if equal, !0 if not equal (password auth) */ int (*check_password)(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]); /** store this password (register) */ int (*set_password)(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]); /** make or break the user (register / register remove) */ int (*create_user)(authreg_t ar, sess_t sess, const char *username, const char *realm); int (*delete_user)(authreg_t ar, sess_t sess, const char *username, const char *realm); /** called prior to session being closed, to cleanup session specific private data */ void (*sess_end)(authreg_t ar, sess_t sess); /** called prior to authreg shutdown */ void (*free)(authreg_t ar); /* Additions at the end - to preserve offsets for existing modules */ /** returns 1 if the user is permitted to authorize as the requested_user, 0 if not. requested_user is a JID */ int (*user_authz_allowed)(authreg_t ar, sess_t sess, const char *username, const char *realm, const char *requested_user); /** Apple extensions for challenge/response authentication methods */ int (*create_challenge)(authreg_t ar, sess_t sess, const char *username, const char *realm, char *challenge, int maxlen); int (*check_response)(authreg_t ar, sess_t sess, const char *username, const char *realm, const char *challenge, const char *response); }; /** get a handle for a single module */ C2S_API authreg_t authreg_init(c2s_t c2s, const char *name); /** shut down */ C2S_API void authreg_free(authreg_t ar); /** type for the module init function */ typedef int (*ar_module_init_fn)(authreg_t); /** the main authreg processor */ C2S_API int authreg_process(c2s_t c2s, sess_t sess, nad_t nad); /* int authreg_user_exists(authreg_t ar, const char *username, const char *realm); int authreg_get_password(authreg_t ar, const char *username, const char *realm, char password[257]); int authreg_check_password(authreg_t ar, const char *username, const char *realm, char password[257]); int authreg_set_password(authreg_t ar, const char *username, const char *realm, char password[257]); int authreg_create_user(authreg_t ar, const char *username, const char *realm); int authreg_delete_user(authreg_t ar, const char *username, const char *realm); void authreg_free(authreg_t ar); */ /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; const char **char_val; sess_t *sess_val; }; // Data for stream redirect errors typedef struct stream_redirect_st { const char *to_address; const char *to_port; } *stream_redirect_t; jabberd2-jabberd-2.3.4/c2s/main.c000066400000000000000000001106541261462775300163650ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "c2s.h" #include static sig_atomic_t c2s_shutdown = 0; sig_atomic_t c2s_lost_router = 0; static sig_atomic_t c2s_logrotate = 0; static sig_atomic_t c2s_sighup = 0; static void _c2s_signal(int signum) { c2s_shutdown = 1; c2s_lost_router = 0; } static void _c2s_signal_hup(int signum) { c2s_logrotate = 1; c2s_sighup = 1; } static void _c2s_signal_usr1(int signum) { set_debug_flag(0); } static void _c2s_signal_usr2(int signum) { set_debug_flag(1); } /** store the process id */ static void _c2s_pidfile(c2s_t c2s) { const char *pidfile; FILE *f; pid_t pid; pidfile = config_get_one(c2s->config, "pidfile", 0); if(pidfile == NULL) return; pid = getpid(); if((f = fopen(pidfile, "w+")) == NULL) { log_write(c2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno)); return; } if(fprintf(f, "%d", pid) < 0) { log_write(c2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno)); fclose(f); return; } fclose(f); log_write(c2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile); } /** pull values out of the config file */ static void _c2s_config_expand(c2s_t c2s) { const char *str, *ip, *mask; char *req_domain, *to_address, *to_port; config_elem_t elem; int i; stream_redirect_t sr; set_debug_log_from_config(c2s->config); c2s->id = config_get_one(c2s->config, "id", 0); if(c2s->id == NULL) c2s->id = "c2s"; c2s->router_ip = config_get_one(c2s->config, "router.ip", 0); if(c2s->router_ip == NULL) c2s->router_ip = "127.0.0.1"; c2s->router_port = j_atoi(config_get_one(c2s->config, "router.port", 0), 5347); c2s->router_user = config_get_one(c2s->config, "router.user", 0); if(c2s->router_user == NULL) c2s->router_user = "jabberd"; c2s->router_pass = config_get_one(c2s->config, "router.pass", 0); if(c2s->router_pass == NULL) c2s->router_pass = "secret"; c2s->router_pemfile = config_get_one(c2s->config, "router.pemfile", 0); c2s->router_cachain = config_get_one(c2s->config, "router.cachain", 0); c2s->router_private_key_password = config_get_one(c2s->config, "router.private_key_password", 0); c2s->router_ciphers = config_get_one(c2s->config, "router.ciphers", 0); c2s->retry_init = j_atoi(config_get_one(c2s->config, "router.retry.init", 0), 3); c2s->retry_lost = j_atoi(config_get_one(c2s->config, "router.retry.lost", 0), 3); if((c2s->retry_sleep = j_atoi(config_get_one(c2s->config, "router.retry.sleep", 0), 2)) < 1) c2s->retry_sleep = 1; c2s->log_type = log_STDOUT; if(config_get(c2s->config, "log") != NULL) { if((str = config_get_attr(c2s->config, "log", 0, "type")) != NULL) { if(strcmp(str, "file") == 0) c2s->log_type = log_FILE; else if(strcmp(str, "syslog") == 0) c2s->log_type = log_SYSLOG; } } if(c2s->log_type == log_SYSLOG) { c2s->log_facility = config_get_one(c2s->config, "log.facility", 0); c2s->log_ident = config_get_one(c2s->config, "log.ident", 0); if(c2s->log_ident == NULL) c2s->log_ident = "jabberd/c2s"; } else if(c2s->log_type == log_FILE) c2s->log_ident = config_get_one(c2s->config, "log.file", 0); c2s->packet_stats = config_get_one(c2s->config, "stats.packet", 0); c2s->local_ip = config_get_one(c2s->config, "local.ip", 0); if(c2s->local_ip == NULL) c2s->local_ip = "0.0.0.0"; c2s->local_port = j_atoi(config_get_one(c2s->config, "local.port", 0), 0); c2s->local_pemfile = config_get_one(c2s->config, "local.pemfile", 0); c2s->local_cachain = config_get_one(c2s->config, "local.cachain", 0); c2s->local_private_key_password = config_get_one(c2s->config, "local.private_key_password", 0); c2s->local_verify_mode = j_atoi(config_get_one(c2s->config, "local.verify-mode", 0), 0); c2s->local_ciphers = config_get_one(c2s->config, "local.ciphers", 0); c2s->local_ssl_port = j_atoi(config_get_one(c2s->config, "local.ssl-port", 0), 0); c2s->http_forward = config_get_one(c2s->config, "local.httpforward", 0); c2s->websocket = (config_get(c2s->config, "io.websocket") != NULL); c2s->io_max_fds = j_atoi(config_get_one(c2s->config, "io.max_fds", 0), 1024); c2s->compression = (config_get(c2s->config, "io.compression") != NULL); c2s->io_check_interval = j_atoi(config_get_one(c2s->config, "io.check.interval", 0), 0); c2s->io_check_idle = j_atoi(config_get_one(c2s->config, "io.check.idle", 0), 0); c2s->io_check_keepalive = j_atoi(config_get_one(c2s->config, "io.check.keepalive", 0), 0); c2s->pbx_pipe = config_get_one(c2s->config, "pbx.pipe", 0); elem = config_get(c2s->config, "stream_redirect.redirect"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st)); if(!sr) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting"); exit(1); } req_domain = j_attr((const char **) elem->attrs[i], "requested_domain"); to_address = j_attr((const char **) elem->attrs[i], "to_address"); to_port = j_attr((const char **) elem->attrs[i], "to_port"); if(req_domain == NULL || to_address == NULL || to_port == NULL) { log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping"); continue; } // Note that to_address should be RFC 3986 compliant sr->to_address = to_address; sr->to_port = to_port; xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr); } } c2s->ar_module_name = config_get_one(c2s->config, "authreg.module", 0); if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN; if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST; if(config_get(c2s->config, "authreg.mechanisms.traditional.cram-md5") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_CRAMMD5; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.plain") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_PLAIN; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.digest") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_DIGEST; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.cram-md5") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_CRAMMD5; elem = config_get(c2s->config, "io.limits.bytes"); if(elem != NULL) { c2s->byte_rate_total = j_atoi(elem->values[0], 0); if(c2s->byte_rate_total != 0) { c2s->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1); c2s->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } elem = config_get(c2s->config, "io.limits.stanzas"); if(elem != NULL) { c2s->stanza_rate_total = j_atoi(elem->values[0], 0); if(c2s->stanza_rate_total != 0) { c2s->stanza_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1); c2s->stanza_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } elem = config_get(c2s->config, "io.limits.connects"); if(elem != NULL) { c2s->conn_rate_total = j_atoi(elem->values[0], 0); if(c2s->conn_rate_total != 0) { c2s->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5); c2s->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } c2s->stanza_size_limit = j_atoi(config_get_one(c2s->config, "io.limits.stanzasize", 0), 0); /* tweak timed checks with rate times */ if(c2s->io_check_interval == 0) { if(c2s->byte_rate_total != 0) c2s->io_check_interval = c2s->byte_rate_wait; if(c2s->stanza_rate_total != 0 && c2s->io_check_interval > c2s->stanza_rate_wait) c2s->io_check_interval = c2s->stanza_rate_wait; } str = config_get_one(c2s->config, "io.access.order", 0); if(str == NULL || strcmp(str, "deny,allow") != 0) c2s->access = access_new(0); else c2s->access = access_new(1); elem = config_get(c2s->config, "io.access.allow"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_allow(c2s->access, ip, mask); } } elem = config_get(c2s->config, "io.access.deny"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_deny(c2s->access, ip, mask); } } } static void _c2s_hosts_expand(c2s_t c2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(c2s->config, "local.id"); if(!elem) { log_write(c2s->log, LOG_NOTICE, "no local.id configured - skipping local domains configuration"); return; } for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(c2s->hosts), sizeof(struct host_st)); if(!host) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(c2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(c2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); host->host_private_key_password = j_attr((const char **) elem->attrs[i], "private-key-password"); host->host_ciphers = j_attr((const char **) elem->attrs[i], "ciphers"); #ifdef HAVE_SSL if(host->host_pemfile != NULL) { if(c2s->sx_ssl == NULL) { c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password, host->host_ciphers); if(c2s->sx_ssl == NULL) { log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } else { if(sx_ssl_server_addcert(c2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password, host->host_ciphers) != 0) { log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif host->host_require_starttls = (j_attr((const char **) elem->attrs[i], "require-starttls") != NULL); host->ar_module_name = j_attr((const char **) elem->attrs[i], "authreg-module"); if(host->ar_module_name) { if((host->ar = authreg_init(c2s, host->ar_module_name)) == NULL) { log_write(c2s->log, LOG_NOTICE, "failed to load %s authreg module - using default", host->realm); host->ar = c2s->ar; } } else host->ar = c2s->ar; host->ar_register_enable = (j_attr((const char **) elem->attrs[i], "register-enable") != NULL); host->ar_register_oob = j_attr((const char **) elem->attrs[i], "register-oob"); if(host->ar_register_enable || host->ar_register_oob) { host->ar_register_instructions = j_attr((const char **) elem->attrs[i], "instructions"); if(host->ar_register_instructions == NULL) { if(host->ar_register_oob) host->ar_register_instructions = "Only web based registration is possible with this server."; else host->ar_register_instructions = "Enter a username and password to register with this server."; } } else host->ar_register_password = (j_attr((const char **) elem->attrs[i], "password-change") != NULL); /* check for empty CDATA - XXX this "1" is VERY config.c dependant !!! */ if(! strcmp(id, "1")) { /* remove the realm even if set */ host->realm = NULL; /* skip if vHost already configured */ if(! c2s->vhost) c2s->vhost = host; /* add meaningful log "id" */ strcpy(id, "default vHost"); } else { /* insert into vHosts xhash */ xhash_put(c2s->hosts, pstrdup(xhash_pool(c2s->hosts), id), host); } log_write(c2s->log, LOG_NOTICE, "[%s] configured; realm=%s, authreg=%s, registration %s, using PEM:%s", id, (host->realm != NULL ? host->realm : "no realm set"), (host->ar_module_name ? host->ar_module_name : c2s->ar_module_name), (host->ar_register_enable ? "enabled" : "disabled"), (host->host_pemfile ? host->host_pemfile : "Default")); } } static int _c2s_router_connect(c2s_t c2s) { log_write(c2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", c2s->router_ip, c2s->router_port); c2s->fd = mio_connect(c2s->mio, c2s->router_port, c2s->router_ip, NULL, c2s_router_mio_callback, (void *) c2s); if(c2s->fd == NULL) { if(errno == ECONNREFUSED) c2s_lost_router = 1; log_write(c2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR); return 1; } c2s->router = sx_new(c2s->sx_env, c2s->fd->fd, c2s_router_sx_callback, (void *) c2s); sx_client_init(c2s->router, 0, NULL, NULL, NULL, "1.0"); return 0; } static int _c2s_sx_sasl_callback(int cb, void *arg, void **res, sx_t s, void *cbarg) { c2s_t c2s = (c2s_t) cbarg; const char *my_realm, *mech; sx_sasl_creds_t creds; static char buf[3072]; char mechbuf[256]; struct jid_st jid; jid_static_buf jid_buf; int i, r; sess_t sess; char skey[44]; host_t host; /* init static jid */ jid_static(&jid,&jid_buf); /* retrieve our session */ assert(s != NULL); sprintf(skey, "%d", s->tag); /* * Retrieve the session, note that depending on the operation, * session may be null. */ sess = xhash_get(c2s->sessions, skey); switch(cb) { case sx_sasl_cb_GET_REALM: if(s->req_to == NULL) /* this shouldn't happen */ my_realm = ""; else { /* get host for request */ host = xhash_get(c2s->hosts, s->req_to); if(host == NULL) { log_write(c2s->log, LOG_ERR, "SASL callback for non-existing host: %s", s->req_to); *res = (void *)NULL; return sx_sasl_ret_FAIL; } my_realm = host->realm; if(my_realm == NULL) my_realm = s->req_to; } strncpy(buf, my_realm, 256); *res = (void *)buf; log_debug(ZONE, "sx sasl callback: get realm: realm is '%s'", buf); return sx_sasl_ret_OK; break; case sx_sasl_cb_GET_PASS: assert(sess != NULL); creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); if(sess->host->ar->get_password && (sess->host->ar->get_password)( sess->host->ar, sess, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm: "", buf) == 0) { *res = buf; return sx_sasl_ret_OK; } return sx_sasl_ret_FAIL; case sx_sasl_cb_CHECK_PASS: assert(sess != NULL); creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); if(sess->host->ar->check_password != NULL) { if ((sess->host->ar->check_password)( sess->host->ar, sess, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", (char *)creds->pass) == 0) return sx_sasl_ret_OK; else return sx_sasl_ret_FAIL; } if(sess->host->ar->get_password != NULL) { if ((sess->host->ar->get_password)(sess->host->ar, sess, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", buf) != 0) return sx_sasl_ret_FAIL; if (strcmp(creds->pass, buf)==0) return sx_sasl_ret_OK; } return sx_sasl_ret_FAIL; break; case sx_sasl_cb_CHECK_AUTHZID: assert(sess != NULL); creds = (sx_sasl_creds_t) arg; /* we need authzid to validate */ if(creds->authzid == NULL || creds->authzid[0] == '\0') return sx_sasl_ret_FAIL; /* authzid must be a valid jid */ if(jid_reset(&jid, creds->authzid, -1) == NULL) return sx_sasl_ret_FAIL; /* and have domain == stream to addr */ if(!s->req_to || (strcmp(jid.domain, s->req_to) != 0)) return sx_sasl_ret_FAIL; /* and have no resource */ if(jid.resource[0] != '\0') return sx_sasl_ret_FAIL; /* and user has right to authorize as */ if (sess->host->ar->user_authz_allowed) { if (sess->host->ar->user_authz_allowed(sess->host->ar, sess, (char *)creds->authnid, (char *)creds->realm, (char *)creds->authzid)) return sx_sasl_ret_OK; } else { if (strcmp(creds->authnid, jid.node) == 0 && (sess->host->ar->user_exists)(sess->host->ar, sess, jid.node, jid.domain)) return sx_sasl_ret_OK; } return sx_sasl_ret_FAIL; case sx_sasl_cb_GEN_AUTHZID: /* generate a jid for SASL ANONYMOUS */ jid_reset(&jid, s->req_to, -1); /* make node a random string */ jid_random_part(&jid, jid_NODE); strcpy(buf, jid.node); *res = (void *)buf; return sx_sasl_ret_OK; break; case sx_sasl_cb_CHECK_MECH: mech = (char *)arg; i=0; while(ihosts, s->req_to); if(host == NULL) { log_write(c2s->log, LOG_WARNING, "SASL callback for non-existing host: %s", s->req_to); return sx_sasl_ret_FAIL; } /* Determine if our configuration will let us use this mechanism. * We support different mechanisms for both SSL and normal use */ if (strcmp(mechbuf, "digest-md5") == 0) { /* digest-md5 requires that our authreg support get_password */ if (host->ar->get_password == NULL) return sx_sasl_ret_FAIL; } else if (strcmp(mechbuf, "plain") == 0) { /* plain requires either get_password or check_password */ if (host->ar->get_password == NULL && host->ar->check_password == NULL) return sx_sasl_ret_FAIL; } /* Using SSF is potentially dangerous, as SASL can also set the * SSF of the connection. However, SASL shouldn't do so until after * we've finished mechanism establishment */ if (s->ssf>0) { r = snprintf(buf, sizeof(buf), "authreg.ssl-mechanisms.sasl.%s",mechbuf); if (r < -1 || r > sizeof(buf)) return sx_sasl_ret_FAIL; if(config_get(c2s->config,buf) != NULL) return sx_sasl_ret_OK; } r = snprintf(buf, sizeof(buf), "authreg.mechanisms.sasl.%s",mechbuf); if (r < -1 || r > sizeof(buf)) return sx_sasl_ret_FAIL; /* Work out if our configuration will let us use this mechanism */ if(config_get(c2s->config,buf) != NULL) return sx_sasl_ret_OK; else return sx_sasl_ret_FAIL; default: break; } return sx_sasl_ret_FAIL; } static void _c2s_time_checks(c2s_t c2s) { sess_t sess; time_t now; union xhashv xhv; now = time(NULL); if(xhash_iter_first(c2s->sessions)) do { xhv.sess_val = &sess; xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val); if(c2s->io_check_idle > 0 && sess->s && now > sess->last_activity + c2s->io_check_idle) { log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] timed out", sess->fd->fd, sess->ip, sess->port); sx_error(sess->s, stream_err_HOST_GONE, "connection timed out"); sx_close(sess->s); continue; } if(c2s->io_check_keepalive > 0 && now > sess->last_activity + c2s->io_check_keepalive && sess->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", sess->fd->fd); sx_raw_write(sess->s, " ", 1); } if(sess->rate != NULL && sess->rate->bad != 0 && rate_check(sess->rate) != 0) { /* read the pending bytes when rate limit is no longer in effect */ log_debug(ZONE, "reading throttled %d", sess->fd->fd); sess->s->want_read = 1; sx_can_read(sess->s); } } while(xhash_iter_next(c2s->sessions)); } static void _c2s_ar_free(const char *module, int modulelen, void *val, void *arg) { authreg_t ar = (authreg_t) val; authreg_free(ar); } JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S", "Jabber Open Source Server: Client to Server", "jabberd2router\0") { c2s_t c2s; char *config_file; int optchar; int mio_timeout; sess_t sess; bres_t res; union xhashv xhv; time_t check_time = 0; const char *cli_id = 0; #ifdef HAVE_UMASK umask((mode_t) 0027); #endif srand(time(NULL)); #ifdef HAVE_WINSOCK2_H /* get winsock running */ { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* !!! tell user that we couldn't find a usable winsock dll */ return 0; } } #endif jabber_signal(SIGINT, _c2s_signal); jabber_signal(SIGTERM, _c2s_signal); #ifdef SIGHUP jabber_signal(SIGHUP, _c2s_signal_hup); #endif #ifdef SIGPIPE jabber_signal(SIGPIPE, SIG_IGN); #endif jabber_signal(SIGUSR1, _c2s_signal_usr1); jabber_signal(SIGUSR2, _c2s_signal_usr2); c2s = (c2s_t) calloc(1, sizeof(struct c2s_st)); /* load our config */ c2s->config = config_new(); config_file = CONFIG_DIR "/c2s.xml"; /* cmdline parsing */ while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0) { switch(optchar) { case 'c': config_file = optarg; break; case 'D': #ifdef DEBUG set_debug_flag(1); #else printf("WARN: Debugging not enabled. Ignoring -D.\n"); #endif break; case 'i': cli_id = optarg; break; case 'h': case '?': default: fputs( "c2s - jabberd client-to-server connector (" VERSION ")\n" "Usage: c2s \n" "Options are:\n" " -c config file to use [default: " CONFIG_DIR "/c2s.xml]\n" " -i id Override config element\n" #ifdef DEBUG " -D Show debug output\n" #endif , stdout); config_free(c2s->config); free(c2s); return 1; } } if(config_load_with_id(c2s->config, config_file, cli_id) != 0) { fputs("c2s: couldn't load config, aborting\n", stderr); config_free(c2s->config); free(c2s); return 2; } c2s->stream_redirects = xhash_new(11); _c2s_config_expand(c2s); c2s->ar_modules = xhash_new(5); if(c2s->ar_module_name == NULL) { log_write(c2s->log, LOG_NOTICE, "no default authreg module specified in config file"); } else if((c2s->ar = authreg_init(c2s, c2s->ar_module_name)) == NULL) { access_free(c2s->access); config_free(c2s->config); log_free(c2s->log); free(c2s); exit(1); } c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility); log_write(c2s->log, LOG_NOTICE, "starting up"); _c2s_pidfile(c2s); c2s->sessions = xhash_new(1023); c2s->conn_rates = xhash_new(101); c2s->dead = jqueue_new(); c2s->dead_sess = jqueue_new(); c2s->sx_env = sx_env_new(); #ifdef USE_WEBSOCKET /* possibly wrap in websocket */ if(c2s->websocket) { sx_env_plugin(c2s->sx_env, sx_websocket_init, c2s->http_forward); } #else if(c2s->http_forward) { log_write(c2s->log, LOG_ERR, "httpforward available only with websocket support built-in"); } #endif #ifdef HAVE_SSL /* get the ssl context up and running */ if(c2s->local_pemfile != NULL) { c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->local_pemfile, c2s->local_cachain, c2s->local_verify_mode, c2s->local_private_key_password, c2s->local_ciphers); if(c2s->sx_ssl == NULL) { log_write(c2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to clients"); c2s->local_pemfile = NULL; } } /* try and get something online, so at least we can encrypt to the router */ if(c2s->sx_ssl == NULL && c2s->router_pemfile != NULL) { c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, NULL, c2s->router_pemfile, c2s->router_cachain, NULL, c2s->router_private_key_password, c2s->router_ciphers); if(c2s->sx_ssl == NULL) { log_write(c2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted"); c2s->router_pemfile = NULL; } } #endif #ifdef HAVE_LIBZ /* get compression up and running */ if(c2s->compression) sx_env_plugin(c2s->sx_env, sx_compress_init); #endif /* get stanza ack up */ sx_env_plugin(c2s->sx_env, sx_ack_init); /* and user IP address plugin */ sx_env_plugin(c2s->sx_env, address_init); /* get sasl online */ c2s->sx_sasl = sx_env_plugin(c2s->sx_env, sx_sasl_init, "xmpp", _c2s_sx_sasl_callback, (void *) c2s); if(c2s->sx_sasl == NULL) { log_write(c2s->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); } /* get bind up */ sx_env_plugin(c2s->sx_env, bind_init, c2s); c2s->mio = mio_new(c2s->io_max_fds); if(c2s->mio == NULL) { log_write(c2s->log, LOG_ERR, "failed to create MIO, aborting"); exit(1); } /* hosts mapping */ c2s->hosts = xhash_new(1021); _c2s_hosts_expand(c2s); c2s->sm_avail = xhash_new(1021); c2s->retry_left = c2s->retry_init; _c2s_router_connect(c2s); mio_timeout = ((c2s->io_check_interval != 0 && c2s->io_check_interval < 5) ? c2s->io_check_interval : 5); while(!c2s_shutdown) { mio_run(c2s->mio, mio_timeout); if(c2s_logrotate) { set_debug_log_from_config(c2s->config); log_write(c2s->log, LOG_NOTICE, "reopening log ..."); log_free(c2s->log); c2s->log = log_new(c2s->log_type, c2s->log_ident, c2s->log_facility); log_write(c2s->log, LOG_NOTICE, "log started"); c2s_logrotate = 0; } if(c2s_sighup) { log_write(c2s->log, LOG_NOTICE, "reloading some configuration items ..."); config_t conf; conf = config_new(); if (conf && config_load(conf, config_file) == 0) { xhash_free(c2s->stream_redirects); c2s->stream_redirects = xhash_new(11); char *req_domain, *to_address, *to_port; config_elem_t elem; int i; stream_redirect_t sr; elem = config_get(conf, "stream_redirect.redirect"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st)); if(!sr) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting"); exit(1); } req_domain = j_attr((const char **) elem->attrs[i], "requested_domain"); to_address = j_attr((const char **) elem->attrs[i], "to_address"); to_port = j_attr((const char **) elem->attrs[i], "to_port"); if(req_domain == NULL || to_address == NULL || to_port == NULL) { log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping"); continue; } // Note that to_address should be RFC 3986 compliant sr->to_address = to_address; sr->to_port = to_port; xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr); } } config_free(conf); } else { log_write(c2s->log, LOG_WARNING, "couldn't reload config (%s)", config_file); if (conf) config_free(conf); } c2s_sighup = 0; } if(c2s_lost_router) { if(c2s->retry_left < 0) { log_write(c2s->log, LOG_NOTICE, "attempting reconnect"); sleep(c2s->retry_sleep); c2s_lost_router = 0; if (c2s->router) sx_free(c2s->router); _c2s_router_connect(c2s); } else if(c2s->retry_left == 0) { c2s_shutdown = 1; } else { log_write(c2s->log, LOG_NOTICE, "attempting reconnect (%d left)", c2s->retry_left); c2s->retry_left--; sleep(c2s->retry_sleep); c2s_lost_router = 0; if (c2s->router) sx_free(c2s->router); _c2s_router_connect(c2s); } } /* cleanup dead sess (before sx_t as sess->result uses sx_t nad cache) */ while(jqueue_size(c2s->dead_sess) > 0) { sess = (sess_t) jqueue_pull(c2s->dead_sess); /* free sess data */ if(sess->ip != NULL) free((void*)sess->ip); if(sess->smcomp != NULL) free((void*)sess->smcomp); if(sess->result != NULL) nad_free(sess->result); if(sess->resources != NULL) for(res = sess->resources; res != NULL;) { bres_t tmp = res->next; jid_free(res->jid); free(res); res = tmp; } if(sess->rate != NULL) rate_free(sess->rate); if(sess->stanza_rate != NULL) rate_free(sess->stanza_rate); free(sess); } /* cleanup dead sx_ts */ while(jqueue_size(c2s->dead) > 0) sx_free((sx_t) jqueue_pull(c2s->dead)); /* time checks */ if(c2s->io_check_interval > 0 && time(NULL) >= c2s->next_check) { log_debug(ZONE, "running time checks"); _c2s_time_checks(c2s); c2s->next_check = time(NULL) + c2s->io_check_interval; log_debug(ZONE, "next time check at %d", c2s->next_check); } if(time(NULL) > check_time + 60) { #ifdef POOL_DEBUG pool_stat(1); #endif if(c2s->packet_stats != NULL) { int fd = open(c2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd >= 0) { char buf[100]; int len = snprintf(buf, 100, "%lld\n", c2s->packet_count); if (write(fd, buf, len) != len) { close(fd); fd = -1; } else close(fd); } if (fd < 0) { log_write(c2s->log, LOG_ERR, "failed to write packet statistics to: %s", c2s->packet_stats); c2s_shutdown = 1; } } check_time = time(NULL); } } log_write(c2s->log, LOG_NOTICE, "shutting down"); if(xhash_iter_first(c2s->sessions)) do { xhv.sess_val = &sess; xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val); if(sess->active && sess->s) sx_close(sess->s); } while(xhash_iter_next(c2s->sessions)); /* cleanup dead sess */ while(jqueue_size(c2s->dead_sess) > 0) { sess = (sess_t) jqueue_pull(c2s->dead_sess); /* free sess data */ if(sess->ip != NULL) free((void*)sess->ip); if(sess->result != NULL) nad_free(sess->result); if(sess->resources != NULL) for(res = sess->resources; res != NULL;) { bres_t tmp = res->next; jid_free(res->jid); free(res); res = tmp; } free(sess); } while(jqueue_size(c2s->dead) > 0) sx_free((sx_t) jqueue_pull(c2s->dead)); if (c2s->fd != NULL) mio_close(c2s->mio, c2s->fd); sx_free(c2s->router); sx_env_free(c2s->sx_env); mio_free(c2s->mio); xhash_free(c2s->sessions); xhash_walk(c2s->ar_modules, _c2s_ar_free, NULL); xhash_free(c2s->ar_modules); xhash_free(c2s->conn_rates); xhash_free(c2s->stream_redirects); xhash_free(c2s->sm_avail); xhash_free(c2s->hosts); jqueue_free(c2s->dead); jqueue_free(c2s->dead_sess); access_free(c2s->access); log_free(c2s->log); config_free(c2s->config); free(c2s); #ifdef POOL_DEBUG pool_stat(1); #endif #ifdef HAVE_WINSOCK2_H WSACleanup(); #endif return 0; } jabberd2-jabberd-2.3.4/c2s/pbx.c000066400000000000000000000100711261462775300162220ustar00rootroot00000000000000/* vim: set noet ts=4 sw=4: */ /* * jabberd - Jabber Open Source Server * Copyright (c) 2009 Tomasz Sterna * * 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, MA02111-1307USA */ /** @file c2s/pbx.c * @brief PBX integration * @author Tomasz Sterna * $Date$ * $Revision$ */ #include "c2s.h" #define COMMANDLINE_LENGTH_MAX 2048 static void _pbx_close_pipe(c2s_t c2s); static void _pbx_open_pipe(c2s_t c2s, int mode); static void _pbx_read_pipe(c2s_t c2s); static void _pbx_write_pipe(c2s_t c2s); int _pbx_process_command(c2s_t c2s, const char *cmd); static void _pbx_read_command(c2s_t c2s) { char buf[COMMANDLINE_LENGTH_MAX]; char *bufp; bufp = (char*)&buf; while (read(c2s->pbx_pipe_fd, bufp, 1) > 0) if(bufp - ((char*)&buf) < COMMANDLINE_LENGTH_MAX-1) bufp++; *bufp = '\0'; log_debug(ZONE, "command read: %s", buf); _pbx_close_pipe(c2s); if(_pbx_process_command(c2s, buf) == 0) _pbx_write_pipe(c2s); _pbx_read_pipe(c2s); } static int _pbx_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { c2s_t c2s = (c2s_t) arg; log_debug(ZONE, "action %s on PBX pipe", a==0?"action_ACCEPT":a==1?"action_READ":a==2?"action_WRITE":a==3?"action_CLOSE":"-unknown-"); switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); _pbx_read_command(c2s); return 1; /* want to read again */ case action_WRITE: /* write buffered lines from jqueue */ _pbx_close_pipe(c2s); return 0; case action_CLOSE: c2s->pbx_pipe_mio_fd = 0; c2s->pbx_pipe_fd = -1; return 0; default: break; } return 0; } static void _pbx_close_pipe(c2s_t c2s) { log_debug(ZONE, "### close_pipe"); if(c2s->pbx_pipe_mio_fd) mio_close(c2s->mio, c2s->pbx_pipe_mio_fd); } static void _pbx_open_pipe(c2s_t c2s, int mode) { #ifdef WIN32 log_debug(ZONE, "PBX is not supported under Windows"); log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet"); exit(EXIT_FAILURE); #else log_debug(ZONE, "### open_pipe"); c2s->pbx_pipe_fd = open(c2s->pbx_pipe, mode | O_NONBLOCK); if(c2s->pbx_pipe_fd == -1) { c2s->pbx_pipe_mio_fd = 0; log_debug(ZONE, "error opening pipe: %d %s", errno, strerror(errno)); log_write(c2s->log, LOG_ERR, "failed to open PBX named pipe %s for %s", c2s->pbx_pipe, mode==O_RDONLY?"reading":"writing"); exit(EXIT_FAILURE); } else c2s->pbx_pipe_mio_fd = mio_register(c2s->mio, c2s->pbx_pipe_fd, _pbx_mio_callback, (void *) c2s); #endif } /* open pipe for reading */ static void _pbx_read_pipe(c2s_t c2s) { log_debug(ZONE, "### read_pipe"); _pbx_open_pipe(c2s, O_RDONLY); mio_read(c2s->mio, c2s->pbx_pipe_mio_fd); } /* trigger buffer write */ static void _pbx_write_pipe(c2s_t c2s) { log_debug(ZONE, "### write_pipe"); _pbx_open_pipe(c2s, O_RDWR); mio_write(c2s->mio, c2s->pbx_pipe_mio_fd); } void c2s_pbx_init(c2s_t c2s) { #ifdef WIN32 log_debug(ZONE, "PBX is not supported under Windows"); log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet"); exit(EXIT_FAILURE); #else struct stat sb; /* create the FIFO */ if(stat(c2s->pbx_pipe, &sb) == -1) { if(mkfifo(c2s->pbx_pipe, S_IRUSR | S_IWUSR | S_IRGRP) == -1) { log_write(c2s->log, LOG_ERR, "failed to create PBX named pipe: %s", c2s->pbx_pipe); exit(EXIT_FAILURE); } }else{ if(!S_ISFIFO(sb.st_mode)) { log_write(c2s->log, LOG_ERR, "file %s exists but is not a named pipe", c2s->pbx_pipe); exit(EXIT_FAILURE); } } _pbx_read_pipe(c2s); #endif } jabberd2-jabberd-2.3.4/c2s/pbx_commands.c000066400000000000000000000127201261462775300201060ustar00rootroot00000000000000/* vim: set noet ts=4 sw=4: */ /* * jabberd - Jabber Open Source Server * Copyright (c) 2009 Tomasz Sterna * * 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, MA02111-1307USA */ /** @file c2s/pbx_commands.c * @brief PBX integration commands interpreter * @author Tomasz Sterna * $Date$ * $Revision$ */ /** * Available commands: * START jid/resource [[priority ]status] [description] - opens PBX resource session * STOP jid/resource [description] - closes PBX resource session * STATUS - dumps list of currently open PBX sessions * * [status] in: CHAT, ONLINE, DND, AWAY, XA */ #include "c2s.h" static int _pbx_command_part_len(const char *cmd) { int i; for(i=0; *cmd != ' ' && *cmd != '\t' && *cmd != '\n' && *cmd != '\0'; cmd++, i++); return i; } static nad_t _pbx_presence_nad(int available, const char *cmd) { nad_t nad; int ns; char *show = NULL; nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "presence", 0); if(!available) { nad_append_attr(nad, -1, "type", "unavailable"); } else { char *cont; long int priority; char prioritystr[5]; // -128 to +127 + \0 priority = strtol(cmd, &cont, 10); log_debug(ZONE, "Read %ld priority", priority); if(cmd == cont) priority = -1; // use -1 priority if not given if(priority < -128) priority = -128; if(priority > 127) priority = 127; nad_append_elem(nad, -1, "priority", 1); snprintf(prioritystr, 5, "%ld", priority); nad_append_cdata(nad, prioritystr, strlen(prioritystr), 2); if(cmd != cont) { cmd = cont; while(*cmd == ' ') { cmd++; } } if(!strncmp("CHAT", cmd, 4)) { cmd += 4; show = "chat"; } if(!strncmp("ONLINE", cmd, 6)) { cmd += 6; } if(!strncmp("DND", cmd, 3)) { cmd += 3; show = "dnd"; } if(!strncmp("AWAY", cmd, 4)) { cmd += 4; show = "away"; } if(!strncmp("XA", cmd, 2)) { cmd += 2; show = "xa"; } if(show) { nad_append_elem(nad, -1, "show", 1); nad_append_cdata(nad, show, strlen(show), 2); } } while(*cmd == ' ') { cmd++; } if(*cmd != '\0' && *cmd != '\n') { int len = strlen(cmd); nad_append_elem(nad, -1, "status", 1); nad_append_cdata(nad, cmd, len - (cmd[len-1] == '\n' ? 1 : 0), 2); } return nad; } /** * process commandline * @return: 0 to indicate that output needs to be written */ int _pbx_process_command(c2s_t c2s, const char *cmd) { jid_t jid; int action = 0, len; sess_t sess; char hashbuf[44] = "PBX"; char *sesshash; sesshash = hashbuf+3; /* get command */ if(!strncasecmp("START ", cmd, 6)) { cmd += 6; action = 1; } if(!strncasecmp("STOP ", cmd, 5)) { cmd += 5; action = 2; } if(action != 0) { len = _pbx_command_part_len(cmd); if(len > 0) { jid = jid_new(cmd, len); if(jid) { cmd += len; if(*cmd != '\0') cmd++; shahash_r(jid_full(jid), sesshash); sess = xhash_get(c2s->sessions, hashbuf); switch(action) { case 1: log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd); if(sess == NULL) { /* create new session */ sess = (sess_t) calloc(1, sizeof(struct sess_st)); sess->c2s = c2s; sess->last_activity = time(NULL); /* put into sessions hash */ snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf); xhash_put(c2s->sessions, sess->skey, (void *) sess); /* generate bound resource */ sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf); sess->resources->jid = jid; /* open SM session */ log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid)); sm_start(sess, sess->resources); /* generate presence packet to get session online */ /* a bit hacky, but we need to emulate _some_ of the client behavior */ sess->result = _pbx_presence_nad(1, cmd); } else { /* just send the presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd)); } break; case 2: log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd); if(sess != NULL) { /* send unavailable presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd)); /* end the session */ sm_end(sess, sess->resources); xhash_zap(c2s->sessions, sess->skey); jqueue_push(c2s->dead_sess, (void *) sess, 0); } break; } /* TODO: respond with "OK", return 0 */ return -1; } } /* TODO: generate "ERR" response, return 0 */ return -1; } if(!strncasecmp("STATUS", cmd, 6)) { log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet"); return -1; } return -1; } jabberd2-jabberd-2.3.4/c2s/sm.c000066400000000000000000000066621261462775300160630ustar00rootroot00000000000000/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "c2s.h" /** generate a new session request id */ static void _sm_generate_id(sess_t sess, bres_t res, const char *type) { char str[3094]; /* JID=3071 chars max + time = 12 chars max + type = 10 chars max + terminator = 3094 */ snprintf(str, 3094, "%s%d%s", type, (int) time(NULL), jid_full(res->jid)); str[3093] = '\0'; shahash_r(str, res->sm_request); } /** make a new action route */ static nad_t _sm_build_route(sess_t sess, bres_t res, const char *action, const char *target, const char *id) { nad_t nad; int ns, ans; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "route", 0); nad_append_attr(nad, -1, "to", sess->smcomp?sess->smcomp:((char *) res->jid->domain)); nad_append_attr(nad, -1, "from", sess->c2s->id); ans = nad_add_namespace(nad, uri_SESSION, "sc"); nad_append_elem(nad, ans, "session", 1); if(res->c2s_id[0] != '\0') nad_append_attr(nad, ans, "c2s", res->c2s_id); if(res->sm_id[0] != '\0') nad_append_attr(nad, ans, "sm", res->sm_id); nad_append_attr(nad, -1, "action", action); if(target != NULL) nad_append_attr(nad, -1, "target", target); if(id != NULL) nad_append_attr(nad, -1, "id", id); log_debug(ZONE, "built new route nad for %s action %s target %s id %s", jid_full(res->jid), action, target, id); return nad; } void sm_start(sess_t sess, bres_t res) { _sm_generate_id(sess, res, "start"); sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "start", jid_full(res->jid), res->sm_request)); } void sm_end(sess_t sess, bres_t res) { sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "end", NULL, NULL)); } void sm_create(sess_t sess, bres_t res) { _sm_generate_id(sess, res, "create"); sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "create", jid_user(res->jid), res->sm_request)); } void sm_delete(sess_t sess, bres_t res) { sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "delete", jid_user(res->jid), NULL)); } void sm_packet(sess_t sess, bres_t res, nad_t nad) { int ns; ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_wrap_elem(nad, 0, ns, "route"); nad_set_attr(nad, 0, -1, "to", sess->smcomp?sess->smcomp:((char *) res->jid->domain), 0); nad_set_attr(nad, 0, -1, "from", sess->c2s->id, 0); ns = nad_append_namespace(nad, 1, uri_SESSION, "sc"); nad_set_attr(nad, 1, ns, "c2s", res->c2s_id, 0); if(res->c2s_id[0] != '\0') nad_set_attr(nad, 1, ns, "sm", res->sm_id, 0); sx_nad_write(sess->c2s->router, nad); } jabberd2-jabberd-2.3.4/config.rpath000077500000000000000000000334341261462775300171160ustar00rootroot00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2002 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a shlibext= host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix3* | aix4* | aix5*) wl='-Wl,' ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6*) wl='-Wl,' ;; linux*) echo '__INTEL_COMPILER' > conftest.$ac_ext if $CC -E conftest.$ac_ext >/dev/null | grep __INTEL_COMPILER >/dev/null then : else # Intel icc wl='-Qoption,ld,' fi ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) if test "x$host_vendor" = xsni; then wl='-LD' else wl='-Wl,' fi ;; esac fi hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then case "$host_os" in aix3* | aix4* | aix5*) # On AIX, the GNU linker is very broken ld_shlibs=no ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' ;; solaris* | sysv5*) if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi esac fi if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=yes ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9* | hpux10* | hpux11*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_minus_L=yes # Not in the search PATH, but as the default # location of the library. ;; irix5* | irix6*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; sco3.2v5*) ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) if test "x$host_vendor" = xsno; then hardcode_direct=yes # is this really true??? else hardcode_direct=no # Motorola manual says yes, but my tests say they lie fi ;; sysv4.3*) ;; sysv5*) hardcode_libdir_flag_spec= ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4.2uw2*) hardcode_direct=yes hardcode_minus_L=no ;; sysv5uw7* | unixware7*) ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics libname_spec='lib$name' sys_lib_dlsearch_path_spec="/lib /usr/lib" sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" case "$host_os" in aix3*) shlibext=so ;; aix4* | aix5*) shlibext=so ;; amigaos*) shlibext=ixlibrary ;; beos*) shlibext=so ;; bsdi4*) shlibext=so sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" ;; cygwin* | mingw* | pw32*) case $GCC,$host_os in yes,cygwin*) shlibext=dll.a ;; yes,mingw*) shlibext=dll sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` ;; yes,pw32*) shlibext=dll ;; *) shlibext=dll ;; esac ;; darwin* | rhapsody*) shlibext=dylib ;; freebsd1*) ;; freebsd*) shlibext=so ;; gnu*) shlibext=so ;; hpux9* | hpux10* | hpux11*) shlibext=sl ;; irix5* | irix6*) shlibext=so case "$host_os" in irix5*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 ") libsuff= shlibsuff= ;; *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" ;; linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) ;; linux-gnu*) shlibext=so ;; netbsd*) shlibext=so ;; newsos6) shlibext=so ;; openbsd*) shlibext=so ;; os2*) libname_spec='$name' shlibext=dll ;; osf3* | osf4* | osf5*) shlibext=so sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) shlibext=so ;; solaris*) shlibext=so ;; sunos4*) shlibext=so ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) shlibext=so case "$host_vendor" in motorola) sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; uts4*) shlibext=so ;; dgux*) shlibext=so ;; sysv4*MP*) if test -d /usr/nec; then shlibext=so fi ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_sys_lib_search_path_spec=`echo "X$sys_lib_search_path_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_sys_lib_dlsearch_path_spec=`echo "X$sys_lib_dlsearch_path_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' </dev/null 2>&1; then] AC_MSG_ERROR([maximum allowed optimization level is -O2]) fi AC_MSG_RESULT([fine]) # extra paths AC_ARG_WITH([extra_include_path], AC_HELP_STRING([--with-extra-include-path], [use additional include paths]), extra_include_path=$withval) split_includes="`echo $extra_include_path | sed -e 's/:/ /g'`" for incpath in $split_includes ; do CPPFLAGS="-I$incpath $CPPFLAGS" done AC_ARG_WITH([extra_library_path], AC_HELP_STRING([--with-extra-library-path], [use additional library paths (remember to update /etc/ld.so.conf too)]), extra_library_path=$withval) split_libs="`echo $extra_library_path | sed -e 's/:/ /g'`" for libpath in $split_libs ; do LDFLAGS="-L$libpath $LDFLAGS" done # set type of "char" to be "unsigned char" CFLAGS="$CFLAGS -funsigned-char" # developer flags AC_ARG_ENABLE([developer], AC_HELP_STRING([--enable-developer], [Compile with warnings and debugging symbols]), CFLAGS="-Wall -Wno-pointer-sign -g $CFLAGS") # debugging AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debug messages]), want_debug=$enableval, want_debug=no) if test "x-$want_debug" = "x-yes" ; then AC_DEFINE(DEBUG,1,[Define to 1 if you want to get debug output with -D.]) AC_DEFINE(SX_DEBUG,1,[Define to 1 if you want to get SX debug output with -D.]) fi AC_ARG_ENABLE(nad_debug, AC_HELP_STRING([--enable-nad-debug], [enable NAD pointer tracking]), want_nad_debug=$enableval, want_nad_debug=no) if test "x-$want_nad_debug" = "x-yes" ; then AC_DEFINE(NAD_DEBUG,1,[Define to 1 if you want to enable NAD pointer tracking.]) fi AC_ARG_ENABLE(pool_debug, AC_HELP_STRING([--enable-pool-debug], [enable memory pool statistics]), want_pool_debug=$enableval, want_pool_debug=no) if test "x-$want_pool_debug" = "x-yes" ; then AC_DEFINE(POOL_DEBUG,1,[Define to 1 if you want to enable memory pool statistics.]) fi AC_ARG_ENABLE(mio_debug, AC_HELP_STRING([--enable-mio-debug], [enable managed IO debug output]), want_mio_debug=$enableval, want_mio_debug=no) if test "x-$want_mio_debug" = "x-yes" ; then AC_DEFINE(MIO_DEBUG,1,[Define to 1 if you want to enable managed IO debug output.]) fi # Two-step header checking. First check for headers which don't # require any other headers. AC_HEADER_DIRENT AC_HEADER_RESOLV AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_HEADER_TIME AC_CHECK_HEADERS([arpa/inet.h \ arpa/nameser.h \ fcntl.h \ netinet/in.h \ signal.h \ stdarg.h \ stdint.h \ stdlib.h \ string.h \ sys/filio.h \ sys/ioctl.h \ sys/socket.h \ sys/time.h \ sys/timeb.h \ sys/types.h \ sys/stat.h \ sys/utsname.h \ syslog.h \ unistd.h \ windows.h \ winsock2.h \ ]) # Now check for those headers that do, including all the required # headers. AC_CHECK_HEADERS([resolv.h windns.h],,, [#ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_WINSOCK2_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_STRUCT_TIMEZONE AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT8_T # generic system types AC_CREATE_STDINT_H(ac-stdint.h) # Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_REPLACE_FNMATCH AC_FUNC_FORK AC_FUNC_MEMCMP AC_FUNC_MKTIME AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_VPRINTF AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([close \ dup2 \ fcntl \ _findfirst \ gethostname \ getopt \ getpagesize \ getpid \ gettimeofday \ inet_aton \ inet_ntoa \ ioctl \ isascii \ memchr \ memmove \ memset \ mkdir \ _mkdir \ modf \ select \ setenv \ sleep \ Sleep \ socket \ strcasecmp \ strchr \ strdup \ strerror \ stricmp \ strncasecmp \ strndup \ strnicmp \ strstr \ tzset \ uname \ ]) AC_CHECK_FUNC([crypt], ,[AC_CHECK_LIB([crypt], [crypt])]) if test "x$ac_cv_lib_crypt_crypt" = "xyes"; then AC_DEFINE(HAVE_CRYPT, 1, [Define to 1 if you have the crypt() function]) fi AM_CONDITIONAL(HAVE_CRYPT, [test "x$ac_cv_lib_crypt_crypt" = "xyes"]) AC_CHECK_FUNC([connect], ,[AC_CHECK_LIB([socket], [connect])]) AC_CHECK_LIB([ws2_32], [_head_libws2_32_a]) AC_CHECK_FUNC(gethostbyname, ,[AC_CHECK_LIB([resolv], [gethostbyname])]) AC_CHECK_FUNC(gethostbyname, ,[AC_CHECK_LIB([nsl], [gethostbyname])]) if test "x$ac_cv_lib_nsl_gethostbyname" != "xyes" && test "x$ac_cv_func_gethostbyname" != "xyes" ; then AC_CHECK_FUNC([gethostbyname], , [AC_CHECK_LIB([socket], [gethostbyname])]) fi if test "$ac_cv_lib_nsl_gethostbyname" = "$ac_cv_func_gethostbyname" ; then AC_MSG_CHECKING([if we can include libnsl + libsocket]) LIBS="-lnsl -lsocket $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[(void) gethostbyname]])],[my_ac_link_result=yes],[my_ac_link_result=no ]) if test "$my_ac_link_result" = "no" ; then AC_MSG_RESULT([failure]) AC_MSG_ERROR([unable to use gethostbyname()]) else AC_MSG_RESULT([success]) fi fi AC_SEARCH_LIBS(inet_ntop, nsl,[ AC_DEFINE(HAVE_INET_NTOP, 1, [Define to 1 if you have the `inet_ntop' function.])]) dnl ** Check for inet_ntop AC_SEARCH_LIBS(inet_pton, nsl,[ AC_DEFINE(HAVE_INET_PTON, 1, [Define to 1 if you have the `inet_pton' function.])]) # windows has different names for a few basic things if test "x-$ac_cv_func_getpid" != "x-yes" -a "x-$ac_cv_func__getpid" = "x-yes" ; then AC_DEFINE(getpid,_getpid,[Define to a function than can provide getpid(2) functionality.]) fi if test "x-$ac_cv_func_sleep" != "x-yes" -a "x-$ac_cv_func_Sleep" = "x-yes" ; then AC_DEFINE(sleep,Sleep,[Define to a function than can provide sleep(2) functionality.]) fi if test "x-$ac_cv_func_strcasecmp" != "x-yes" -a "x-$ac_cv_func_stricmp" = "x-yes" ; then AC_DEFINE(strcasecmp,stricmp,[Define to a function than can provide strcasecmp(3) functionality.]) fi if test "x-$ac_cv_func_strncasecmp" != "x-yes" -a "x-$ac_cv_func_strnicmp" = "x-yes" ; then AC_DEFINE(strncasecmp,strnicmp,[Define to a function than can provide strncasecmp(3) functionality.]) fi # winsock substitutions if test "x-$ac_cv_func_close" != "x-yes" ; then AC_MSG_CHECKING(for closesocket) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[closesocket(0)]])], [AC_MSG_RESULT(yes) AC_DEFINE(close,closesocket,[Define to a function than can provide close(2) functionality.])], AC_DEFINE(HAVE_CLOSE,1,[Define to 1 if you have the 'close' function.]) AC_MSG_RESULT(no)) fi if test "x-$ac_cv_func_ioctl" != "x-yes" ; then AC_MSG_CHECKING(for ioctlsocket) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ioctlsocket(0,0,0)]])], [AC_MSG_RESULT(yes) AC_DEFINE(ioctl,ioctlsocket,[Define to a function than can provide ioctl(2) functionality.])], AC_DEFINE(HAVE_IOCTL,1,[Define to 1 if you have the 'ioctl' function.]) AC_MSG_RESULT(no)) fi # res_query has been seen in libc, libbind and libresolv if test "x-$ac_cv_header_resolv_h" = "x-yes" ; then AC_CHECK_FUNCS(res_query) if test "x-$ac_cv_func_res_query" = "x-yes" ; then have_res_query=yes else AC_CHECK_LIB(resolv, res_query) if test "x-$ac_cv_lib_resolv_res_query" = "x-yes" ; then have_res_query=yes else AC_CHECK_LIB(bind, res_query) if test "x-$ac_cv_lib_bind_res_query" = "x-yes" ; then have_res_query=yes else dnl some glibcs have res_query as a macro, so work around it AC_MSG_CHECKING([for res_query in -lresolv (alternate version)]) save_libs="$LIBS" LIBS="-lresolv $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[res_query(0,0,0,0,0)]])], [AC_MSG_RESULT(yes) have_res_query=yes], [AC_MSG_RESULT(no) LIBS="$save_libs"]) fi fi fi fi # windows calls it DnsQuery if test "x-$ac_cv_header_windns_h" = "x-yes" ; then AC_MSG_CHECKING([for DnsQuery in -ldnsapi]) save_libs="$LIBS" LIBS="-ldnsapi $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[DnsQuery(0,0,0,0,0,0)]])], [AC_MSG_RESULT(yes) have_dnsquery=yes], [AC_MSG_RESULT(no) LIBS="$save_libs"]) fi if test "x-$have_res_query" = "x-yes" ; then AC_DEFINE(HAVE_RES_QUERY,1,[Define to 1 if you have the 'res_query' function.]) elif test "x-$have_dnsquery" = "x-yes" ; then AC_DEFINE(HAVE_DNSQUERY,1,[Define to 1 if you have the 'DnsQuery' function.]) else AC_MSG_ERROR([no DNS resolver interface (res_query or DnsQuery) found]) fi # syslog if test "x-$ac_cv_header_syslog_h" = "x-yes" ; then AC_CHECK_FUNCS(syslog vsyslog) fi if test "x-$ac_cv_header_windows_h" = "x-yes" ; then AC_MSG_CHECKING(for ReportEvent) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ReportEvent(0,0,0,0,0,0,0,0,0)]])], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_REPORTEVENT,1,[Define to 1 if you have the 'ReportEvent' function.])], AC_MSG_RESULT(no)) fi # snprintf/vsnprintf don't exist everywhere. additionally, we require # them to gracefully accept NULLs, which is non-standard AC_CHECK_FUNCS(snprintf vsnprintf) if test "x-$ac_cv_func_snprintf" = "x-yes" ; then AC_MSG_CHECKING([if snprintf can handle NULL arguments]) AC_RUN_IFELSE([AC_LANG_SOURCE([[#include #include segv() { exit(1); } main() { char b[10]; signal(SIGSEGV,segv); snprintf(b,10,"%s",NULL); exit(0); }]])], AC_MSG_RESULT(yes), [AC_MSG_RESULT(no) AC_DEFINE(HAVE_BROKEN_SNPRINTF,1,[Define to 1 if 'snprintf' cannot handle NULL arguments.])]) fi if test "x-$ac_cv_func_vsnprintf" = "x-yes" ; then AC_MSG_CHECKING([if vsnprintf can handle NULL arguments]) AC_RUN_IFELSE([AC_LANG_SOURCE([[#include #include #include segv() { exit(1); } expand(char *f,...) { va_list ap; char b[10]; va_start(ap,f); vsnprintf(b,10,f,ap); va_end(ap); } main() { char b[10]; signal(SIGSEGV,segv); expand("%s", NULL); exit(0); }]])], AC_MSG_RESULT(yes), [AC_MSG_RESULT(no) AC_DEFINE(HAVE_BROKEN_VSNPRINTF,1,[Define to 1 if 'vsnprintf' cannot handle NULL arguments.])]) fi TYPE_SOCKLEN_T # # Checks for libraries. # Expat AC_CHECK_LIB([expat], [XML_ParserCreate]) if test "x-$ac_cv_lib_expat_XML_ParserCreate" != "x-yes" ; then AC_MSG_ERROR([Expat not found]) fi # libidn >= 0.3.0 AC_CHECK_LIB(idn, stringprep_check_version) if test "x-$ac_cv_lib_idn_stringprep_check_version" = "x-yes" ; then AC_MSG_CHECKING(for Libidn version >= 0.3.0) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return !(stringprep_check_version("0.3.0"))]])], [AC_MSG_RESULT(yes) have_idn=yes], AC_MSG_RESULT(no)) fi if test "x-$have_idn" != "x-yes" ; then AC_MSG_ERROR([Libidn >= 0.3.0 not found]) fi # udns AC_CHECK_LIB(udns, dns_init) if test "x-$ac_cv_lib_udns_dns_init" != "x-yes" ; then AC_MSG_ERROR([UDNS library not found]) fi # GnuSASL AC_CHECK_HEADERS(gsasl.h) if test "x-$ac_cv_header_gsasl_h" = "x-yes" ; then AC_CHECK_LIB(gsasl, gsasl_check_version) fi if test "x-$ac_cv_lib_gsasl_gsasl_check_version" = "x-yes" ; then AC_MSG_CHECKING(for GnuSASL version >= 1.4.0) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return !(gsasl_check_version("1.4.0"))]])], [AC_MSG_RESULT(yes) have_gsasl=yes], AC_MSG_RESULT(no)) fi if test "x-$have_gsasl" != "x-yes" ; then AC_MSG_ERROR([GnuSASL >= 1.4.0 not found]) fi # # optional libs # OpenSSL >= 1.0.1 AC_ARG_ENABLE(ssl, AC_HELP_STRING([--enable-ssl[=DIR]], [enable SSL/TLS support (yes)]), want_ssl=$enableval, want_ssl=yes) if test "x-$want_ssl" != "x-no" ; then if test "x-$want_ssl" != "x-yes" ; then CFLAGS="$CFLAGS -I$enableval/include" CPPFLAGS="$CPPFLAGS -I$enableval/include" LDFLAGS="$LDFLAGS -L$enableval/lib" fi AC_CHECK_HEADERS(openssl/crypto.h) if test "x-$ac_cv_header_openssl_crypto_h" = "x-yes" ; then AC_CHECK_LIB(crypto, CRYPTO_lock) fi if test "x-$ac_cv_lib_crypto_CRYPTO_lock" = "x-yes" ; then AC_CHECK_HEADERS(openssl/ssl.h) fi if test "x-$ac_cv_header_openssl_ssl_h" = "x-yes" ; then AC_CHECK_LIB(ssl, SSL_connect) fi if test "x-$ac_cv_lib_ssl_SSL_connect" = "x-yes" ; then AC_MSG_CHECKING(for OpenSSL version >= 1.0.1) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return !(SSLeay() >= 0x010001000L)]])], [AC_MSG_RESULT(yes) have_openssl=yes], AC_MSG_RESULT(no)) fi if test "x-$have_openssl" != "x-yes" ; then AC_MSG_ERROR([OpenSSL >= 1.0.1 not found]) fi AC_DEFINE(HAVE_SSL,1,[Define to 1 if OpenSSL is available.]) fi AM_CONDITIONAL(HAVE_SSL, [test "x-$have_openssl" = "x-yes"]) dnl Check for & handle argument to --with-zlib. _cppflags=$CPPFLAGS _ldflags=$LDFLAGS AC_ARG_WITH(zlib, AC_HELP_STRING([--with-zlib=DIR],[search for zlib in DIR]) AC_HELP_STRING([--without-zlib],[disable use of zlib]), [OPT_ZLIB="$withval"]) if test "$OPT_ZLIB" = "no" ; then AC_MSG_WARN([zlib disabled]) else if test "$OPT_ZLIB" = "yes" ; then OPT_ZLIB="" fi if test -z "$OPT_ZLIB" ; then dnl check for the lib first without setting any new path, since many dnl people have it in the default path AC_CHECK_LIB(z, inflateEnd, dnl libz found, set the variable [HAVE_LIBZ="1"], dnl if no lib found, try /usr/local [OPT_ZLIB="/usr/local"]) fi dnl Add a nonempty path to the compiler flags if test -n "$OPT_ZLIB"; then CPPFLAGS="$CPPFLAGS -I$OPT_ZLIB/include" LDFLAGS="$LDFLAGS -L$OPT_ZLIB/lib$libsuff" fi AC_CHECK_HEADER(zlib.h, [ dnl zlib.h was found HAVE_ZLIB_H="1" dnl if the lib wasn't found already, try again with the new paths if test "$HAVE_LIBZ" != "1"; then AC_CHECK_LIB(z, gzread, [ dnl the lib was found! HAVE_LIBZ="1" ], [ CPPFLAGS=$_cppflags LDFLAGS=$_ldflags]) fi ], [ dnl zlib.h was not found, restore the flags CPPFLAGS=$_cppflags LDFLAGS=$_ldflags] ) if test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" != "1" then AC_MSG_WARN([configure found only the libz lib, not the header file!]) elif test "$HAVE_LIBZ" != "1" && test "$HAVE_ZLIB_H" = "1" then AC_MSG_WARN([configure found only the libz header file, not the lib!]) elif test "$HAVE_LIBZ" = "1" && test "$HAVE_ZLIB_H" = "1" then dnl both header and lib were found! AC_SUBST(HAVE_LIBZ) AC_DEFINE(HAVE_ZLIB_H, 1, [if you have the zlib.h header file]) AC_DEFINE(HAVE_LIBZ, 1, [if zlib is available]) LIBS="$LIBS -lz" fi fi AM_CONDITIONAL(HAVE_LIBZ, [test "$HAVE_LIBZ" = "1"]) # MySQL AC_ARG_ENABLE([mysql], AC_HELP_STRING([--enable-mysql[=DIR]], [enable MySQL auth/reg/storage support (no)]), [ enable_mysql="$enableval" have_mysql=no MYSQL_PREFIX="$enableval" ], [ enable_mysql=no have_mysql=no ]) if test "x-$enable_mysql" != "x-no" ; then if test "$MYSQL_PREFIX" = "yes" ; then MYSQL_PREFIX=/usr fi AC_PATH_PROG(mysqlconfig,mysql_config,,[$MYSQL_PREFIX/bin:$PATH]) if test [ -z "$mysqlconfig" ] then AC_MSG_ERROR([mysql_config executable not found: MySQL 5.0 or greater is required.]) else AC_MSG_CHECKING(MySQL libraries) MYSQL_LIBS=`${mysqlconfig} --libs` AC_MSG_RESULT("$MYSQL_LIBS") AC_MSG_CHECKING(mysql includes) MYSQL_CFLAGS=`${mysqlconfig} --cflags` AC_MSG_RESULT("$MYSQL_CFLAGS") MYSQL_VERSION=`${mysqlconfig} --version` MYSQL_VERSION_MAJOR=${MYSQL_VERSION%%.*} if test $MYSQL_VERSION_MAJOR -lt 5 ; then AC_MSG_ERROR([MySQL version 5.0 or greater required.]) fi have_mysql=yes AC_DEFINE(STORAGE_MYSQL, 1, [Define to 1 if you want to use MySQL for storage.]) fi fi AC_SUBST(MYSQL_CFLAGS) AC_SUBST(MYSQL_LIBS) AM_CONDITIONAL(STORAGE_MYSQL, [test "x-$have_mysql" = "x-yes"]) # PostgreSQL AC_ARG_ENABLE([pgsql], AC_HELP_STRING([--enable-pgsql[=DIR]], [enable PostgreSQL auth/reg/storage support (no)]), [ enable_pgsql="$enableval" have_pgsql=no PGSQL_PREFIX="$enableval"], [ enable_pgsql=no have_pgsql=no ]) if test "x-$enable_pgsql" != "x-no" ; then if test "$PGSQL_PREFIX" = "yes" ; then PGSQL_PREFIX=/usr fi AC_PATH_PROG(pgconfig,pg_config,,[$PGSQL_PREFIX/bin:$PATH]) if test [ -z "$pgconfig" ] then AC_MSG_ERROR([pg_config executable not found: PostgreSQL 8.0 or greater is required.]) else AC_MSG_CHECKING(PostgresSQL libraries) PGSQL_LIBDIR=`$pgconfig --libdir` PGSQL_LIBS="-L$PGSQL_LIBDIR -lpq" AC_MSG_RESULT("$PGSQL_LIBS") AC_MSG_CHECKING(pgsql includes) PGSQL_INCLUDE=`$pgconfig --includedir` PGSQL_CFLAGS="-I$PGSQL_INCLUDE" AC_MSG_RESULT("$PGSQL_CFLAGS") have_pgsql=yes AC_DEFINE([STORAGE_POSTGRES],[1],[Define to 1 if you want to use PostgreSQL for storage.]) fi fi AC_SUBST(PGSQL_CFLAGS) AC_SUBST(PGSQL_LIBS) AM_CONDITIONAL(STORAGE_PGSQL, [test "x-$have_pgsql" = "x-yes"]) # SQLite 3 AC_ARG_ENABLE([sqlite], AS_HELP_STRING([--enable-sqlite], [enable SQLite3 auth/reg/storage support (no)]), [enable_sqlite=$enableval have_sqlite=no], [enable_sqlite=no have_sqlite=no]) if test "x-$enable_sqlite" = "x-yes" ; then AC_CHECK_HEADERS([sqlite3.h], [ AC_CHECK_LIB([sqlite3], [sqlite3_open], [ have_sqlite=yes SQLITE_LIBS="-lsqlite3" AC_DEFINE(STORAGE_SQLITE, 1, [Define to 1 if you want to use SQLite 3 for storage.]) ]) ]) if test "x-$have_sqlite" != "x-yes" ; then AC_MSG_ERROR([SQLite3 support requested, but headers/libraries not found.]) fi fi AC_SUBST(SQLITE_LIBS) AM_CONDITIONAL(STORAGE_SQLITE, [test "x-$have_sqlite" = "x-yes"]) # Berkeley DB _save_libs="$LIBS" AC_ARG_ENABLE(db, AC_HELP_STRING([--enable-db], [enable Berkeley DB auth/reg/storage support (no)]), want_db=$enableval, want_db=no) if test "x-$want_db" = "x-yes" ; then AC_CHECK_HEADERS(db.h) if test "x-$ac_cv_header_db_h" = "x-yes" ; then for lib in db43 db42 db-4.3 db-4.2 db-4.1 db-4 db4 db41 db ; do if test "xxx$have_db_version" != "xxxyes" ; then AC_MSG_CHECKING([for db_create in -l$lib]) save_libs="$LIBS" LIBS="-l$lib $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[db_create(0,0,0)]])], [AC_MSG_RESULT(yes) AC_MSG_CHECKING(for Berkeley DB version >= 4.1.25) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include ]], [[do { int major, minor, patch; db_version(&major, &minor, &patch); if(major < 4 || (major == 4 && minor < 1) || (major == 4 && minor == 1 && patch < 24) || (int)DB_VERSION_MAJOR != major || (int)DB_VERSION_MINOR != minor) return 1; } while(0)]])], [AC_MSG_RESULT(yes) have_db_version=yes DB_LIBS="-l$lib"], AC_MSG_RESULT(no))], AC_MSG_RESULT(no)) LIBS="$save_libs" fi done fi if test "x-$have_db_version" != "x-yes" ; then AC_MSG_ERROR([Berkeley DB >= 4.1.24 not found]) else AC_DEFINE(STORAGE_DB,1,[Define to 1 if you want to use Berkeley DB for auth/reg/storage.]) fi fi AC_SUBST(DB_LIBS) AM_CONDITIONAL(STORAGE_DB, [test "x-$have_db_version" = "x-yes"]) LIBS="$_save_libs" # Oracle AC_ARG_WITH(oracle-home, AC_HELP_STRING([--with-oracle-home=DIR], [the Oracle home directory, for includes and libs]), [ ac_oracle_home="$withval" ]) AC_ARG_ENABLE(oracle, AC_HELP_STRING([--enable-oracle], [enable Oracle auth/reg/storage support (no)]), want_oracle=$enableval, want_oracle=no) if test "x-$want_oracle" = "x-yes" ; then AC_CHECK_HEADERS(oci.h) if test "x-$ac_cv_header_oci_h" != "x-yes" ; then if test -n $ac_oracle_home ; then AC_MSG_CHECKING([for oci.h in $ac_oracle_home]) save_cppflags="$CPPFLAGS" CPPFLAGS="-I$ac_oracle_home/rdbms/demo -I$ac_oracle_home/rdbms/public $CPPFLAGS" save_libs="$LIBS" LIBS="-L$ac_oracle_home/lib $LIBS" save_ldflags="$LDFLAGS" LDFLAGS="-Wl,-rpath,$ac_oracle_home/lib $LDFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]])], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_OCI_H,,[Define if you have oci.h]) ac_cv_header_oci_h=yes], AC_MSG_RESULT(no)) if test "x-$ac_cv_header_oci_h" != "x-yes" ; then CPPFLAGS="$save_cppflags" LIBS="$save_libs" LDFLAGS="$save_ldflags" fi fi fi if test "x-$ac_cv_header_oci_h" = "x-yes" ; then AC_CHECK_LIB(clntsh, OCIInitialize) fi if test "x-$ac_cv_lib_clntsh_OCIInitialize" != "x-yes" ; then AC_MSG_ERROR([Oracle client libraries not found]) else have_oracle="yes" ORACLE_CPPFLAGS="-I$ac_oracle_home/rdbms/demo -I$ac_oracle_home/rdbms/public" ORACLE_LIBS="-L$ac_oracle_home/lib" ORACLE_LDFLAGS="-Wl,-rpath,$ac_oracle_home/lib" AC_DEFINE(STORAGE_ORACLE,1,[Define to 1 if you want to use Oracle for auth/reg/storage.]) fi fi AC_SUBST(ORACLE_CPPFLAGS) AC_SUBST(ORACLE_LIBS) AC_SUBST(ORACLE_LDFLAGS) AM_CONDITIONAL(STORAGE_ORACLE, [test "x-$have_oracle" = "x-yes"]) # OpenLDAP AC_ARG_ENABLE(ldap, AC_HELP_STRING([--enable-ldap], [enable OpenLDAP auth/reg support (no)]), want_ldap=$enableval, want_ldap=no) if test "x-$want_ldap" = "x-yes" ; then AC_CHECK_HEADERS(lber.h ldap.h) save_libs="$LIBS" if test "x-$ac_cv_header_ldap_h" = "x-yes" -a "x-$ac_cv_header_lber_h" = "x-yes" ; then AC_CHECK_LIB(lber, ber_alloc) AC_CHECK_LIB(ldap, ldap_init) fi if test "x-$ac_cv_lib_lber_ber_alloc" = "x-yes" -a "x-$ac_cv_lib_ldap_ldap_init" = "x-yes" ; then AC_MSG_CHECKING(for OpenLDAP version >= 2.1.0) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[do { LDAPAPIInfo info; info.ldapai_info_version = LDAP_API_INFO_VERSION; ldap_get_option(0, LDAP_OPT_API_INFO, &info); if(info.ldapai_vendor_version != LDAP_VENDOR_VERSION || LDAP_VENDOR_VERSION < 2004) return 1; } while(0)]])], [AC_MSG_RESULT(yes) have_ldap_version=yes], AC_MSG_RESULT(no)) fi LIBS="$save_libs" if test "x-$have_ldap_version" != "x-yes" ; then AC_MSG_ERROR([OpenLDAP client libraries >= 2.1.0 not found]) else LDAP_LIBS="-llber -lldap" AC_DEFINE(STORAGE_LDAP,1,[Define to 1 if you want to use OpenLDAP for auth/reg.]) fi fi AC_SUBST(LDAP_LIBS) AM_CONDITIONAL(STORAGE_LDAP, [test "x-$have_ldap_version" = "x-yes"]) # Plugabble Authentication Modules (PAM) AC_ARG_ENABLE(pam, AC_HELP_STRING([--enable-pam], [enable PAM auth/reg support (no)]), want_pam=$enableval, want_pam=no) if test "x-$want_pam" = "x-yes" ; then AC_CHECK_HEADERS(security/pam_appl.h) if test "x-$ac_cv_header_security_pam_appl_h" = "x-yes" ; then AC_CHECK_LIB(pam, pam_start, [ have_pam="yes" PAM_LIBS="-lpam" AC_DEFINE(STORAGE_PAM,1,[Define to 1 if you want to use PAM for auth/reg.]) ], [AC_MSG_ERROR([PAM application libraries not found])]) fi fi AC_SUBST(PAM_LIBS) AM_CONDITIONAL(STORAGE_PAM, [test "x-$have_pam" = "x-yes"]) # pipe (not really an external package, but does need some checks) AC_ARG_ENABLE(pipe, AC_HELP_STRING([--enable-pipe], [enable pipe auth/reg support (no)]), want_pipe=$enableval, want_pipe=no) if test "x-$want_pipe" = "x-yes" ; then AC_CHECK_HEADERS(sys/wait.h) AC_FUNC_FORK AC_CHECK_FUNCS(pipe wait) if test "x-$ac_cv_header_sys_wait_h" != "x-yes" -o \ "x-$ac_cv_func_fork" != "x-yes" -o \ "x-$ac_cv_func_pipe" != "x-yes" -o \ "x-$ac_cv_func_wait" != "x-yes" ; then AC_MSG_ERROR([Pipe auth/reg requirements (sys/wait.h, fork(), pipe(), wait()) not found]) else have_pipe="yes" AC_DEFINE(STORAGE_PIPE,1,[Define to 1 if you want to use pipes for auth/reg.]) fi fi AM_CONDITIONAL(STORAGE_PIPE, [test "x-$have_pipe" = "x-yes"]) # Anonymous AC_ARG_ENABLE(anon, AC_HELP_STRING([--enable-anon], [enable anonymous auth/reg support (no)]), want_anon=$enableval, want_anon=no) if test "x-$want_anon" = "x-yes" ; then AC_DEFINE(STORAGE_ANON,1,[Define to 1 if you want anonymous auth.]) fi AM_CONDITIONAL(STORAGE_ANON, [test "x-$want_anon" = "x-yes"]) # Filesystem storage AC_ARG_ENABLE(fs, AC_HELP_STRING([--enable-fs], [enable filesystem storage support (no)]), want_fs=$enableval, want_fs=no) if test "x-$want_fs" = "x-yes" ; then AC_DEFINE(STORAGE_FS,1,[Define to 1 if you want to use the filesystem for storage.]) fi AM_CONDITIONAL(STORAGE_FS, [test "x-$want_fs" = "x-yes"]) # WebSocket support AC_ARG_ENABLE(websocket, AC_HELP_STRING([--enable-websocket], [enable WebSocket support on C2S port (no)]), want_websocket=$enableval, want_websocket=no) if test "x-$want_websocket" = "x-yes" ; then AC_CHECK_LIB([http_parser], [http_parser_init]) if test "x-$ac_cv_lib_http_parser_http_parser_init" != "x-yes" ; then AC_MSG_ERROR([http_parser not found]) else AC_DEFINE(USE_WEBSOCKET,1,[Define to 1 if you want to have WebSocket support in C2S.]) fi fi AM_CONDITIONAL(USE_WEBSOCKET, [test "x-$want_websocket" = "x-yes"]) # # IPv6 checks AC_DEFUN([_IP6_INCLUDES],[[ #include "ac-stdint.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif ]]) # these types are sometimes missing AC_CHECK_TYPES([in_port_t, sa_family_t, struct sockaddr_storage, struct sockaddr_in6, struct in6_addr],,, _IP6_INCLUDES) # some glibcs have broken sockaddr_storage members if test "x-$ac_cv_type_struct_sockaddr_storage" = "x-yes" ; then AC_MSG_CHECKING(for broken __ss_family member in struct sockaddr_storage) AC_COMPILE_IFELSE([AC_LANG_PROGRAM(_IP6_INCLUDES, [[do { struct sockaddr_storage s; s.__ss_family = 0; } while(0)]])], [AC_MSG_RESULT(yes) AC_DEFINE(ss_family, __ss_family, [Define to '__ss_family' if 'struct sockaddr_storage' defines '__ss_family' instead of 'ss_family'.])], AC_MSG_RESULT(no)) AC_MSG_CHECKING(for broken __ss_len member in struct sockaddr_storage) AC_COMPILE_IFELSE([AC_LANG_PROGRAM(_IP6_INCLUDES, [[do { struct sockaddr_storage s; s.__ss_len = 0; } while(0)]])], [AC_MSG_RESULT(yes) AC_DEFINE(ss_len, __ss_len, [Define to '__ss_len' if 'struct sockaddr_storage' defines '__ss_len' instead of 'ss_len'.])], AC_MSG_RESULT(no)) fi # # mio backend selection AC_ARG_ENABLE(mio, AC_HELP_STRING([--enable-mio=BACKENDS], [use one of BACKENDS to drive MIO (select poll epoll kqueue)]), mio_check=$enableval, mio_check='kqueue epoll poll select') mio_backend='' for backend in $mio_check ; do case x-$backend in x-kqueue) AC_CHECK_HEADERS(sys/event.h) if test "x-$ac_cv_header_sys_event_h" = "x-yes" ; then AC_CHECK_FUNCS(kqueue,[ mio_backend='kqueue' AC_DEFINE(MIO_KQUEUE,1,[Define to 1 if you want to use 'kqueue' for non-blocking I/O.])]) fi ;; x-epoll) AC_CHECK_HEADERS(sys/epoll.h) if test "x-$ac_cv_header_sys_epoll_h" = "x-yes" ; then AC_CHECK_FUNCS(epoll_create,[ mio_backend='epoll' AC_DEFINE(MIO_EPOLL,1,[Define to 1 if you want to use 'epoll' for non-blocking I/O.])]) fi ;; x-poll) AC_CHECK_HEADERS(poll.h) if test "x-$ac_cv_header_poll_h" = "x-yes" ; then AC_CHECK_FUNCS(poll,[ mio_backend='poll' AC_DEFINE(MIO_POLL,1,[Define to 1 if you want to use 'poll' for non-blocking I/O.])]) fi ;; x-select) AC_CHECK_HEADERS(sys/select.h) if test "x-$ac_cv_header_sys_select_h" = "x-yes" ; then AC_CHECK_FUNCS(select, have_select=yes) fi if test "x-$have_select" != "x-yes" -a "x-$ac_cv_header_winsock2_h" = "x-yes" ; then AC_MSG_CHECKING([for select in ws2_32]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[select(0,0,0,0,0)]])], [AC_MSG_RESULT(yes) have_select=yes], AC_MSG_RESULT(no)) fi if test "x-$have_select" = "x-yes" ; then mio_backend='select' AC_DEFINE(MIO_SELECT,1,[Define to 1 if you want to use 'select' for non-blocking I/O.]) fi ;; esac done if test "x-$mio_backend" = "x-" ; then AC_MSG_ERROR([no MIO backend available out of: $mio_check]) fi # use libc function substitution library? AC_ARG_WITH(subst, AC_HELP_STRING([--without-subst],[disable use of substitution library]), [OPT_LIBSUBST="$withval"]) AC_SUBST(USE_LIBSUBST) AM_CONDITIONAL(USE_LIBSUBST, [test "$OPT_LIBSUBST" != "no"]) # conditional features AC_ARG_ENABLE(superseded, AC_HELP_STRING([--enable-superseded], [enable superseded XEP support (yes)]), want_superseded=$enableval, want_superseded=no) if test "x-$want_superseded" = "x-yes" ; then AC_DEFINE(ENABLE_SUPERSEDED,1,[Define to 1 if you want to compile-in superseded XEP handlers.]) fi AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental], [enable experimental features (yes)]), want_experimental=$enableval, want_experimental=no) if test "x-$want_experimental" = "x-yes" ; then AC_DEFINE(ENABLE_EXPERIMENTAL,1,[Define to 1 if you want to compile-in experimental features.]) fi AM_CONDITIONAL(ENABLE_EXPERIMENTAL, [test "x-$want_experimental" = "x-yes"]) AC_ARG_ENABLE(tests, AC_HELP_STRING([--enable-tests], [enable tests (yes)]), want_tests=$enableval, want_tests=yes) if test "x-$want_tests" = "x-yes" ; then PKG_CHECK_MODULES([CHECK], [check >= 0.9.4], [want_tests=yes], [want_tests=no]) fi AM_CONDITIONAL(ENABLE_TESTS, [test "x-$want_tests" = "x-yes"]) AC_ARG_ENABLE([werror], AC_HELP_STRING([--enable-werror], [Treat all warnings as error]), CFLAGS="-Wall -Werror $CFLAGS") # Generate Makefiles AC_CONFIG_FILES([Doxyfile Makefile etc/Makefile etc/templates/Makefile man/Makefile subst/Makefile util/Makefile mio/Makefile sx/Makefile storage/Makefile c2s/Makefile router/Makefile s2s/Makefile sm/Makefile tools/Makefile tests/Makefile]) AC_OUTPUT jabberd2-jabberd-2.3.4/contrib/000077500000000000000000000000001261462775300162375ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/contrib/README000066400000000000000000000012341261462775300171170ustar00rootroot00000000000000This directory contains patches to the code which you may or may not find useful. They are modifications to the main source which would have had a detrimental affect towards jabberd2's goal of 100% xmpp compliance. Or they simply were not deemed appropriate to add into the main source dist. However, there are situations in which this code may be of use, so the patches are kept here. These patches are not maintained by jabberd2 team and may or may not be out of date. You are have been warned. Good Luck patch-flash-v2 -------------- This modifies c2s in order to allow macromedia's embrace and extend proprietary mark-up language to inter-operate with j2. jabberd2-jabberd-2.3.4/contrib/cyrus-sasl-digest-md5-fix.diff000066400000000000000000000063141261462775300237260ustar00rootroot00000000000000Pulled from CVS, Ident strings removed to let the patch apply pretty cleanly. =================================================================== RCS file: /afs/andrew.cmu.edu/system/cvs/src/sasl/plugins/digestmd5.c,v retrieving revision 1.183 retrieving revision 1.184 diff -u -r1.183 -r1.184 --- src/sasl/plugins/digestmd5.c 2006/11/27 20:41:55 1.183 +++ src/sasl/plugins/digestmd5.c 2007/02/14 17:16:14 1.184 @@ -556,12 +556,17 @@ return SASL_OK; } +static int is_lws_char (char c) +{ + return (c == ' ' || c == HT || c == CR || c == LF); +} + static char *skip_lws (char *s) { if (!s) return NULL; /* skipping spaces: */ - while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) { + while (is_lws_char(s[0])) { if (s[0] == '\0') break; s++; } @@ -750,17 +755,30 @@ static void get_pair(char **in, char **name, char **value) { char *endpair; - /* int inQuotes; */ char *curp = *in; *name = NULL; *value = NULL; if (curp == NULL) return; - if (curp[0] == '\0') return; - - /* skipping spaces: */ - curp = skip_lws(curp); - + + while (curp[0] != '\0') { + /* skipping spaces: */ + curp = skip_lws(curp); + + /* 'LWS "," LWS "," ...' is allowed by the DIGEST-MD5 ABNF */ + if (curp[0] == ',') { + curp++; + } else { + break; + } + } + + if (curp[0] == '\0') { + /* End of the string is not an error */ + *name = ""; + return; + } + *name = curp; curp = skip_token(curp,1); @@ -787,22 +805,24 @@ endpair = unquote (curp); if (endpair == NULL) { /* Unbalanced quotes */ *name = NULL; + *value = NULL; return; } - if (endpair[0] != ',') { - if (endpair[0]!='\0') { - *endpair++ = '\0'; - } + + /* An optional LWS is allowed after the value. Skip it. */ + if (is_lws_char (endpair[0])) { + /* Remove the trailing LWS from the value */ + *endpair++ = '\0'; + endpair = skip_lws(endpair); } - - endpair = skip_lws(endpair); - + /* syntax check: MUST be '\0' or ',' */ if (endpair[0] == ',') { endpair[0] = '\0'; endpair++; /* skipping <,> */ } else if (endpair[0] != '\0') { *name = NULL; + *value = NULL; return; } @@ -2090,9 +2110,17 @@ char *name = NULL, *value = NULL; get_pair(&in, &name, &value); - if (name == NULL) - break; + if (name == NULL) { + SETERROR(sparams->utils, + "Parse error"); + result = SASL_BADAUTH; + goto FreeAllMem; + } + if (*name == '\0') { + break; + } + /* Extracting parameters */ /* @@ -3222,10 +3250,14 @@ /* if parse error */ if (name == NULL) { params->utils->seterror(params->utils->conn, 0, "Parse error"); - result = SASL_FAIL; + result = SASL_BADAUTH; goto FreeAllocatedMem; } + if (*name == '\0') { + break; + } + if (strcasecmp(name, "realm") == 0) { nrealm++; @@ -3887,9 +3919,14 @@ if (name == NULL) { params->utils->seterror(params->utils->conn, 0, "DIGEST-MD5 Received Garbage"); + result = SASL_BADAUTH; break; } + if (*name == '\0') { + break; + } + if (strcasecmp(name, "rspauth") == 0) { if (strcmp(text->response_value, value) != 0) { jabberd2-jabberd-2.3.4/contrib/patch-flash-v2000066400000000000000000000151171261462775300207060ustar00rootroot00000000000000From 8e79a912cf41d41da558aeae44e0389a6f8a2e21 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Tue, 6 Dec 2011 23:31:10 +0100 Subject: [PATCH] Updated flash patch --- c2s/c2s.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c2s/c2s.h | 4 ++ 2 files changed, 134 insertions(+), 0 deletions(-) diff --git a/c2s/c2s.c b/c2s/c2s.c index 5d58407..1fcda9d 100644 --- a/c2s/c2s.c +++ b/c2s/c2s.c @@ -22,6 +22,65 @@ #include "c2s.h" #include +/* + * M.Bootsma, LogicaCMG Hoofddorp, Netherlands + * October 2004 + * + * Added a patch for flash:stream support + * + * Flash is not 100% compatible with the XML stream standard: + * 1. it terminates every XML message with a '\0' + * 2. it terminates the stream header with a / + * (this would close the stream) + * 3. it starts the stream with a flash:stream header instead of + * a stream:stream header. + * + * The patch checks the first message of a starting session stream + * for any '\0'. If found it flags the session as a Flash session + * and replases the complete header with a Jabber compatible + * header. + * After that every incoming message is filtered and '\0' is + * replaced with ' '. + * For every outgoing message, a '\0' is appended and the response + * of the header is replaced for a flash friendly version + * + * The whole flash patch can be switched off by undefining CP2005_FLASH_PATCH + * in config.h(.in) + */ + +#ifdef CP2005_FLASH_PATCH + +#define FLASH_BUFFER_SIZE 256 + +static const char caStreamHeader [] = ""; +static const char caFlashHeader [] = ""; + +static void ExtractValue(char *pMessage, char *pVariable, char *pValue) { + int iLen; + char *p; + char *pEnd; + + /* + * extract the value of an attribute from a XML message + * eg: <.... id='1234567890' ....> returns 1234567890 + */ + + p = strstr(pMessage, pVariable); + if (p != NULL) { + p += (strlen(pVariable) + 1); + /* find end of value, search for closing ' or " */ + pEnd = strchr(p, p [-1]); + iLen = pEnd - p; + if (iLen < FLASH_BUFFER_SIZE) { + memcpy(pValue, p, iLen); + pValue[iLen] = '\0'; + log_debug(ZONE, "++++ Extracted Var %s: [%s]\n", pVariable, pValue); + } + } +} +#endif + + static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { sess_t sess = (sess_t) arg; sx_buf_t buf = (sx_buf_t) data; @@ -31,6 +90,12 @@ static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) char root[9]; bres_t bres, ires; +#ifdef CP2005_FLASH_PATCH + char *p, *pEnd; + char caHost[FLASH_BUFFER_SIZE] = ""; + char caID[FLASH_BUFFER_SIZE]; +#endif + switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); @@ -137,11 +202,76 @@ static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) buf->len = len; +#ifdef CP2005_FLASH_PATCH + /* check for 0 bytes in the first packet + * if found it must be a flash client + * remove any 0 in the data and + * the / that ends the data[len]; + + if (sess->s->state == state_NONE) { + /* stream is new, look for 0 bytes */ + p = memchr(buf->data, '\0', buf->len); + if ((p != NULL) && (p < pEnd)) { + log_debug(ZONE, "++++ Flash Stream detected\n%.*s", buf->len, buf->data); + sess->flash_client = 1; + + /* extract destination host */ + ExtractValue(buf->data, "to=", caHost); + + /* create normal stream:stream header, resize data buffer first */ + _sx_buffer_alloc_margin(buf, 0, sizeof(caStreamHeader) + strlen(caHost) + 8 + 10 /*sw paranoid*/); + snprintf(buf->data, buf->len, caStreamHeader, caHost); + buf->len = strlen(buf->data); + pEnd = &buf->data[buf->len]; + + log_debug(ZONE, "++++ Converted to\n%.*s", buf->len, buf->data); + } + } + + /* Check all other messages in the stream to remove \0's etc */ + if (sess->flash_client) + /* remove 0's from flash packets */ + for (p = buf->data; p < pEnd; p++) + if (*p == '\0') + *p = ' '; +#endif + return len; case event_WRITE: log_debug(ZONE, "writing to %d", sess->fd->fd); +#ifdef CP2005_FLASH_PATCH + if (sess->flash_client) { + /* look for the header data, "len, buf->data); + + /* extract id from id="123456567778765" or id='45454545454' */ + ExtractValue(buf->data, "from=", caHost); + ExtractValue(buf->data, "id=", caID); + + /* create flash:stream header, realloc buffer first */ + _sx_buffer_alloc_margin(buf, 0, sizeof(caFlashHeader) + strlen(caHost) + strlen(caID) + 8); + sprintf(buf->data, caFlashHeader, caHost, caID); + buf->len = strlen(buf->data); + + log_debug(ZONE, "++++ Converted to %s", buf->data); + } else { + // Add some space for the junk we are going to add at the end + _sx_buffer_alloc_margin(buf, 0, 8); + } + + /* add a 0 to flash packets */ + buf->data[buf->len] = '\0'; + buf->len++; + } +#endif + len = send(sess->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); diff --git a/c2s/c2s.h b/c2s/c2s.h index 48c57d9..7b71dab 100644 --- a/c2s/c2s.h +++ b/c2s/c2s.h @@ -104,6 +104,10 @@ struct sess_st { int active; +#ifdef CP2005_FLASH_PATCH + int flash_client; +#endif + /* session related packet waiting for sm response */ nad_t result; -- 1.7.7.3 jabberd2-jabberd-2.3.4/docs/000077500000000000000000000000001261462775300155275ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/docs/dev/000077500000000000000000000000001261462775300163055ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/docs/dev/c2s-authreg000066400000000000000000000011741261462775300203570ustar00rootroot00000000000000Simple authentication (iq:auth) flow: state: STREAM >>> iq:auth get <<< iq:auth result containing auth methods >>> iq:auth set verify credentials start session <<< iq:auth result Registration (iq:register) flow: state: STREAM >>> iq:register get <<< iq:register result containing required fields (username & password) >>> iq:register set create user <<< iq:register Registration remove flow: state: OPEN >>> iq:register set containing remove tag stop session destroy user <<< iq:register result <<< disconnect Password change flow: state: OPEN >>> iq:register set save password <<< iq:register result jabberd2-jabberd-2.3.4/docs/dev/c2s-pipe-authenticator000066400000000000000000000011311261462775300225160ustar00rootroot00000000000000c2s startup pipe init - create socketpair - fork - attach pair to stdio - exec prog Commands return OK or NO, followed by return values Init: [auth process running] <<< OK USER-EXISTS GET-PASSWORD CHECK-PASSWORD SET-PASSWORD CREATE-USER DESTROY-USER FREE >>> USER-EXISTS user [realm] <<< OK <<< NO >>> GET-PASSWORD user [realm] <<< OK encoded_pass <<< NO >>> CHECK-PASSWORD user encoded_pass [realm] <<< OK <<< NO >>> SET-PASSWORD user encoded_pass [realm] <<< OK <<< NO >>> CREATE-USER user [realm] <<< OK <<< NO >>> DELETE-USER user [realm] <<< OK <<< NO >>> FREE [auth process exits] jabberd2-jabberd-2.3.4/docs/dev/component-protocol000066400000000000000000000022001261462775300220630ustar00rootroot00000000000000C == component, R == router. This all happens in state_OPEN (ie after auth). These elements are scoped by the 'http://jabberd.jabberstudio.org/ns/component/1.0' namespace. Joining the network ------------------- Bind a name to this component: C: [options] R: or R: Options: Sets this component as the default route Make this component a log sink (receives copies of all packets) Unbind a name: C: R: Domain advertisement ------------------- Domain online: R: Domain offline: R: Sending packets --------------- Send a unicast packet: C: Send a broadcast packet: C: Throttling packets ------------------ (Un)throttle packets (toggle): C: R: jabberd2-jabberd-2.3.4/docs/dev/programmers-guide.xml000066400000000000000000000715071261462775300224720ustar00rootroot00000000000000
jabberd2 Programmers Guide v0.01 for jabberd 2.0.0 alpha3 2002 Robert Norris This material may be distributed only subject to the terms and conditions set forth in the Open Publications License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). This document describes the various programming interfaces available in the jabberd2 system.
expat - XML parsing library The XML parsing requirements of the jabberd system are handled by the ubiquitous Expat library. Since we need a parser that is namespace aware, v1.95 is the version in use. Expat is widely used and understood, and it doesn't make sense to repeat a long description of the library here. More information can be found on the Expat homepage.
mio - Managed I/O MIO is an event wrapper around UNIX file descriptors. The application can associate a callback function with each file descriptor it is interested in monitoring. When some kind of activity occurs on the file descriptor, the callback is fired. For network-driven applications such as jabberd, this is very useful, as it allows the main loop of the application to be reduced to a simple call into the MIO subsystem.
Data types MIO context - mio_t mio_t is an opaque type that holds all the state information for the file descriptors being handled by the context. It is created by mio_new(), freed by mio_free(), and passed as the first argument to every other MIO function. MIO action (event) - mio_action_t mio_action_t is an enumeration which is passed as the second argument to a callback, to inform the application of which event occured. It can take one of four values: action_ACCEPT - someone has connected to this (listening) file descriptor. action_READ - this file descriptor has data waiting to be read. action_WRITE - this file descriptor is able to be written to. action_CLOSE - this file descriptor has been closed. MIO handler (callback) - mio_handler_t mio_handler_t is a prototype for a callback. A callback function should be of the following type: typedef int (*mio_handler_t)(mio_t m, mio_action_t a, int fd, void *data, void *arg) When called, the arguments passed to the callback are as follows: mio_t m - the MIO context that is managing the file descriptor. mio_action_t a - the action that occured. int fd - the file descriptor that this action occured on. Note that for action_ACCEPT, this argument will be hold the file descriptor of the new connection. void *data - action-specific data. This is currently only used for action_ACCEPT - when this action occurs, data should be casted to char *, where it will contain a string representation of the remote IP address. void *arg - this is the application-specific data that was registered at the same time the callback was registered with mio_fd() or mio_app(). The return type of the callback function is different depending on the action: action_ACCEPT - if the callback returns 0, the newly-accepted file descriptor will be tracked in the MIO context. If it returns non-zero, the connection will be closed. action_READ - if the callback returns 0, no further read events will be fired to the callback until mio_read() is called on this file descriptor. If it returns non-zero, events will continue to be processed. action_WRITE - if the callback returns 0, no further write events will be fired to the callback until mio_write() is called on this file descriptor. If it returns non-zero, events will continue to be processed. action_CLOSE - the return value is ignored for this action.
Creating/freeing a MIO context - mio_new(), mio_free() mio_t mio_new(int maxfd) mio_new() creates a new MIO context. This function takes the following arguments: int maxfd - the highest file descriptor (+1) that can be managed by this MIO context. This function returns the following values: NULL - creation of the MIO context failed for some reason. This is typically caused by a failure to allocate resources. non-NULL - creation of the MIO context succeeded. The returned context is ready for use. void mio_free(mio_t m) mio_free() frees a MIO context. It does not close any file descriptors that are being managed by the MIO context. This function takes the following arguments: mio_t m - pointer to the MIO context to free. This function returns nothing.
Setting the callback for a file descriptor - mio_fd(), mio_app() int mio_fd(mio_t m, int fd, mio_handler_t app, void *arg) mio_fd() instructs MIO to begin tracking the given file descriptor. Note that the file descriptor will be set to non-blocking mode as a result of this call. This function takes the following arguments: mio_t m - the MIO context to associate this file descriptor with. int fd - the file descriptor to track. mio_handler_t app - the callback to invoke when an event occurs. void *arg - application-specific data to be passed to the callback. This function returns the following values: < 0 - the file descriptor number is too large for this MIO context to track. The maximum is set by mio_new(). >= 0 - the file descriptor is being tracked. void mio_app(mio_t m, int fd, mio_handler_t app, void *arg) mio_app() resets the callback on the given file descriptor. This can only be called on a file descriptor that is being tracked by the MIO context. This function takes the following arguments: mio_t m - the MIO context this file descriptor is associated with. int fd - the file descriptor to reset the callback for. mio_handler_t app - the callback to invoke when an event occurs. void *arg - application-specific data to be passed to the callback. This function returns nothing.
Requesting notification about file descriptor events - mio_read(), mio_write() void mio_read(mio_t m, int fd) mio_read() instructs MIO to process read events for the given file descriptor. When such an event occurs, the application callback for the file descriptor will be called with the action_READ event. This function takes the following arguments: mio_t m - the MIO context this file descriptor is associated with. int fd - the file descriptor to process read events for. This function returns nothing. void mio_write(mio_t m, int fd) mio_write() instructs MIO to process write events for the given file descriptor. When such an event occurs, the application callback for the file descriptor will be called with the action_WRITE event. This function takes the following arguments: mio_t m - the MIO context this file descriptor is associated with. int fd - the file descriptor to process write events for. This function returns nothing.
Closing a file descriptor - mio_close() void mio_close(mio_t m, int fd) mio_close() is a wrapper around close() that also stops the file descriptor from being tracked by the MIO context. You should use this in place of close() for a MIO-managed file descriptor. This function takes the following arguments: mio_t m - the MIO context this file descriptor is associated with. int fd - the file descriptor to close. This function returns nothing.
Creating a new file descriptor - mio_connect(), mio_listen() int mio_connect(mio_t m, int port, const char *hostip, mio_handler_t app, void *arg) mio_connect() initiates a connection to the given ip/port. This function returns immediately, and the connect continues in the background (in non-blocking mode). The application should call mio_read() and/or mio_write() after calling mio_connect() in order to receive events after the connection has completed. If the connect fails, the callback will be called with the action_CLOSE event. This function takes the following arguments: mio_t m - the MIO context that will track this connection. int port - the remote port to connect to. char *hostip - string representation of the remote IP address to connect to. mio_handler_t app - the callback to invoke when an event occurs. void *arg - application-specific data to be passed to the callback. This function returns the following values: < 0 - the file descriptor creation or the connect init failed for some reason. errno may have more information. >= 0 - the new file descriptor. int mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg) mio_listen() starts a listening socket on the given ip/port. The callback will be called with the action_ACCEPT action when a new connection is initiated. This function takes the following arguments: mio_t m - the MIO context that will track this socket, and newly-accepted connections. int port - the local port to listen on. char *sourceip - string representation of the local IP address to listen on. mio_handler_t app - the callback to invoke when an event occurs. void *arg - application-specific data to be passed to the callback. This function returns the following values: < 0 - the file descriptor creation or the listen init failed for some reason. errno may have more information. >= 0 - the file descriptor of the listening socket.
Process pending events on file descriptors - mio_run() void mio_run(mio_t m, int timeout) mio_run() processes pending events on file descriptors being tracked by the given MIO context. It will fire the associated callback if anything interesting has happened to a file descriptor. This function takes the following arguments: mio_t m - the MIO context to process. int timeout - Number of seconds to wait for events for. The call will block for at least this long. To do one check, then return (ie non-blocking behaviour), set this to 0. This function returns nothing.
Extending MIO - backends for event-readiness APIs TODO
util - Support utilities jabberd2 provides a variety of special-purpose utility libraries to aid the programmer with common functions. Some of them contain dependencies on other utilities and in one case (config), also a dependency on Expat. These dependencies are noted.
access - IP-based access controls
Data types access context - access_t
Creating/freeing an access context - access_new(), access_free() access_t access_new(int order) void access_free(access_t access)
Adding an access control rule - access_allow(), access_deny() int access_allow(access_t access, const char *ip, const char *mask) int access_deny(access_t access, const char *ip, const char *mask)
Checking whether are not an IP address matches a rule - access_check() int access_check(access_t access, const char *ip)
config - XML config files TODO
jid - Jabber ID manipulation TODO
log - Logging (file/syslog)
Data types log context - log_t
Creating/freeing a log context - log_new(), log_free() log_t log_new(int syslog, const char *ident, int facility) void log_free(log_t log)
Writing data to a log - log_write() log_t log_write(log_t log, int level, const char *msgfmt, ...)
nad - Lightweight XML DOM TODO
pool - Memory pools TODO
rate - Rate controls
Data types rate context - rate_t
Creating/freeing a rate context - rate_new(), rate_free() rate_t rate_new(int total, int seconds, int wait) void rate_free(rate_t rt)
Updated rate counts - rate_add(), rate_reset() void rate_add(rate_t rt, int count) void rate_reset(rate_t rt)
Checking rate limits - rate_check(), rate_left() int rate_check(rate_t rt) int rate_left(rate_t rt)
serial - Data serialisation
Retrieving values from a buffer - ser_string_get(), ser_int_get() int ser_string_get(char **dest, int *source, const char *buf, int len) int ser_int_get(int *dest, int *source, const char *buf, int len)
Adding values to a buffer - ser_string_set(), ser_int_set() void ser_string_set(char *source, int *dest, const char **buf, int *len) void ser_int_set(int source, int *dest, const char **buf, int *len)
sha - SHA1 hash generation
Generating a SHA1 hash - shahash(), shahash_r() char *shahash(char *str) void shahash_r(const char *str, char hashbuf[41]
str - String manipulation
spool - String pools
Data types spool context - spool
Creating a spool context - spool_new() spool spool_new(pool p)
Adding strings to a spool context - spool_add(), spooler() void spool_add(spool s, const char *str) void spooler(spool s, ...)
Getting the contents of a spool context - spool_print() char *spool_print(spool s)
Concatenating strings on the fly - spools() void spools(pool p, ...)
xhash - Hash tables TODO
sx - XML streams abstraction
Data types TODO
Creating/freeing an XML stream - sx_new(), sx_free(), sx_env_new(), sx_env_free() TODO
Beginning and ending an XML stream - sx_client_init(), sx_server_init(), sx_auth(), sx_close() TODO
Using an XML stream TODO. Creating a stream. Connecting it and performing any needed authorizations or negotiations. Writing nads to the stream. Processing nads parsed by the stream. Shutting down a stream. Handling I/O for the stream. Dealing with network or protocol errors.
Providing an <type>sx_callback_t</type> function An XML stream communicates events and data to the rest of the program by invoking the callback function which was given as an argument to sx_new(). The first two arguments of the callback function are the sx_t which is invoking the callback, and an enumerated value (sx_event_t) which indicates the reason the callback was invoked. The interpretation of the third argument (a void *) and the return value (an integer) depends on the value of the event argument. The event_WANT_READ and event_WANT_WRITE events indicate that the xml stream is expecting input from the underlying octet-stream or has data it wishes to write to that stream. The callback should invoke either sx_can_read() or sx_can_write() as appropriate. If the read or write can be performed immediately without blocking, it can be invoked directly from the callback; otherwise, the callback should schedule the function to be called when data (or buffer space) is available. The data argument and the return value are not used for these event types. event_READ and event_WRITE are requests for the callback to perform IO on behalf of the xml stream. The data argument is a pointer to an sx_buf_t. For event_READ, the callback should read into the specified buffer, adjust the buffer's len to indicate the number of bytes read, and return a nonnegative number to indicate success. For event_WRITE, the callback should return the number of bytes written from the buffer. A negative return value indicates that an error (including end-of-file) has occurred and the stream must be shut down. TODO: nonblocking IO and event loops; use of mio_* functions. event_STREAM, event_OPEN, event_CLOSED, event_ERROR: TODO. Being notified of changes in the stream's state. event_PACKET: TODO. Processing a packet received by the stream.
Implementing a stream plugin TODO: What a plugin is for and what it can do. Existing stream plugins. How to create a new stream plugin. Processing sent and received bytes. Processing sent and received nads.
Buffer management functions used with XML streams TODO: sx_buf_t functions and memory management.
Extending the session manager
Storage drivers TODO
Protocol modules TODO
Extending the client-to-server connector
Authenticator modules TODO
Using the pipe authenticator TODO
Internal protocols
Session control protocol TODO
DNS resolution protocol TODO
jabberd2-jabberd-2.3.4/docs/dev/sm-c2s-protocol000066400000000000000000000040071261462775300211740ustar00rootroot00000000000000If any action fails, the component returns it with sm:failed='1' on the session element. We don't use the route type at all anymore, that is reserved for _routing_ errors. This has the nice side effect of allowing us to distinguish between "session ended" and "sm crashed". No bounce must result from a failed action. The namespace URL is "http://jabberd.jabberstudio.org/ns/session/1.0" c2s->sm: start session sm->c2s: session started c2s->sm: end session sm->c2s: session ended c2s->sm: send packet ... sm->c2s: send packet ... c2s->sm: create user sm->c2s: user created c2s->sm: delete user sm->c2s: user deleteed jabberd2-jabberd-2.3.4/docs/dev/sm-presence-logic000066400000000000000000000057461261462775300215600ustar00rootroot00000000000000This is the logic employed by the presence tracker. The business rules are implemented in the SM core (sm/pres.c). The triggers (protocol specifics) are implemented in the Presence module (sm/mod_presence.c). XMPP version (no "invisible" presence) -------------------------------------- There are three sets of JIDs: T: trusted - these may see our presence ("from" or "both" in roster) A: available - these have been sent directed available presence E: error - these bounced presence updates Business rules: B1. Broadcasting available presence: forward to all in T, unless or E B2. Broadcasting unavailable presence: forward to all in T and A, unless in E clear A and E B3. Remote presence probe: respond if in T remove from E B4. Remote presence update: forward to all sessions with priority >= 0 B5. Remote presence error: add to E remove from A B6. Directed available presence: forward add to A (unless in T) remove from E B7. Directed unavailable presence: forward remove from A and E Triggers: T1. T2. T3. T4. or T5. T6. T7. Jabber version (XMPP + "invisible" presence) -------------------------------------------- There are three sets of JIDs: T: trusted - these may see our presence ("from" or "both" in roster) A: available - these have been sent directed available presence E: error - these bounced presence updates There is also an "invisible" flag, I. Business rules: B1. Broadcasting available presence: forward to all in T, unless in E clear I B2. Broadcasting unavailable presence: forward to all in T and A, unless in E clear A and E clear I B3. Broadcasting invisible presence: send unavailable to all in T, unless in A or E set I B4. Remote presence probe: respond if in T and I clear respond if in T and in A and I set remove from E B5. Remote presence update: forward to all sessions with priority >= 0 B6. Remote presence error: add to E remove from A B7. Directed available presence: forward add to A (unless in T) remove from E B8. Directed unavailable presence: forward remove from A and E Triggers: T1. T2. T3. () T4. T5. or T6. T7. T8. jabberd2-jabberd-2.3.4/docs/dev/sm-storage000066400000000000000000000110451261462775300203120ustar00rootroot00000000000000Writing a storage module for jadlsm ----------------------------------- The storage manager presents a hash-style interface to underlying data stores. The hash "key" is represented by two strings - a data type and and arbitrary string (often a JID). Associated with each key is a set of values, each with an index (ie an array). There are five operations that can be performed a particular key: put - appends a data item to the end of the array get - retrieves the data item at the given index zap - deletes the data item at the given index, and shifts all the items to the left of the given index back one, to fill in the hole replace - replaces the data item at the given index with another data item count - counts the number of data items in the array for a given key Storage module code must be stored in a single file called storage_foo.c (where foo is the name of your module), and must export a single function, foo_init, which is of the form: st_ret_t foo_init(st_module_st mod); This function should perform any module-wide initialisation. This might include reading config settings, connecting to a database, etc. The module should fill out the fields of the module structure mod. mod contains seven function pointers which your module to set to point to the implementation of each function. There is also a field called private, which is a void pointer and can be used to store any module-specific data. mod has a field called st, which references the storage manager instance for the session manager. The lsm field of st can be used to get to the session manager instance, and from there, to the config system, the log system, the nad cache, and any other session manager systems. Your module should implement seven functions which are referenced by the pointers in mod. These are: st_ret_t db_add_type(st_module_t mod, char *type) Called to signal to the module that it will be required to manage data of this type. st_ret_t db_put(st_module_t mod, char *key, char *type, char *buf, int buflen) Stores a single data item of this type in the array associated with the key. If the key exists, the item is added to the end of the array. If the key doesn't exist, it is created. st_ret_t db_get(st_module_t mod, char *key, char *type, int num, char **buf, int *buflen) Returns data item #num of this type from the array associated with the key. A buffer should be allocated to hold the returned data, and the buffer and the length returned in buf and buflen. It is the responsibility of the caller to free the returned buffer. st_ret_t db_zap(st_module_t mod, char *key, char *type, int num) Deletes data item #num of this type from the array associated with the key. Items following the deleted key are moved left one space in the array (to fill in the gap); eg: 0 1 2 3 foo bar baz last Deleting item 2 would result in 0 1 2 foo bar last st_ret_t db_replace(st_module_t mod, char *key, char *type, int num, char *buf, int buflen) This is effectively a combination of zap and delete, except that the new data item is added in-place; ie it replaced the specified value without moving any of the other items. st_ret_t db_count(st_module_t mod, char *key, char *type, int *count) Returns the number of items of this type in the array associated with the key. st_ret_t is an enumerated type which is used to flag the result of the function call to the caller. Functions should return one of four values: st_SUCCESS - the call completed successfully st_FAILURE - something went wrong and the call could not complete st_NOTFOUND - the requested storage key does not exist (only for get, zap, replace and count) st_NOTIMPL - the call is not implemented (or, this module can not handle the given type) Once completed, your storage module can be included in the build process by specifying --storage-module=foo at compile time. The type configuration for your module is done in jadlsm.xml. You should add a section for your module in the section. For example, to make your module handle the "message" type, you'd use: message You can also have multiple types for a module: message last Or your module can be set up as the default for all undeclared types: This config file section is a good place to include any configuration that your module requires (eg database location, auth credentials, etc). See storage_db.c for an example implementation. jabberd2-jabberd-2.3.4/docs/dev/sm-storage-types000066400000000000000000000056041261462775300214600ustar00rootroot00000000000000This is a list of the DB collections types that the SM uses, and their fields. type: active user: core fields: time os_type_INTEGER If a user has a stored value for "active" then they "exist" for the purposes of routing and delivery. The value is the time (in seconds since the epoch) that they were first "created". This value is stored in user->active, which is used by mod_offline and mod_roster to determine if it should bother processing messages and subscription requests. type: logout user: mod_iq_last fields: time os_type_INTEGER This stores the time (in seconds since the epoch) of the last session that logged out. This is used to provide an iq:last response when there are no sessions online. type: roster-items user: mod_roster fields: jid os_type_STRING name os_type_STRING to os_type_BOOLEAN from os_type_BOOLEAN ask os_type_BOOLEAN This stores the roster items that make a user's roster. type: roster-groups user: mod_roster fields: jid os_type_STRING group os_type_STRING This stores the groups associated with each of a user's roster items. type: vcard user: mod_iq_vcard fields: fn os_type_STRING nickname os_type_STRING url os_type_STRING tel os_type_STRING email os_type_STRING title os_type_STRING role os_type_STRING bday os_type_STRING desc os_type_STRING n-given os_type_STRING n-family os_type_STRING adr-street os_type_STRING adr-extadd os_type_STRING adr-locality os_type_STRING adr-region os_type_STRING adr-pcode os_type_STRING adr-country os_type_STRING org-orgname os_type_STRING org-orgunit os_type_STRING Stores the various fields the make up the user's vcard. type: queue user: mod_offline fields: xml os_type_NAD This stores messages and s10n requests that are waiting to be delivered to the user. Each DB row contains a single complete packet. type: private user: mod_iq_private fields: ns os_type_STRING xml os_type_NAD This stores user private data (iq:private). ns holds the namespace (for fast lookup), and xml holds the complete packet (actually a copy of the original IQ set that stored the packet). type: motd-messages user: mod_announce fields: xml os_type_NAD This stores the current "message of the day" message. There is only one motd at any one time. type: motd-times user: mod_announce fields: time os_type_INTEGER This stores the time of the last motd message that a user received. It is used to determine whether to send the current motd to the user. jabberd2-jabberd-2.3.4/docs/layout000066400000000000000000000006721261462775300167740ustar00rootroot00000000000000jabber2/ docs/ - Documentation code/ - Doxygen generated dev/ - Hacker docs mio/ - Managed Input/Ouput (FD event processor) sx/ - Streams for XML (Jabber connection / stream library) util/ - Utilities (config, logging, NADs, hashtables, etc) c2s/ - Client-to-server router/ - XML router sm/ - Session manager s2s/ - Server-to-server jabberd2-jabberd-2.3.4/etc/000077500000000000000000000000001261462775300153525ustar00rootroot00000000000000jabberd2-jabberd-2.3.4/etc/Makefile.am000066400000000000000000000033531261462775300174120ustar00rootroot00000000000000LIBTOOL += --quiet sysconf_DATA = c2s.xml.dist router.xml.dist s2s.xml.dist sm.xml.dist jabberd.cfg.dist router-users.xml.dist router-filter.xml.dist initdir = $(prefix)/etc/init init_DATA = jabberd-c2s.conf jabberd-router.conf jabberd-s2s.conf jabberd-sm.conf systemddir = $(prefix)/lib/systemd/system systemd_DATA = jabberd-sm.service jabberd.service jabberd-s2s.service jabberd-router.service jabberd-c2s.service configs = $(sysconf_DATA) $(init_DATA) $(systemd_DATA) EXTRA_DIST = $(sysconf_DATA:%.dist=%.dist.in) $(init_DATA:%.conf=%.conf.in) $(systemd_DATA:%.service=%.service.in) SUBDIRS = templates jabberd_bin = router sm s2s c2s edit = sed \ -e 's,@package\@,$(PACKAGE),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@libdir\@,$(libdir),g' \ -e 's,@pkglibdir\@,$(pkglibdir),g' $(configs): $(sysconf_DATA:%.dist=@srcdir@/%.dist.in) $(init_DATA:%.conf=@srcdir@/%.conf.in) $(systemd_DATA:%.service=%.service.in) @echo "generating $@ from $@.in"; \ edit='$(edit)'; \ list='$(jabberd_bin)'; for p in $$list; do \ bin=`echo "$$p" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ edit="$$edit -e s,@jabberd_$$p\_bin\\@,$$bin,g"; \ done; \ rm -f $@ $@.tmp; \ eval "$$edit < @srcdir@/$@.in > $@.tmp"; \ mv $@.tmp $@ install-data-hook: @list='$(sysconf_DATA)'; for p in $$list; do \ dest=`echo $$p | sed -e s/.dist//`; \ if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ else \ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ fi; \ done clean-local: rm -f $(configs) jabberd2-jabberd-2.3.4/etc/c2s.xml.dist.in000066400000000000000000000614701261462775300201420ustar00rootroot00000000000000 c2s @localstatedir@/@package@/pid/${id}.pid 127.0.0.1 5347 jabberd secret 3 3 2 jabberd/c2s local3 localhost.localdomain 0.0.0.0 5222 1024 0 1000 0 65535 allow,deny 0 0 0 @pkglibdir@ sqlite @localstatedir@/@package@/db/sqlite.db 2000 <!-- use crypt(3)ed passwords <crypt/> --> <!-- use A1HASH passwords This stores the MD5 digest of user:realm:password in the database <a1hash/> --> </password_type> </sqlite> <!-- MySQL module configuration --> <mysql> <!-- Database server host and port --> <host>localhost</host> <port>3306</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> <!-- Passwords in DB may be stored in plain or hashed format --> <!-- NOTE: If you are using hashed passwords, the only auth method that will work is PLAIN. Make sure that you disabled others in 'mechanisms' sections of the config file. --> <password_type> <!-- only one may be enabled here --> <plaintext/> <!-- use crypt(3)ed passwords <crypt/> --> <!-- use A1HASH passwords This stores the MD5 digest of user:realm:password in the database <a1hash/> --> <!-- use bcrypt passwords NOTE: cost has to be higher than 3 and lower than 32 <bcrypt cost='10'/> --> </password_type> </mysql> <!-- PostgreSQL module configuration --> <pgsql> <!-- PostgreSQL connection info. For the rest of the options see http://www.postgresql.org/docs/8.0/interactive/libpq.html --> <conninfo>dbname=jabberd2 user=jabberd2 password=secret</conninfo> <!-- Alternatively you may set connection settings separately. These are used only in absence of 'conninfo' --> <!-- Database server host and port --> <host>localhost</host> <port>5432</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database schema --> <schema>public</schema> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> <!-- Passwords in DB may be stored in plain or hashed format --> <!-- NOTE: If you are using hashed passwords, the only auth method that will work is PLAIN. Make sure that you disabled others in 'mechanisms' sections of the config file. --> <password_type> <!-- only one may be enabled here --> <plaintext/> <!-- use crypt(3)ed passwords <crypt/> --> <!-- use A1HASH passwords This stores the MD5 digest of user:realm:password in the database <a1hash/> --> </password_type> </pgsql> <!-- Oracle driver configuration --> <oracle> <!-- Database server host and port. --> <host>localhost</host> <port>1521</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> </oracle> <!-- Berkeley DB module configuration --> <db> <!-- Directory to store database files under --> <path>@localstatedir@/@package@/db</path> <!-- Synchronize the database to disk after each write. If you disable this, database accesses may be faster, but data may be lost if jabberd crashes. --> <sync/> </db> <!-- LDAPFULL module configuration --> <ldapfull> <!-- LDAP server host and port (default: 389) --> <uri>ldap://localhost/ ldaps://ldap.example.com/</uri> <!-- DN to bind as for searches. If unspecified, the searches will be done anonymously. --> <!-- <binddn>cn=Directory Manager</binddn> <bindpw>secret</bindpw> --> <!-- Type of LDAP server. Currently "ad" for active directory and "ldap" for other ldap servers. If not specified, then it is ldap. --> <!-- <type>ad</type> --> <!-- LDAP attribute that holds the user ID (default: uid) --> <uidattr>uid</uidattr> <objectclass>posixAccount</objectclass> <!-- LDAP attribute that holds the cleartext or hashed password (not needed when pwscheme is set to 'bind') --> <pwattr>userPassword</pwattr> <!-- if you use included jabberd.schema use this: <uidattr>jid</uidattr> <objectclass>jabberUser</objectclass> <pwattr>jabberPassword</pwattr> --> <!-- Attribute that holds jabber account status. Must be TRUE for AD, and 1 for other LDAP server. If not specified, then it will not be used. --> <!-- <validattr>valid</validattr> --> <!-- Group that users must be members of If this is set, only user that are members of the specified LDAP group can log in. The group must be specified with its full distinguished name --> <!-- <group_dn>cn=jabberdusers,ou=servicegroups,dc=example,dc=com</group_dn> --> <fulluid/> <!-- If pwscheme is not defined, then passwords are stored in clear text and digest authentication may be done. If passwords are hashed, then you cannot use digest authentication and should use plain text authentication. Any of sha, ssha, crypt, bind and clear may be specified. 'sha' specifies that the attribute in pwattr holds a base-64 encoded SHA-1 hashed password beginning with the string {SHA}. 'ssha' specifies that the attribute in pwattr holds a base-64 SHA-1 hashed password appended with 32 bits of salt and beginning with the string {SSHA}. 'crypt' specifies that the attribute in pwattr holds a UNIX-style crypt(3) hashed password. 'bind' specifies that the password is not stored in an attribute but is authenticated directly by the LDAP server by binding using the user's DN. This should be compatible with the widest variety of LDAP servers. --> <!-- <pwscheme>bind</pwscheme> --> <!-- base DN of the tree. You should specify a DN for each authentication realm declared in the <local/> section above, by using the realm attribute. --> <basedn realm='company'>o=Company.com</basedn> <basedn>o=Example Corp.</basedn> </ldapfull> <!-- LDAP module configuration --> <!-- Remember that you need to use PLAIN auth with LDAP backend --> <ldap> <!-- LDAP server host and port (default: 389) --> <host>ldap.example.com</host> <port>389</port> <!-- Use LDAP v3 if possible. If disabled, v2 will be used. Encryption options are only available if v3 is enabled. --> <!-- <v3/> --> <!-- Encryption. If enabled, this will create an encrypted channel to the LDAP server using the LDAP STARTTLS mechanism. --> <!-- <starttls/> --> <!-- Encryption. If enabled, this will create an encrypted channel to the server using the old-style "ldaps://" mechanism. It is recommended that you use <starttls/> instead of this. --> <!-- <ssl/> --> <!-- DN to bind as for searches. If unspecified, the searches will be done anonymously. --> <!-- <binddn>cn=Directory Manager</binddn> <bindpw>secret</bindpw> --> <!-- LDAP attribute that holds the user ID (default: uid) --> <uidattr>uid</uidattr> <!-- Enable the append-realm element if you want to append realm value (usernam@realm) to the uidattr value <append-realm/> --> <!-- Alternatively to <uidattr/> and <append-realm/> you may specify full LDAP search <query/> that will be used to get user objects from directory. The following replacements take place: %u is replaced by user login name %r is replaced by user login realm When <query/> is specified, <uidattr/> and <append-realm/> are unused and take no effect. --> <!-- <query>(&amp;(mail=%u@%r)(objectClass=inetOrgPerson))</query> --> <!-- base DN of the tree. You should specify a DN for each authentication realm declared in the <local/> section above, by using the realm attribute. --> <basedn realm='company'>o=Company.com</basedn> <basedn>o=Example Corp.</basedn> </ldap> <!-- if you want to configure more than one LDAP server create ldap1, ldap2 etc. sections <ldap1> </ldap1> --> <!-- Pipe module configuration --> <pipe> <!-- Program to execute --> <exec>@bindir@/pipe-auth.pl</exec> </pipe> </authreg> </c2s> <!-- vim: syntax=xml --> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-c2s.conf.in������������������������������������������������������0000664�0000000�0000000�00000000234�12614627753�0020703�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������description "jabberd Client-2-Server component" start on runlevel [2345] stop on runlevel [!2345] respawn exec sudo -u jabber @bindir@/@jabberd_c2s_bin@ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-c2s.service.in���������������������������������������������������0000664�0000000�0000000�00000000422�12614627753�0021415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Jabber Client To Server Connector Requires=jabberd-router.service After=network.target jabberd-router.service BindTo=jabberd.service [Service] User=jabber ExecStart=@bindir@/@jabberd_c2s_bin@ -c @sysconfdir@/c2s.xml [Install] WantedBy=multi-user.target ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-router.conf.in���������������������������������������������������0000664�0000000�0000000�00000000226�12614627753�0021535�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������description "jabberd Router component" start on runlevel [2345] stop on runlevel [!2345] respawn exec sudo -u jabber @bindir@/@jabberd_router_bin@ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-router.service.in������������������������������������������������0000664�0000000�0000000�00000000345�12614627753�0022252�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Jabber Router XML Packet Distributior After=network.target BindTo=jabberd.service [Service] User=jabber ExecStart=@bindir@/@jabberd_router_bin@ -c @sysconfdir@/router.xml [Install] WantedBy=multi-user.target �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-s2s.conf.in������������������������������������������������������0000664�0000000�0000000�00000000234�12614627753�0020723�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������description "jabberd Server-2-Server component" start on runlevel [2345] stop on runlevel [!2345] respawn exec sudo -u jabber @bindir@/@jabberd_s2s_bin@ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-s2s.service.in���������������������������������������������������0000664�0000000�0000000�00000000422�12614627753�0021435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Jabber Server To Server Connector Requires=jabberd-router.service After=network.target jabberd-router.service BindTo=jabberd.service [Service] User=jabber ExecStart=@bindir@/@jabberd_s2s_bin@ -c @sysconfdir@/s2s.xml [Install] WantedBy=multi-user.target ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-sm.conf.in�������������������������������������������������������0000664�0000000�0000000�00000000233�12614627753�0020632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������description "jabberd Session Manager component" start on runlevel [2345] stop on runlevel [!2345] respawn exec sudo -u jabber @bindir@/@jabberd_sm_bin@ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd-sm.service.in����������������������������������������������������0000664�0000000�0000000�00000000321�12614627753�0021343�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Jabber IM Session Manager After=network.target BindTo=jabberd.service [Service] User=jabber ExecStart=@bindir@/@jabberd_sm_bin@ -c @sysconfdir@/sm.xml [Install] WantedBy=multi-user.target ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd.cfg.dist.in������������������������������������������������������0000664�0000000�0000000�00000001066�12614627753�0020776�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # jabberd config file # # # This file tells the jabberd wrapper what programs to launch, # and the config files to launch them with. If the config file # is left out, then the system default will be used. # # To run multiple Session Managers, just list them all seperatly # and provide the path to the appropriate config files. # # program [ path to config file ] # @jabberd_router_bin@ @sysconfdir@/router.xml @jabberd_sm_bin@ @sysconfdir@/sm.xml @jabberd_s2s_bin@ @sysconfdir@/s2s.xml @jabberd_c2s_bin@ @sysconfdir@/c2s.xml ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/jabberd.service.in�������������������������������������������������������0000664�0000000�0000000�00000000642�12614627753�0020734�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Jabber Server Requires=jabberd-router.service jabberd-sm.service jabberd-c2s.service jabberd-s2s.service After=network.target jabberd-router.service jabberd-sm.service jabberd-c2s.service jabberd-s2s.service BindTo=jabberd-router.service jabberd-sm.service jabberd-c2s.service jabberd-s2s.service [Service] Type=oneshot ExecStart=/bin/true RemainAfterExit=yes [Install] WantedBy=multi-user.target ����������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/router-filter.xml.dist.in������������������������������������������������0000664�0000000�0000000�00000003223�12614627753�0022246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- This is the router filter ruleset. It allows for finegrained routing control. to, from - wildmat patterns absent attribute matches absence of attribute "*" matches any value of attribute what - XPath like query redirect - send packet to given JID instead original recipient error - none given means allow, if given means deny this is an XMPP RFC defined error condition log - if set, the matched packets will be logged in router log Rules are matched in order of apperance. First match is efffective. --> <filter> <!-- first allow any routing without to or from - it's internal. --> <!-- <rule/> <rule from="*"/> <rule to="*"/> --> <!-- create simple alias --> <!-- <rule from="*" to="god@example.org" redirect="admin@example.org"/> --> <!-- don't allow msn registrations, but... --> <!-- <rule from="dearhart@example.org" to="msn.example.org"/> --> <!-- <rule error="not-allowed" from="*" to="msn.example.org" what="iq/query?xmlns=jabber:iq:register" log="yes"/> --> <!-- this user should not talk with evil --> <!-- <rule error="not-allowed" from="user@example.org" to="*@evil.gov" what="message"/> --> <!-- I don't want evil to read my data --> <!-- <rule error="forbidden" from="*@evil.gov" to="admin@example.org" what="iq/vCard" log="on"/> --> <!-- and finally, let's blind the world with some exceptions --> <!-- <rule from="*@goodguys.org" to="*" what="presence"/> <rule from="admin@example.org" to="*" what="presence"/> <rule error="not-acceptable" from="*" to="*" what="presence"/> --> </filter> <!-- vim: syntax=xml --> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/router-users.xml.dist.in�������������������������������������������������0000664�0000000�0000000�00000000402�12614627753�0022116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- This is the list of known router users, and their authentication secrets. Access control is done via the settings in router.xml --> <users> <user> <name>jabberd</name> <secret>secret</secret> </user> </users> <!-- vim: syntax=xml --> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/router.xml.dist.in�������������������������������������������������������0000664�0000000�0000000�00000015634�12614627753�0020774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- Router configuration --> <router> <!-- ID of the router on the network (default: router) --> <id>router</id> <!-- The process ID file. Comment this out if you don't need to know the process ID from outside the process (eg for control scripts) --> <pidfile>@localstatedir@/@package@/pid/${id}.pid</pidfile> <!-- Log configuration - type is "syslog", "file" or "stdout" --> <log type='syslog'> <!-- If logging to syslog, this is the log ident --> <ident>jabberd/router</ident> <!-- If logging to syslog, this is the log facility (local0 - local7) [default: local3] --> <facility>local3</facility> <!-- If logging to file, this is the filename of the logfile --> <!-- <file>@localstatedir@/@package@/log/router.log</file> --> <!-- Filename of the debug logfile --> <!-- <debug>@localstatedir@/@package@/log/debug-${id}.log</debug> --> </log> <!-- Local network configuration --> <local> <!-- IP address to bind to (default: 0.0.0.0) --> <ip>0.0.0.0</ip> <!-- Port to bind to (default: 5347) --> <port>5347</port> <!-- File containing the user table. This is where the router gets its component and secret information from for component authentication.--> <users>@sysconfdir@/router-users.xml</users> <!-- Shared secret used to identify XEP-0114 components (that is, "jabber:component:accept" components that authenticate using the Jabber Component Protocol's "handshake", for example mu-conference). If this is commented out, support for XEP-0114 components will be disabled. --> <secret>secret</secret> <!-- File containing an SSL certificate and private key for client connections. From SSL_CTX_use_certificate_chain_file(3): "The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA" (the latter one being optional). If this is commented out, connecting components will not be able to request an SSL-encrypted channel. --> <!-- <pemfile>@sysconfdir@/server.pem</pemfile> --> </local> <!-- Timed checks --> <check> <!-- Interval between checks. Checks will be run every n seconds. 0 disables all checks. (default: 60) --> <interval>60</interval> <!-- Keepalives. Connections that have not been used for longer than this many seconds will have a single whitespace character sent to them. This will force the TCP connection to be closed if they have disconnected without us knowing about it. 0 disables keepalives. (default: 0) --> <keepalive>0</keepalive> </check> <!-- input/output settings --> <io> <!-- Maximum number of file descriptors. Note that the number of possible connections will be slightly less than this, because the router itself can use up four on its own. If the supply of file descriptors is exhausted, new incoming connections will be denied. These file descriptors are really only used when a component connects to the router. So unless you have a lot of components for some reason then you probably don't need to change this value. (default: 1024) --> <max_fds>1024</max_fds> <!-- Rate limiting --> <limits> <!-- Maximum bytes per second - if more than X bytes are sent in Y seconds, connection is throttled for Z seconds. The format is: <bytes seconds='Y' throttle='Z'>X</bytes> Default Y is 1, default Z is 5. set X to 0 to disable. --> <bytes>0</bytes> <!-- Maximum connects per second - if more than X connects are attempted from a single IP in Y seconds, that IP is throttled for Z seconds. The format is: <connects seconds='Y' throttle='Z'>X</connects> Default Y is 5, default Z is 5. set X to 0 to disable. --> <connects>0</connects> </limits> <!-- IP-based access controls. If a connection IP matches an allow rule, the connection will be accepted. If a connecting IP matches a deny rule, the connection will be refused. If the connecting IP does not match any rules, or it matches both an allow and a deny rule, the contents of the <order/> option determines what happens. --> <access> <!-- Rule check order (default: allow,deny) allow,deny - Check allow rules, then check deny rules. Allow by default. deny,allow - Check deny rules, then check allow rules. Deny by default. --> <order>allow,deny</order> <!-- Allow a network. If the mask isn't specified, it defaults to 255.255.255.255 (ie allow onle the specified IP) --> <!-- <allow ip='127.0.0.0' mask='255.0.0.0'/> --> <!-- Allow a single host --> <!-- <allow ip='12.34.56.78'/> --> <!-- Deny a network or a host --> <!-- <deny ip='127.0.0.1' mask='255.0.0.0'/> <deny ip='87.65.43.21'/> --> </access> </io> <!-- Name aliases. Packets destined for the domain specified in the "name" attribute will be routed to the component that has currently bound the name in the "target" attribute (assuming it is online). This is usually only required for some kinds of legacy components (particularly jabberd 1.4 "uplink" components) --> <aliases> <!-- Example for a MUC component running from a jabberd 1.4 uplink --> <!-- <alias name='conference.domain.com' target='muclinker'/> --> </aliases> <!-- Access control information --> <aci> <!-- The usernames listed here will get access to all restricted functions, regardless of restrictions further down --> <acl type='all'> <user>jabberd</user> </acl> <!-- These users can bind names other than their username --> <!-- <acl type='bind'> </acl> --> <!-- These users can bind a name as a default route --> <!-- <acl type='default-route'> <user>s2s</user> </acl> --> <!-- These users can elect to receive all packets that pass through the router --> <!-- <acl type='log'> <user>msglog</user> </acl> --> <!-- File containing packet filter rules. May be used for fine grained packet routing control. --> <filter>@sysconfdir@/router-filter.xml</filter> </aci> <!-- Simple message logging to flat file Remove <enabled/> tag to disable logging --> <!-- <message_logging> <enabled/> <file>filename</file> </message_logging> --> </router> <!-- vim: syntax=xml --> ����������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/s2s.xml.dist.in����������������������������������������������������������0000664�0000000�0000000�00000027133�12614627753�0020160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- s2s configuration --> <s2s> <!-- Our ID on the network (default: s2s) --> <id>s2s</id> <!-- The process ID file. Comment this out if you don't need to know the process ID from outside the process (eg for control scripts) --> <pidfile>@localstatedir@/@package@/pid/${id}.pid</pidfile> <!-- Router connection configuration --> <router> <!-- IP/port the router is waiting for connections on --> <ip>127.0.0.1</ip> <!-- default: 127.0.0.1 --> <port>5347</port> <!-- default: 5347 --> <!-- Username/password to authenticate as --> <user>jabberd</user> <!-- default: jabberd --> <pass>secret</pass> <!-- default: secret --> <!-- The router will only allow one component to be the default route (ie the component that receives packets destined for unknown hosts). If you want to run more than one s2s instance, you need to uncomment this so that s2s does not try to become the default route. Note that all outgoing s2s communication will go to the component that is the default route. --> <!-- <non-default/> --> <!-- File containing an SSL certificate and private key to use when setting up an encrypted channel with the router. From SSL_CTX_use_certificate_chain_file(3): "The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA" (the latter one being optional). If this is commented out, or the file can't be read, no attempt will be made to establish an encrypted channel with the router. --> <!-- <pemfile>@sysconfdir@/server.pem</pemfile> --> <!-- Router connection retry --> <retry> <!-- If the connection to the router can't be established at startup, we should try again this many times before exiting. Use -1 to retry indefinitely. [default: 3] --> <init>3</init> <!-- If we lost the connection to the router during normal operation (ie we've successfully connected to the router in the past), we should try to reconnect this many times before exiting. Use -1 to retry indefinitely. [default: 3] --> <lost>3</lost> <!-- Sleep for this many seconds before trying attempting a reconnect. [default: 2] --> <sleep>2</sleep> </retry> </router> <!-- Log configuration - type is "syslog", "file" or "stdout" --> <log type='syslog'> <!-- If logging to syslog, this is the log ident --> <ident>jabberd/s2s</ident> <!-- If logging to syslog, this is the log facility (local0 - local7) [default: local3] --> <facility>local3</facility> <!-- if logging to file, this is the filename of the logfile --> <!-- <file>@localstatedir@/@package@/log/s2s.log</file> --> <!-- Filename of the debug logfile --> <!-- <debug>@localstatedir@/@package@/log/debug-${id}.log</debug> --> </log> <!-- Local network configuration --> <local> <!-- IP and port to listen for incoming s2s connections on (default: 0.0.0.0, 5269) --> <ip>0.0.0.0</ip> <port>5269</port> <!-- Multihomed machines (with more than one interface and IP address) need to specify outgoing S2S connections interface/address. If not set, the <ip> section address above is used. --> <!-- <origins> <ip>1.2.3.4</ip> <ip>fe80::202:b3ff:fe1e:8329</ip> </origins> --> <!-- Secret used to generate dialback keys. If you have more than one s2s instance configured, make sure that this is the same on all of them. If this is commented out, a random one will be generated. --> <!-- <secret>secret</secret> --> <!-- File containing an SSL certificate and private key to use when setting up encrypted s2s connections with other servers (STARTTLS + Dialback). From SSL_CTX_use_certificate_chain_file(3): "The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA" (the latter one being optional). If this is commented out, or the file can't be read, no attempt will be made to establish encrypted connections with other servers. --> <!-- <pemfile>@sysconfdir@/server.pem</pemfile> --> <!-- SSL verify mode - see SSL_CTX_set_verify(3), mode parameter --> <!-- <verify-mode>7</verify-mode> --> <!-- List of available TLS ciphers --> <!-- <ciphers>DEFAULT</ciphers> --> <!-- File containing an optional SSL certificate chain file for SSL connections. --> <!-- <cachain>@sysconfdir@/cachain.pem</cachain> --> </local> <!-- input/output settings --> <io> <!-- Maximum number of file descriptors. Note that the number of possible connections will be slightly less than this, because s2s itself can use some on its own. If the supply of file descriptors is exhausted, new incoming connections will be denied. These connections are mainly consumed when we make a connection to an external jabber server, or an external jabber server connects to us. If you don't have a lot of users then there's probably no need for s2s to establish connections to external jabber servers and the default value here is probably fine. On the other hand, if you have lots of users with lots of remote buddies in their buddylist then s2s will need to have lots of open connections with other jabber servers and you may need to increase this value. Note that this value only affects how many file descriptors jabberd is able to handle internally. You may also need to tell your operating system to allow jabberd to use more file descriptors. On Linux this can be done using ulimit -n or by changing the value of /proc/sys/fd/file-max. (default: 1024) --> <max_fds>1024</max_fds> <!-- Rate limiting --> <limits> <!-- Maximum stanza size - if more than given number of bytes are read in one incoming stanza, the stream is closed with policy-violation error. Set to 0 to disable. Values less than 16384 might not work. --> <stanzasize>65535</stanzasize> </limits> <!-- Enable XEP-0138: Stream Compression --> <!-- <compression/> --> </io> <!-- Timed checks --> <check> <!-- Interval between checks. Checks will be run every n seconds. 0 disables all checks except DNS expiry. (default: 60) --> <interval>60</interval> <!-- Queue expiry and connection timeout. While a connection is being established and dialback is in progress, packets are queued. If a valid connection has not been established within this many seconds, the connection process will be aborted and the queued packets will be bounced. Timeout checks are made for three phases of setting up a route authenticated through dialback: 1. Connection establishment to exchange of stream headers 2. Initiating dialback (incoming connections) 3. Completing dialback (incoming and outgoing) If stage 1 connection establishment fails and there are alternative hosts for this route that have not failed recently, they will be tried too before finally giving up. 0 disables queue expiry. (default: 60) --> <queue>60</queue> <!-- Queue retry timeout. If the queue is older than this timeout, the connection will not be retried even if there are alternative hosts that have not failed recently. 0 disables retry expiry. (default: 300) --> <retry>300</retry> <!-- Idle connection checks. Connections that have not sent data for longer than this many seconds will be dropped. 0 disables idle timeouts. (default: 86400) --> <idle>86400</idle> <!-- Keepalives. Outgoing connections that have not been used for longer than this many seconds will have a single whitespace character sent to them. This will force the TCP connection to be closed if they have disconnected without us knowing about it. 0 disables keepalives. (default: 0) --> <keepalive>0</keepalive> <!-- Interval between DNS result/bad host expiry. 0 disables expiry checks. (default: 300) --> <dnscache>300</dnscache> </check> <!-- Statistics --> <stats> <!-- file containing count of packets that went through --> <!-- <packet>@localstatedir@/@package@/stats/s2s.packets</packet> --> </stats> <lookup> <!-- SRV TCP services will be resolved in the following order. The first one that returns something will be used (ie dereferenced via an A/AAAA lookup). If no SRV records are found, resolver will fallback to a straight A/AAAA lookup. --> <!-- xmpp-server is mandated by the XMPP spec --> <srv>xmpp-server</srv> <!-- traditionally, jabber has been used --> <srv>jabber</srv> <!-- If this is enabled, the resolver will look up AAAA records as well as A records. This is needed if you want s2s to use IPv6. Connection attempts will be made to all IPv6 hosts before trying IPv4 (see bad host timeout below). --> <!-- <resolve-ipv6/> --> <!-- Minimum time that DNS lookup results are cached (overrides max below). --> <min-ttl>30</min-ttl> <!-- Maximum time that DNS lookup results are cached. --> <max-ttl>86400</max-ttl> <!-- Time /etc/hosts lookup results are cached for (default: 86400). --> <etc-hosts-ttl>86400</etc-hosts-ttl> <!-- Minimum time to wait before using hosts that we have failed to establish a connection to (unless there are no alternatives). Do not set this too low - it is required to detect permanent problems like broken IPv6 connectivity in order to attempt IPv4. 0 disables bad host caching. (default: 3600) --> <bad-host-timeout>3600</bad-host-timeout> <!-- Disable the DNS cache (negative caching will still be done). This is likely to negatively impact performance while saving a small amount of memory since multiple DNS requests must then be made for every re-connection. --> <!-- <no-cache/> --> </lookup> <!-- If this is enabled, domains which share the same host will re-use existing outgoing connections. This is a potential security risk as the SSL connection from the first domain will be re-used too. --> <out-conn-reuse/> <security> <!-- Require TLS secured S2S connections --> <!-- <require_tls/> --> <!-- Domain whitelisting --> <!-- <enable_whitelist/> --> <!-- Domain whitelisting When defined, only whitelisted domains are allowed to connect --> <!-- <whitelist_domain>domain1.tld</whitelist_domain> <whitelist_domain>domain2.tld</whitelist_domain> <whitelist_domain>other.tld</whitelist_domain> --> </security> </s2s> <!-- vim: syntax=xml --> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/sm.xml.dist.in�����������������������������������������������������������0000664�0000000�0000000�00000074641�12614627753�0020076�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- Session manager configuration --> <sm> <!-- Our ID on the network (default: sm) --> <id>sm</id> <!-- The process ID file. Comment this out if you don't need to know the process ID from outside the process (eg for control scripts) --> <pidfile>@localstatedir@/@package@/pid/${id}.pid</pidfile> <!-- Router connection configuration --> <router> <!-- IP/port the router is waiting for connections on --> <ip>127.0.0.1</ip> <!-- default: 127.0.0.1 --> <port>5347</port> <!-- default: 5347 --> <!-- Username/password to authenticate as --> <user>jabberd</user> <!-- default: jabberd --> <pass>secret</pass> <!-- default: secret --> <!-- File containing an SSL certificate and private key to use when setting up an encrypted channel with the router. From SSL_CTX_use_certificate_chain_file(3): "The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA" (the latter one being optional). If this is commented out, or the file can't be read, no attempt will be made to establish an encrypted channel with the router. --> <!-- <pemfile>@sysconfdir@/server.pem</pemfile> --> <!-- Router connection retry --> <retry> <!-- If the connection to the router can't be established at startup, we should try again this many times before exiting. Use -1 to retry indefinitely. [default: 3] --> <init>3</init> <!-- If we lost the connection to the router during normal operation (ie we've successfully connected to the router in the past), we should try to reconnect this many times before exiting. Use -1 to retry indefinitely. [default: 3] --> <lost>3</lost> <!-- Sleep for this many seconds before trying attempting a reconnect. [default: 2] --> <sleep>2</sleep> </retry> </router> <!-- Log configuration - type is "syslog", "file" or "stdout" --> <log type='syslog'> <!-- If logging to syslog, this is the log ident --> <ident>jabberd/sm</ident> <!-- If logging to syslog, this is the log facility (local0 - local7) [default: local3] --> <facility>local3</facility> <!-- If logging to file, this is the filename of the logfile --> <!-- <file>@localstatedir@/@package@/log/sm.log</file> --> <!-- Filename of the debug logfile --> <!-- <debug>@localstatedir@/@package@/log/debug-${id}.log</debug> --> </log> <!-- Local network configuration --> <local> <!-- Who we identify ourselves as. Users will have this as the domain part of their JID. If you want your server to be accessible from other Jabber servers, this IDs must be FQDN resolvable by DNSes. If not set, the SM id is used. --> <id>localhost.localdomain</id> <!-- <id>vhost1.localdomain</id> <id>vhost2.localdomain</id> --> </local> <!-- Storage database configuration --> <storage> <!-- Dynamic storage modules path --> <path>@pkglibdir@</path> <!-- By default, we use the SQLite driver for all storage --> <driver>sqlite</driver> <!-- Its also possible to explicitly list alternate drivers for specific data types. --> <!-- Store vcards in a ldapvcard database instead --> <!-- <driver type='vcard'>ldapvcard</driver> --> <!-- Only ldapvcard driver implements published-roster: --> <!-- <driver type='published-roster'>ldapvcard</driver> --> <!-- Use ldapvcard driver for published-roster-groups. See description in section sm/user/template/mapped-groups. Used by mod_published_roster. See ldapvcard section for options. When resolving group id to group name, it searches for groupsobjectclass objects at groupsdn base using group id (in groupsidattr) as key and returns the first value of groupattr of first found entry. E.g.. in general case, if group id is "some-dep", and groupsdn is o=org, and class is jabberGroup, it searches for (&(objectClass=jabberGroup)(cn=some-dep)) and returns value of jabberPublishedItem attribute, which may contain textual description. --> <!-- <driver type='published-roster-groups'>ldapvcard</driver> --> <!-- Rate limiting --> <limits> <!-- Maximum queries per second - if more than X queries are sent in Y seconds, connection is throttled for Z seconds. The format is: <queries seconds='Y' throttle='Z'>X</bytes> Default Y is 5, default Z is 60. set X to 0 to disable. --> <!-- <queries>3</queries> --> </limits> <!-- SQLite driver configuration --> <sqlite> <!-- Database name --> <dbname>@localstatedir@/@package@/db/sqlite.db</dbname> <!-- Transaction support. If this is commented out, transactions will be disabled. This might make database accesses faster, but data may be lost if jabberd crashes. --> <transactions/> <!-- SQLite busy-timeout in milliseconds. --> <busy-timeout>2000</busy-timeout> </sqlite> <!-- MySQL driver configuration --> <mysql> <!-- Database server host and port --> <host>localhost</host> <port>3306</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> <!-- Transaction support. If this is commented out, transactions will be disabled. This might make database accesses faster, but data may be lost if jabberd crashes. This will need to be disabled if you are using a MySQL earlier than v3.23.xx, as transaction support did not appear until this version. --> <transactions/> </mysql> <!-- PostgreSQL driver configuration --> <pgsql> <!-- PostgreSQL connection info. For the rest of the options see http://www.postgresql.org/docs/8.0/interactive/libpq.html --> <conninfo>dbname=jabberd2 user=jabberd2 password=secret</conninfo> <!-- Alternatively you may set connection settings separately. These are used only in absence of 'conninfo' --> <!-- Database server host and port --> <host>localhost</host> <port>5432</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database schema --> <schema>public</schema> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> <!-- Transaction support. If this is commented out, transactions will be disabled. This might make database accesses faster, but data may be lost if jabberd crashes. --> <transactions/> </pgsql> <!-- Berkeley DB driver configuration. This does not support roster maxitems or offline userquota (because the mod_roster implementation does not implement the 'count' callback). --> <db> <!-- Directory to store database files under --> <path>@localstatedir@/@package@/db</path> <!-- Synchronize the database to disk after each write. If you disable this, database accesses may be faster, but data may be lost if jabberd crashes. --> <sync/> </db> <!-- Oracle driver configuration --> <oracle> <!-- Database server host and port. --> <host>localhost</host> <port>1521</port> <!-- Database name --> <dbname>jabberd2</dbname> <!-- Database username and password --> <user>jabberd2</user> <pass>secret</pass> </oracle> <!-- Filesystem driver configuration --> <fs> <!-- Directory to store database files under. --> <path>@localstatedir@/lib/jabberd2/fs</path> </fs> <!-- LDAPVCARD driver configuration --> <ldapvcard> <!-- LDAP server host and port (default: 389) --> <uri>ldap://localhost/ ldaps://ldap.example.com/</uri> <!-- DN to bind as for searches. If unspecified, the searches will be done anonymously. --> <!-- <binddn>cn=Directory Manager</binddn> <bindpw>secret</bindpw> --> <!-- see authreg.ldapfull in c2s.xml for description. --> <!-- <type>ad</type> --> <!-- LDAP attribute that holds the user ID (default: uid) --> <uidattr>uid</uidattr> <objectclass>posixAccount</objectclass> <pwattr>userPassword</pwattr> <!-- if you use included jabberd.schema use this: <uidattr>jid</uidattr> <objectclass>jabberUser</objectclass> <pwattr>jabberPassword</pwattr> --> <!-- Realm to append to uidattr. --> <!-- <realm>example.org</realm> --> <!-- see authreg.ldapfull in c2s.xml for description. --> <!-- <validattr>valid</validattr> --> <!-- base DN of the tree. You should specify a DN for each authentication realm declared in the <local/> section above, by using the realm attribute. --> <basedn>o=Example Corp.</basedn> <!-- attribute that holds published group name or id, jabberPublishedGroup if not set --> <!-- <groupattr>jabberPublishedGroup</groupattr> --> <!-- this option is helpful if your schema does not have designated attribute that holds jabber group name you can use any attribute in <groupattr> i.e. 'distinguishedName' and then extract a part of it using Regular Expression; first matching () group will be used --> <!-- <groupattr_regex>OU=([^,]*),</groupattr_regex> --> <!-- boolean attribute that tells whether or not to publish this user jabberPublishedItem by default --> <!-- <publishedattr>jabberPublishedItem</publishedattr> --> <!-- If value specified, then keep cache of "published-roster" database, which is used for all users. Cache is renewed when kept more seconds than value specified. Setting this value increases perfomance of publishing roster. If not specified, then we don't keep cache. --> <publishedcachettl>60</publishedcachettl> <mapped-groups> <!-- If turned on, then mapping of group ids to names with LDAP will works. --> <!-- <map-groups/> --> <!-- base for searches for group id to group name mappings --> <basedn>ou=jabbergroups, o=Example Corp.</basedn> <!-- what objectclass to search, jabberGroup by default --> <!-- <objectclass>jabberGroup</objectclass> --> <!-- what attribute to search, cn by default --> <!-- <idattr>cn</idattr> --> <!-- attribute with text group name, description by default --> <!-- <nameattr>description</nameattr> --> </mapped-groups> </ldapvcard> </storage> <!-- Access control information --> <aci> <!-- The JIDs listed here will get access to all restricted functions, regardless of restrictions further down --> <acl type='all'> <jid>admin@localhost.localdomain</jid> </acl> <!-- These JIDs can send broadcast messages (announce, motd) --> <!-- <acl type='broadcast'> <jid>nocstaff1@localhost.localdomain</jid> <jid>nocstaff2@localhost.localdomain</jid> </acl> --> <!-- These JIDs will receive messages addressed to the sm itself (help requestes and such) --> <!-- <acl type='messages'> <jid>support@localhost.localdomain</jid> </acl> --> <!-- These JIDs can discover active user/session information --> <!-- <acl type='disco'> <jid>webstatus@localhost.localdomain</jid> </acl> --> </aci> <!-- Module chain configuration Modules listed in a chain are called in the order specified at the appropriate time for that chain (assuming that the module knows how to work with that chain; otherwise it simply ignores it). Removing a module from these lists will stop the module being called, even if it's compiled into the server. Serveral modules have a presence in more than one chain. It is possible to remove a module from one chain but not others, but this may cause strange behaviour. Make sure you know what you're doing. When configuring sm for ANONYMOUS access, remove all instances of the following modules: active announce amp offline privacy roster template-roster roster-publish pep vacation status iq-last iq-private iq-vcard and do not enable auto-create option. --> <modules> <!-- Dynamic sm modules path --> <path>@pkglibdir@</path> <!-- sess-start. The modules in this chain are called when a session is first started (usually on request by c2s as part of the authentication process). This is normally used to load per-session data. --> <chain id='sess-start'> <module>status</module> <!-- record status information --> </chain> <!-- sess-end. The modules in this chain are called just before a session is destroyed (after the client has disconnected). --> <chain id='sess-end'> <module>status</module> <!-- update status information --> <module>iq-last</module> <!-- update logout time --> </chain> <!-- in-sess. The modules in this chain are called when a packet arrives from an active user session. Note that this chain is also responsible for delivering packets to their destinations - this is usually handled by the "deliver" module. --> <chain id='in-sess'> <module>validate</module> <!-- validate packet type --> <module>status</module> <!-- update status information --> <module>privacy</module> <!-- manage privacy lists --> <module>roster</module> <!-- handle roster get/sets and s10ns --> <module>vacation</module> <!-- manage vacation settings --> <!-- <module>pep</module> <!- - personal eventing --> <module>iq-vcard</module> <!-- store and retrieve the user's vcard --> <module>iq-ping</module> <!-- return the server ping --> <module>iq-private</module> <!-- manage the user's private data store --> <module>disco</module> <!-- respond to agents requests from sessions --> <module>amp</module> <!-- advanced message processing --> <module>offline</module> <!-- if we're coming online for the first time, deliver queued messages --> <module>announce</module> <!-- deliver motd --> <module>presence</module> <!-- process and distribute presence updates --> <module>deliver</module> <!-- deliver packets with full jids directly --> </chain> <!-- out-sess. The modules in this chain are called just before a packet is delivered to an active user session. --> <chain id='out-sess'> <!-- <module>pep</module> <!- - personal eventing --> </chain> <!-- in-router. The modules in this chain are called when a packet arrives from the router (ie another component or s2s), but before any processing is done. This is a good place to filter incoming packets. --> <chain id='in-router'> <module>session</module> <!-- perform session actions as required by c2s --> <module>validate</module> <!-- validate packet type --> <module>presence</module> <!-- drop incoming presence if user not online --> <module>privacy</module> <!-- filter incoming packets based on privacy rules --> </chain> <!-- out-router. The modules in this chain are called just before a packet is delivered to the router (destined for another component or s2s). This is a good place to filter outgoing packets. --> <chain id='out-router'> <module>privacy</module> <!-- filter outgoing packets based on privacy rules --> </chain> <!-- pkt-sm. The modules in this chain are called when a packet arrives that is addressed to the session manager itself (ie the to JID has no node part). This is normally used to provide session-manager-wide services (like service discovery). --> <chain id='pkt-sm'> <module>iq-last</module> <!-- return the server uptime --> <module>iq-ping</module> <!-- return the server ping --> <module>iq-time</module> <!-- return the current server time --> <module>iq-version</module> <!-- return the server name and version --> <module>amp</module> <!-- advanced message processing --> <module>disco</module> <!-- build the disco list; respond to disco queries --> <module>announce</module> <!-- send broadcast messages (announce, motd, etc) --> <module>help</module> <!-- resend sm messages to administrators --> <module>echo</module> <!-- echo messages sent to /echo --> <module>status</module> <!-- track status information --> <module>presence</module> <!-- proces server presence subscriptions --> </chain> <!-- pkt-user. The modules in this chain are called when a packet arrives that is address to a specific user. Note that this chain is also responsible for delivering packets to user sessions as appropriate - this is usually handled by the "deliver" module. --> <chain id='pkt-user'> <module>roster</module> <!-- handle s10n responses --> <module>presence</module> <!-- process and distribute incoming presence from external entities --> <module>disco</module> <!-- respond to disco queries --> <module>iq-vcard</module> <!-- grab user vcards --> <module>amp</module> <!-- advanced message processing --> <module>deliver</module> <!-- deliver the packet to an active session if we can --> <module>vacation</module> <!-- send vacation messages --> <module>offline</module> <!-- save messages and s10ns for later --> <module>iq-last</module> <!-- return time since last logout --> </chain> <!-- pkt-router. The modules in this chain are called when a special-purpose packet arrives from the router (eg domain advertisements). --> <chain id='pkt-router'> <module>session</module> <!-- take sessions offline if their c2s disappears --> <module>disco</module> <!-- query new components for service information --> </chain> <!-- user-load. The modules in this chain are called to load per-user data. This will happen before a user can be used (ie before a session is created). --> <chain id='user-load'> <module>active</module> <!-- get active status --> <module>roster</module> <!-- load the roster and trust list --> <module>roster-publish</module> <!-- load the published roster --> <module>privacy</module> <!-- load privacy lists --> <module>vacation</module> <!-- load vacation settings --> </chain> <!-- user-unload. The modules in this chain are called right after last per-user session is destroyed. --> <chain id='user-unload'> </chain> <!-- user-create. The modules in this chain are called when a user creation request is received (usually from c2s as part of a registration request). This initialises any per-user data. --> <chain id='user-create'> <module>active</module> <!-- activate new users --> <module>template-roster</module> <!-- populate roster from template --> </chain> <!-- user-delete. The modules in this chain are called when a user deletion request is received (usually from c2s as part of a registration removal request). This deletes all data that may have been previously created for the user during normal operation. --> <chain id='user-delete'> <module>active</module> <!-- deactivate users --> <module>announce</module> <!-- delete motd data --> <module>offline</module> <!-- bounce queued messages --> <module>privacy</module> <!-- delete privacy lists --> <module>roster</module> <!-- delete roster --> <module>vacation</module> <!-- delete vacation settings --> <module>status</module> <!-- delete status information --> <module>iq-last</module> <!-- delete last logout time --> <module>iq-private</module> <!-- delete private data --> <module>iq-vcard</module> <!-- delete vcard --> </chain> <!-- disco-extend. The modules in this chain are called when a disco info request is send to session manager. It implements XEP-0128 Service Discovery Extensions mechanizm to add additional information to disco#info reply. --> <chain id='disco-extend'> <module>iq-version</module> <!-- add XEP-xxxx Software Information --> <module>help</module> <!-- add XEP-0157 Contact Addresses --> </chain> </modules> <!-- Service discovery configuration --> <discovery> <!-- Service identity. these specify the category, type and name of this service that will be included in discovery information responses. --> <identity> <category>server</category> <!-- default: server --> <type>im</type> <!-- default: im --> <name>Jabber IM server</name> <!-- default: Jabber IM server --> </identity> <!-- The discovery module can respond to jabber:iq:agents queries for compatibility with older clients. Comment this out to disable this. --> <agents/> <!-- Static service list. The discover module can discover disco-capable services automatically as they come online. Most XEP-0114 components, however, will not support discovery. In order to get them to appear in disco/agents lists returned to the client, they should be listed here. Note that if a disco-capable service with the same name as one listed below comes online, the information it provides will override the information listed below. The "category" and "type" attributes, and the list of supported namespaces are only used for agents compatibility. If you have disabled this above, you may omit them. --> <items> <!-- example entry for a user directory --> <!-- <item category='service' type='jud' jid='users.jabber.org' name='Jabber User Directory'/> --> <!-- example entry for a groupchat (conference) service --> <!-- <item category='conference' type='public' jid='conference.jabber.org' name='Text conferencing'/> --> </items> <!-- Server information added to server discovery information in http://jabber.org/network/serverinfo jabber:x:data form. (XEP-0157) May contain many values per item --> <!-- <serverinfo> <admin-addresses> <value>mailto:xmpp@localhost.localdomain</value> <value>xmpp:admins@localhost.localdomain</value> </admin-addresses> <abuse-addresses> <value>mailto:abuse@localhost.localdomain</value> <value>xmpp:abuse@localhost.localdomain</value> </abuse-addresses> <feedback-addresses> <value>http://example.org/feedback.php</value> </feedback-addresses> <sales-addresses/> <security-addresses/> <support-addresses/> </serverinfo> --> </discovery> <!-- User options --> <user> <!-- By default, users must explicitly created before they can start a session. The creation process is usually triggered by a c2s component in response to a client registering a new user. Enabling this option will make it so that user creation will be triggered the first time a non-existant user attempts to start a session. This is useful if you already have users in an external authentication database (eg LDAP) and you don't want them to have to register. --> <!-- <auto-create/> --> <!-- Define maximum size in bytes of fields of vcards. There is a recommendation that the avatar picture SHOULD NOT be larger than 16 KiB. --> <!-- <vcard> <max-field-size> <default>16384</default> <avatar>16384</avatar> </max-field-size> </vcard> --> <!-- Templates. If defined, the contents of these files will be stored in the users data store when they are created. --> <template> <!-- Uncomment <publish> if you wish to forcibly publish roster template from ldap on each user login --> <!-- <publish> --> <!-- Key used for fetching published roster items. Only one might be set at a time. If not set, all items are fetched. --> <!-- <fetch-key> <domain/> <user/> <fixed>grouping-key</fixed> </fetch-key> --> <!-- If <check-remove-domain> given, then published contact is checked against sm user database and if user is unknown to sm, contact will be deleted from user's roster (if it is in roster). If no domain set (tag empty) all contacts are checked. --> <!-- <check-remove-domain>jabber.example.com</check-remove-domain> --> <!-- Alternatively if <force-create-contacts/> is not commented, published contact is added to sm user database and user set known to sm, so it won't auto-unsubscribe on connection established --> <!-- <force-create-contacts/> --> <!-- Keep cache of "active" database specified number of seconds. This will significantly speed up publishing of roster. If unspecified or 0, no cache is used. --> <active-cache-ttl>60</active-cache-ttl> <!-- If <fix-subscriptions/> is not commented, set "to" and "from" subscriptions of user's contacts to subscriptions of corresponding published contacts. --> <!-- <fix-subscriptions/> --> <!-- If <override-names/> is uncommented, then displayed names of contacts in user's roster will be updated accordingly to published roster (if they differ). If commented, then user can rename contacts in roster --> <!-- <override-names/> --> <!-- when mapped-groups is on (<map-groups/> is uncommented), the actual group names for published contacts are read from published-roster-groups storage type, which may be set to ldapvcard driver. The key for searching is published user's group, and returned value is used as group name. So you can assign textual group IDs to users rather then group names. group-cache-ttl keeps cache of mapping from group id to name for specified number of seconds. If unspecified or 0, no cache is used. --> <!-- <mapped-groups> <map-groups/> <group-cache-ttl>120</group-cache-ttl> </mapped-groups> --> <!-- If <force-groups> is commented out, published roster's contact added to user's roster only when user does not have this contact. If <force-groups> is uncommented, then these checks are performed against each roster item already in user's roster: If roster item already present in user's roster in group of same name, no changes are made with this group (note that contact may be in more than one group). If <prefix> or <suffix> are given, then contact removed from any matching groups. After that, contact is added to group from published roster. In other words, all groups of updated contact, that match prefix or suffix, are replaced with group of published contact. This is done because there is no way to determine that group was published or greated by user. --> <!-- <force-groups> <prefix>MyOrg.</prefix> <suffix>(MyOrg)</suffix> </force-groups> --> <!-- </publish> --> <!-- If defined, the contents of these files will be stored in the users data store when they are created. --> <!-- If you defined publish, you should comment-out <roster> --> <!-- <roster>@sysconfdir@/templates/roster.xml</roster> --> </template> </user> <!-- Advanced Message Processing module configuration --> <amp> <!-- You can disable some actions --> <!-- <disableactions> <drop/> <error/> <alert/> <notify/> </disableactions> --> <!-- You can disable some conditions --> <!-- <disableconditions> <expireat/> <matchresource/> <deliver/> </disableconditions> --> <!-- You need to enable this if your server has offline storage disabled --> <!-- <offlinestoragedisabled/> --> </amp> <!-- Offline module configuration --> <offline> <!-- Do not store messages in offline store --> <!-- <dropmessages/> --> <!-- Store headline messages in offline store --> <!-- <storeheadlines/> --> <!-- Do not store subscription requests in offline store --> <!-- <dropsubscriptions/> --> <!-- Offline storage message quota. Specifies how many messages will be stored in user offline store --> <!-- <userquota>500</userquota> --> </offline> <!-- roster module configuration --> <roster> <!-- maximum items per user roster --> <!-- <maxitems>100</maxitems> --> </roster> <!-- status module configuration --> <status> <!-- presence service resource disabled when commented out --> <!-- <resource>webstatus</resource> --> </status> </sm> <!-- vim: syntax=xml --> �����������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/templates/���������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017350�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/templates/Makefile.am����������������������������������������������������0000664�0000000�0000000�00000001504�12614627753�0021404�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������templatesdir = $(sysconfdir)/templates LIBTOOL += --quiet templates_DATA = roster.xml.dist EXTRA_DIST = roster.xml.dist.in edit = sed \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@bindir\@,$(bindir),g' $(templates_DATA): @echo "generating $@ from $@.in"; \ rm -f $@ $@.tmp; \ $(edit) < @srcdir@/$@.in > $@.tmp; \ mv $@.tmp $@ install-data-hook: @list='$(templates_DATA)'; for p in $$list; do \ dest=`echo $$p | sed -e s/.dist//`; \ if test -f $(DESTDIR)$(templatesdir)/$$dest; then \ echo "$@ will not overwrite existing $(DESTDIR)$(templatesdir)/$$dest"; \ else \ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(templatesdir)/$$dest"; \ $(INSTALL_DATA) $$p $(DESTDIR)$(templatesdir)/$$dest; \ fi; \ done clean-local: rm -f $(templates_DATA) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/etc/templates/roster.xml.dist.in���������������������������������������������0000664�0000000�0000000�00000000406�12614627753�0022757�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- This is the roster template. If enabled in sm.xml, new users will get this roster by default. --> <query xmlns='jabber:iq:roster'> <!-- <item name='Helpdesk' jid='helpdesk@localhost' subscription='none'><group>Support</group></item> --> </query> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/license-header���������������������������������������������������������������0000664�0000000�0000000�00000001570�12614627753�0017375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2008 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Tomasz Sterna * * 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, MA02111-1307USA */ ����������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015352�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/Makefile.am��������������������������������������������������������������0000664�0000000�0000000�00000001165�12614627753�0017411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������man_MANS = jabberd.8 c2s.8 router.8 s2s.8 sm.8 EXTRA_DIST = jabberd.8.in c2s.8.in router.8.in s2s.8.in sm.8.in LIBTOOL += --quiet jabberd_bin = router sm s2s c2s edit = sed \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@VERSION\@,$(VERSION),g' $(man_MANS): @echo "generating $@ from $@.in"; \ edit='$(edit)'; \ list='$(jabberd_bin)'; for p in $$list; do \ bin=`echo "$$p" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ edit="$$edit -e s,@jabberd_$$p\_bin\\@,$$bin,g"; \ done; \ rm -f $@ $@.tmp; \ eval "$$edit < @srcdir@/$@.in > $@.tmp"; \ mv $@.tmp $@ clean-local: rm -f $(man_MANS) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/c2s.8.in�����������������������������������������������������������������0000664�0000000�0000000�00000001424�12614627753�0016540�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH @jabberd_c2s_bin@ 8 "28 August 2003" "@VERSION@" "jabberd project" .SH NAME @jabberd_c2s_bin@ \- client-to-server connector .SH SYNOPSIS .B @jabberd_c2s_bin@ .I [-h] [-c config] [-D] .SH DESCRIPTION .BR @jabberd_c2s_bin@ accepts incoming connections from clients, performs authentication and registration functions, and communicates with the session manager on their behalf. .SH OPTIONS .TP .B \-h Show summary of options. .TP .B \-c Alternate configuration file to use. The compiled-in default is @sysconfdir@/c2s.xml. .TP .B \-D Print debugging output. You should configure jabberd with the --enable-debug switch to enable this. .SH SEE ALSO .BR jabberd (8) .BR @jabberd_router_bin@ (8) .BR @jabberd_s2s_bin@ (8) .BR @jabberd_sm_bin@ (8) .SH AUTHOR Robert Norris <rob@cataclysm.cx> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/jabberd.8.in�������������������������������������������������������������0000664�0000000�0000000�00000001253�12614627753�0017442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH jabberd 8 "28 August 2003" "@VERSION@" "jabberd project" .SH NAME jabberd \- jabberd startup script .SH SYNOPSIS .B jabberd .I [-h] [-c config] [-D] .SH DESCRIPTION .BR jabberd is a script that runs the various components that make up the jabberd "server". .SH OPTIONS .TP .B \-h Show summary of options. .TP .B \-c Alternate configuration file to use. The compiled-in default is @sysconfdir@/jabberd.cfg .TP .B \-D Print debugging output. You should configure jabberd with the --enable-debug switch to enable this. .SH SEE ALSO .BR @jabberd_c2s_bin@ (8) .BR @jabberd_router_bin@ (8) .BR @jabberd_s2s_bin@ (8) .BR @jabberd_sm_bin@ (8) .SH AUTHOR Robert Norris <rob@cataclysm.cx> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/router.8.in��������������������������������������������������������������0000664�0000000�0000000�00000001434�12614627753�0017372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH @jabberd_router_bin@ 8 "28 August 2003" "@VERSION@" "jabberd project" .SH NAME @jabberd_router_bin@ \- XML packet distributor .SH SYNOPSIS .B @jabberd_router_bin@ .I [-h] [-c config] [-D] .SH DESCRIPTION .BR @jabberd_router_bin@ is the core component of the jabberd system. It passes XML packets between the components, and manages the entry and exit of components onto the network. .SH OPTIONS .TP .B \-h Show summary of options. .TP .B \-c Alternate configuration file to use. The compiled-in default is @sysconfdir@/router.xml. .TP .B \-D Print debugging output. You should configure jabberd with the --enable-debug switch to enable this. .SH SEE ALSO .BR jabberd (8) .BR @jabberd_c2s_bin@ (8) .BR @jabberd_s2s_bin@ (8) .BR @jabberd_sm_bin@ (8) .SH AUTHOR Robert Norris <rob@cataclysm.cx> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/s2s.8.in�����������������������������������������������������������������0000664�0000000�0000000�00000001301�12614627753�0016552�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH @jabberd_s2s_bin@ 8 "28 August 2003" "@VERSION@" "jabberd project" .SH NAME @jabberd_s2s_bin@ \- server-to-server connector .SH SYNOPSIS .B @jabberd_s2s_bin@ .I [-h] [-c config] [-D] .SH DESCRIPTION .BR @jabberd_s2s_bin@ manages connections between local components and other Jabber servers. .SH OPTIONS .TP .B \-h Show summary of options. .TP .B \-c Alternate configuration file to use. The compiled-in default is @sysconfdir@/s2s.xml. .TP .B \-D Print debugging output. You should configure jabberd with the --enable-debug switch to enable this. .SH SEE ALSO .BR jabberd (8) .BR @jabberd_c2s_bin@ (8) .BR @jabberd_router_bin@ (8) .BR @jabberd_sm_bin@ (8) .SH AUTHOR Robert Norris <rob@cataclysm.cx> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/man/sm.8.in������������������������������������������������������������������0000664�0000000�0000000�00000001513�12614627753�0016467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH @jabberd_sm_bin@ 8 "28 August 2003" "@VERSION@" "jabberd project" .SH NAME @jabberd_sm_bin@ \- Jabber IM session manager .SH SYNOPSIS .B @jabberd_sm_bin@ .I [-h] [-c config] [-D] .SH DESCRIPTION .BR @jabberd_sm_bin@ provides instant messaging services to Jabber clients. It performs all the essential instant messaging services like rosters, presence tracking, message distribution and subscriptions, plus more advanced features. .SH OPTIONS .TP .B \-h Show summary of options. .TP .B \-c Alternate configuration file to use. The compiled-in default is @sysconfdir@/sm.xml. .TP .B \-D Print debugging output. You should configure jabberd with the --enable-debug switch to enable this. .SH SEE ALSO .BR jabberd (8) .BR @jabberd_c2s_bin@ (8) .BR @jabberd_router_bin@ (8) .BR @jabberd_s2s_bin@ (8) .SH AUTHOR Robert Norris <rob@cataclysm.cx> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015363�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/Makefile.am��������������������������������������������������������������0000664�0000000�0000000�00000000451�12614627753�0017417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet AM_CPPFLAGS = -I@top_srcdir@ noinst_LTLIBRARIES = libmio.la noinst_HEADERS = mio.h mio_impl.h mio_epoll.h mio_poll.h mio_select.h mio_kqueue.h mio_wsasync.h libmio_la_SOURCES = mio.c mio_epoll.c mio_poll.c mio_select.c mio_kqueue.c mio_wsasync.c libmio_la_LIBADD = @LDFLAGS@ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio.c��������������������������������������������������������������������0000664�0000000�0000000�00000003162�12614627753�0016315�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" mio_t mio_kqueue_new(int maxfd); mio_t mio_epoll_new(int maxfd); mio_t mio_poll_new(int maxfd); mio_t mio_select_new(int maxfd); mio_t mio_wsasync_new(int maxfd); mio_t mio_new(int maxfd) { mio_t m = NULL; #ifdef MIO_KQUEUE m = mio_kqueue_new(maxfd); if (m != NULL) return m; #endif #ifdef MIO_EPOLL m = mio_epoll_new(maxfd); if (m != NULL) return m; #endif #ifdef MIO_WSASYNC m = mio_wsasync_new(maxfd); if (m != NULL) return m; #endif #ifdef MIO_SELECT m = mio_select_new(maxfd); if (m != NULL) return m; #endif #ifdef MIO_POLL m = mio_poll_new(maxfd); if (m != NULL) return m; #endif return m; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio.h��������������������������������������������������������������������0000664�0000000�0000000�00000012276�12614627753�0016330�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifndef INCL_MIO_H #define INCL_MIO_H #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "util/inaddr.h" #include "ac-stdint.h" /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifdef _WIN32 # define MIO_MAXFD FD_SETSIZE #else # define MIO_MAXFD 1024 #endif #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <stdarg.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_FCNTL_H # include <fcntl.h> #endif #ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> #endif #ifdef HAVE_SYS_FILIO_H # include <sys/filio.h> #endif #ifdef __cplusplus extern "C" { #endif /** * @file mio/mio.h * @brief mio - manage i/o * * This is the most simple fd wrapper possible. It is also customized * per-app and may be limited/extended depending on needs. * * It's basically our own implementation of libevent or libev. * * Usage is pretty simple: * - create a manager * - add fds or tell it to listen * - assign an action handler * - tell mio to read or write with a fd * - process accept, read, write, and close requests * * Note: normal fd's don't get events unless the app calls mio_read/write() first! */ /** the master mio mama */ struct mio_st; typedef struct mio_fd_st { int fd; } *mio_fd_t; /** these are the actions and a handler type assigned by the applicaiton using mio */ typedef enum { action_ACCEPT, action_READ, action_WRITE, action_CLOSE } mio_action_t; typedef int (*mio_handler_t) (struct mio_st **m, mio_action_t a, struct mio_fd_st *fd, void* data, void *arg); typedef struct mio_st { void (*mio_free)(struct mio_st **m); struct mio_fd_st *(*mio_listen)(struct mio_st **m, int port, const char *sourceip, mio_handler_t app, void *arg); struct mio_fd_st *(*mio_connect)(struct mio_st **m, int port, const char *hostip, const char *srcip, mio_handler_t app, void *arg); struct mio_fd_st *(*mio_register)(struct mio_st **m, int fd, mio_handler_t app, void *arg); void (*mio_app)(struct mio_st **m, struct mio_fd_st *fd, mio_handler_t app, void *arg); void (*mio_close)(struct mio_st **m, struct mio_fd_st *fd); void (*mio_write)(struct mio_st **m, struct mio_fd_st *fd); void (*mio_read)(struct mio_st **m, struct mio_fd_st *fd); void (*mio_run)(struct mio_st **m, int timeout); } **mio_t; /** create/free the mio subsytem */ JABBERD2_API mio_t mio_new(int maxfd); /* returns NULL if failed */ #define mio_free(m) (*m)->mio_free(m) /** for creating a new listen socket in this mio (returns new fd or <0) */ #define mio_listen(m, port, sourceip, app, arg) \ (*m)->mio_listen(m, port, sourceip, app, arg) /** for creating a new socket connected to this ip:port (returns new fd or <0, use mio_read/write first) */ #define mio_connect(m, port, hostip, srcip, app, arg) \ (*m)->mio_connect(m, port, hostip, srcip, app, arg) /** for adding an existing socket connected to this mio */ #define mio_register(m, fd, app, arg) \ (*m)->mio_register(m, fd, app, arg) /** re-set the app handler */ #define mio_app(m, fd, app, arg) (*m)->mio_app(m, fd, app, arg) /** request that mio close this fd */ #define mio_close(m, fd) (*m)->mio_close(m, fd) /** mio should try the write action on this fd now */ #define mio_write(m, fd) (*m)->mio_write(m, fd) /** process read events for this fd */ #define mio_read(m, fd) (*m)->mio_read(m, fd) /** give some cpu time to mio to check it's sockets, 0 is non-blocking */ #define mio_run(m, timeout) (*m)->mio_run(m, timeout) /** all MIO related routines should use those for error reporting */ #ifndef _WIN32 # define MIO_ERROR errno # define MIO_SETERROR(e) (errno = e) # define MIO_STRERROR(e) strerror(e) # define MIO_WOULDBLOCK (errno == EWOULDBLOCK || errno == EINTR || errno == EAGAIN) #else /* _WIN32 */ JABBERD2_API char *mio_strerror(int code); # define MIO_ERROR WSAGetLastError() # define MIO_SETERROR(e) WSASetLastError(e) # define MIO_STRERROR(e) mio_strerror(e) # define MIO_WOULDBLOCK (WSAGetLastError() == WSAEWOULDBLOCK) #endif /* _WIN32 */ #ifdef __cplusplus } #endif #endif /* INCL_MIO_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_epoll.c��������������������������������������������������������������0000664�0000000�0000000�00000002200�12614627753�0017500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" #ifdef MIO_EPOLL #include "mio_epoll.h" #include "mio_impl.h" mio_t mio_epoll_new(int maxfd) { return _mio_new(maxfd); } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_epoll.h��������������������������������������������������������������0000664�0000000�0000000�00000020120�12614627753�0017506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO backend for epoll() */ #include <sys/epoll.h> #define MIO_FUNCS \ static int _mio_poll(mio_t m, int t) \ { \ return epoll_wait(MIO(m)->epoll_fd, \ MIO(m)->res_event, 32, t*1000); \ } \ \ static mio_fd_t _mio_alloc_fd(mio_t m, int fd) \ { \ struct epoll_event event; \ mio_priv_fd_t priv_fd = malloc(sizeof (struct mio_priv_fd_st)); \ memset(priv_fd, 0, sizeof (struct mio_priv_fd_st)); \ \ priv_fd->mio_fd.fd = fd; \ priv_fd->events = 0; \ \ event.events = priv_fd->events; \ event.data.u64 = 0; \ event.data.ptr = priv_fd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_ADD, fd, &event); \ \ return (mio_fd_t)priv_fd; \ } #define MIO_FD_VARS \ uint32_t events; #define MIO_VARS \ int defer_free; \ int epoll_fd; \ struct epoll_event res_event[32]; #define MIO_INIT_VARS(m) \ do { \ MIO(m)->defer_free = 0; \ if ((MIO(m)->epoll_fd = epoll_create(maxfd)) < 0) \ { \ mio_debug(ZONE,"unable to initialize epoll mio"); \ free(m); \ return NULL; \ } \ } while(0) #define MIO_FREE_VARS(m) \ do { \ close(MIO(m)->epoll_fd); \ } while(0) #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(m, rfd) #define MIO_FREE_FD(m, mfd) if(mfd)free(mfd) #define MIO_REMOVE_FD(m, mfd) \ do { \ struct epoll_event event; \ event.events = 0; \ event.data.u64 = 0; \ event.data.ptr = mfd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_DEL, \ mfd->mio_fd.fd, &event); \ } while (0) #define MIO_CHECK(m, t) _mio_poll(m, t) #define MIO_SET_READ(m, mfd) \ do { \ struct epoll_event event; \ event.events = mfd->events; \ mfd->events |= EPOLLIN; \ if( mfd->events == event.events ) \ break; \ event.events = mfd->events; \ event.data.u64 = 0; \ event.data.ptr = mfd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_MOD, \ mfd->mio_fd.fd, &event); \ } while (0) #define MIO_SET_WRITE(m, mfd) \ do { \ struct epoll_event event; \ event.events = mfd->events; \ mfd->events |= EPOLLOUT; \ if( mfd->events == event.events ) \ break; \ event.events = mfd->events; \ event.data.u64 = 0; \ event.data.ptr = mfd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_MOD, \ mfd->mio_fd.fd, &event); \ } while (0) #define MIO_UNSET_READ(m, mfd) \ do { \ struct epoll_event event; \ event.events = mfd->events; \ mfd->events &= ~EPOLLIN; \ if( mfd->events == event.events ) \ break; \ event.events = mfd->events; \ event.data.u64 = 0; \ event.data.ptr = mfd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_MOD, \ mfd->mio_fd.fd, &event); \ } while (0) #define MIO_UNSET_WRITE(m, mfd) \ do { \ struct epoll_event event; \ event.events = mfd->events; \ mfd->events &= ~(EPOLLOUT); \ if( mfd->events == event.events ) \ break; \ event.events = mfd->events; \ event.data.u64 = 0; \ event.data.ptr = mfd; \ epoll_ctl(MIO(m)->epoll_fd, EPOLL_CTL_MOD, \ mfd->mio_fd.fd, &event); \ } while (0) #define MIO_CAN_READ(m,iter) \ (MIO(m)->res_event[iter].events & (EPOLLIN|EPOLLERR|EPOLLHUP)) #define MIO_CAN_WRITE(m,iter) \ (MIO(m)->res_event[iter].events & EPOLLOUT) #define MIO_CAN_FREE(m) (!MIO(m)->defer_free) #define MIO_INIT_ITERATOR(iter) \ int iter #define MIO_ITERATE_RESULTS(m, retval, iter) \ for(MIO(m)->defer_free = 1, iter = 0; (iter < retval) || ((MIO(m)->defer_free = 0)); iter++) #define MIO_ITERATOR_FD(m, iter) \ (MIO(m)->res_event[iter].data.ptr) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_impl.h���������������������������������������������������������������0000664�0000000�0000000�00000031213�12614627753�0017341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #include "util/inaddr.h" /* win32 wrappers around strerror */ #ifdef _WIN32 #define close(x) closesocket(x) JABBERD2_API char *mio_strerror(int code) { static char buff[1024]; if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buff, sizeof(buff), NULL)) return buff; return strerror(code); } #endif /* _WIN32 */ /** our internal wrapper around a fd */ typedef enum { type_CLOSED = 0x00, type_NORMAL = 0x01, type_LISTEN = 0x02, type_CONNECT = 0x10, type_CONNECT_READ = 0x11, type_CONNECT_WRITE = 0x12 } mio_type_t; typedef struct mio_priv_fd_st { struct mio_fd_st mio_fd; mio_type_t type; /* app event handler and data */ mio_handler_t app; void *arg; MIO_FD_VARS } *mio_priv_fd_t; /** now define our master data type */ typedef struct mio_priv_st { struct mio_st *mio; int maxfd; MIO_VARS } *mio_priv_t; /* lazy factor */ #define MIO(m) ((mio_priv_t) m) #define FD(m,f) ((mio_priv_fd_t) f) #define ACT(m,f,a,d) (*(FD(m,f)->app))(m,a,&FD(m,f)->mio_fd,d,FD(m,f)->arg) /* temp debug outputter */ #define ZONE __LINE__ #ifndef MIO_DEBUG #define MIO_DEBUG 0 #endif #define mio_debug if(MIO_DEBUG) _mio_debug static void _mio_debug(int line, const char *msgfmt, ...) { va_list ap; va_start(ap,msgfmt); fprintf(stderr,"mio.c#%d: ",line); vfprintf(stderr,msgfmt,ap); va_end(ap); fprintf(stderr,"\n"); } MIO_FUNCS /** add and set up this fd to this mio */ static mio_fd_t _mio_setup_fd(mio_t m, int fd, mio_handler_t app, void *arg) { int flags; mio_fd_t mio_fd; mio_debug(ZONE, "adding fd #%d", fd); mio_fd = MIO_ALLOC_FD(m, fd); if (mio_fd == NULL) return NULL; /* ok to process this one, welcome to the family */ FD(m,mio_fd)->type = type_NORMAL; FD(m,mio_fd)->app = app; FD(m,mio_fd)->arg = arg; /* set the socket to non-blocking */ #if defined(HAVE_FCNTL) flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); #elif defined(HAVE_IOCTL) flags = 1; ioctl(fd, FIONBIO, &flags); #endif return mio_fd; } /** internal close function */ static void _mio_close(mio_t m, mio_fd_t fd) { if(FD(m,fd)->type == type_CLOSED) return; mio_debug(ZONE,"actually closing fd #%d", fd->fd); /* take out of poll sets */ MIO_REMOVE_FD(m, FD(m,fd)); /* let the app know, it must process any waiting write data it has and free it's arg */ if (FD(m,fd)->app != NULL) ACT(m, fd, action_CLOSE, NULL); /* close the socket, and reset all memory */ close(fd->fd); FD(m,fd)->type = type_CLOSED; FD(m,fd)->app = NULL; FD(m,fd)->arg = NULL; if (MIO_CAN_FREE(m)) { MIO_FREE_FD(m, fd); } } /** internally accept an incoming connection from a listen sock */ static void _mio_accept(mio_t m, mio_fd_t fd) { struct sockaddr_storage serv_addr; socklen_t addrlen = (socklen_t) sizeof(serv_addr); int newfd; mio_fd_t mio_fd; char ip[INET6_ADDRSTRLEN]; mio_debug(ZONE, "accepting on fd #%d", fd->fd); /* pull a socket off the accept queue and check */ newfd = accept(fd->fd, (struct sockaddr*)&serv_addr, &addrlen); if(newfd <= 0) return; if(addrlen <= 0) { close(newfd); return; } j_inet_ntop(&serv_addr, ip, sizeof(ip)); mio_debug(ZONE, "new socket accepted fd #%d, %s:%d", newfd, ip, j_inet_getport(&serv_addr)); /* set up the entry for this new socket */ mio_fd = _mio_setup_fd(m, newfd, FD(m,fd)->app, FD(m,fd)->arg); if(!mio_fd) { close(newfd); return; } /* tell the app about the new socket, if they reject it clean up */ if (ACT(m, mio_fd, action_ACCEPT, ip)) { mio_debug(ZONE, "accept was rejected for %s:%d", ip, newfd); MIO_REMOVE_FD(m, FD(m,mio_fd)); /* close the socket, and reset all memory */ close(newfd); MIO_FREE_FD(m, mio_fd); } return; } /** internally change a connecting socket to a normal one */ static void _mio__connect(mio_t m, mio_fd_t fd) { mio_type_t type = FD(m,fd)->type; mio_debug(ZONE, "connect processing for fd #%d", fd->fd); /* reset type and clear the "write" event that flags connect() is done */ FD(m,fd)->type = type_NORMAL; MIO_UNSET_WRITE(m,FD(m,fd)); /* if the app had asked to do anything in the meantime, do those now */ if(type & type_CONNECT_READ) mio_read(m,fd); if(type & type_CONNECT_WRITE) mio_write(m,fd); } /** reset app stuff for this fd */ static void _mio_app(mio_t m, mio_fd_t fd, mio_handler_t app, void *arg) { FD(m,fd)->app = app; FD(m,fd)->arg = arg; } /** main select loop runner */ static void _mio_run(mio_t m, int timeout) { int retval; MIO_INIT_ITERATOR(iter); mio_debug(ZONE, "mio running for %d sec", timeout); /* wait for a socket event */ retval = MIO_CHECK(m, timeout); /* nothing to do */ if(retval == 0) return; /* an error */ if(retval < 0) { mio_debug(ZONE, "MIO_CHECK returned an error (%d)", MIO_ERROR); return; } mio_debug(ZONE,"mio processing %d file descriptors", retval); /* loop through the sockets, check for stuff to do */ MIO_ITERATE_RESULTS(m, retval, iter) { mio_fd_t fd = MIO_ITERATOR_FD(m,iter); if (fd == NULL) continue; /* skip already dead slots */ if(FD(m,fd)->type == type_CLOSED) continue; /* new conns on a listen socket */ if(FD(m,fd)->type == type_LISTEN && MIO_CAN_READ(m,iter)) { _mio_accept(m, fd); goto deferred; } /* check for connecting sockets */ if(FD(m,fd)->type & type_CONNECT && (MIO_CAN_READ(m,iter) || MIO_CAN_WRITE(m,iter))) { _mio__connect(m, fd); goto deferred; } /* read from ready sockets */ if(FD(m,fd)->type == type_NORMAL && MIO_CAN_READ(m,iter)) { /* if they don't want to read any more right now */ if(ACT(m, fd, action_READ, NULL) == 0) MIO_UNSET_READ(m, FD(m,fd)); } /* write to ready sockets */ if(FD(m,fd)->type == type_NORMAL && MIO_CAN_WRITE(m,iter)) { /* don't wait for writeability if nothing to write anymore */ if(ACT(m, fd, action_WRITE, NULL) == 0) MIO_UNSET_WRITE(m, FD(m,fd)); } deferred: /* deferred closing fd * one of previous actions might change the state of fd */ if(FD(m,fd)->type == type_CLOSED) { MIO_FREE_FD(m, fd); } } } /** start processing read events */ static void _mio_read(mio_t m, mio_fd_t fd) { if(m == NULL || fd == NULL) return; /* if connecting, do this later */ if(FD(m,fd)->type & type_CONNECT) { FD(m,fd)->type |= type_CONNECT_READ; return; } MIO_SET_READ(m, FD(m,fd)); } /** try writing to the socket via the app */ static void _mio_write(mio_t m, mio_fd_t fd) { if(m == NULL || fd == NULL) return; /* if connecting, do this later */ if(FD(m,fd)->type & type_CONNECT) { FD(m,fd)->type |= type_CONNECT_WRITE; return; } if(FD(m,fd)->type != type_NORMAL) return; if(ACT(m, fd, action_WRITE, NULL) == 0) return; /* not all written, do more l8r */ MIO_SET_WRITE(m, FD(m,fd)); } /** set up a listener in this mio w/ this default app/arg */ static mio_fd_t _mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg) { int fd, flag = 1; mio_fd_t mio_fd; struct sockaddr_storage sa; if(m == NULL) return NULL; mio_debug(ZONE, "mio to listen on %d [%s]", port, sourceip); memset(&sa, 0, sizeof(sa)); /* if we specified an ip to bind to */ if(sourceip != NULL && !j_inet_pton(sourceip, &sa)) return NULL; if(sa.ss_family == 0) sa.ss_family = AF_INET; /* attempt to create a socket */ if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0) return NULL; /* set up and bind address info */ j_inet_setport(&sa, port); if(bind(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)) < 0) { close(fd); return NULL; } /* start listening with a max accept queue specified by kern.ipc.somaxconn sysctl */ if(listen(fd, -1) < 0) { close(fd); return NULL; } /* now set us up the bomb */ mio_fd = _mio_setup_fd(m, fd, app, arg); if(mio_fd == NULL) { close(fd); return NULL; } FD(m,mio_fd)->type = type_LISTEN; /* by default we read for new sockets */ mio_read(m,mio_fd); return mio_fd; } /** create an fd and connect to the given ip/port */ static mio_fd_t _mio_connect(mio_t m, int port, const char *hostip, const char *srcip, mio_handler_t app, void *arg) { int fd, flag, flags; mio_fd_t mio_fd; struct sockaddr_storage sa, src; memset(&sa, 0, sizeof(sa)); if(m == NULL || port <= 0 || hostip == NULL) return NULL; mio_debug(ZONE, "mio connecting to %s, port=%d",hostip,port); /* convert the hostip */ if(j_inet_pton(hostip, &sa)<=0) { MIO_SETERROR(EFAULT); return NULL; } if(!sa.ss_family) sa.ss_family = AF_INET; /* attempt to create a socket */ if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL; /* Bind to the given source IP if it was specified */ if (srcip != NULL) { /* convert the srcip */ if(j_inet_pton(srcip, &src)<=0) { MIO_SETERROR(EFAULT); return NULL; } if(!src.ss_family) src.ss_family = AF_INET; j_inet_setport(&src, INADDR_ANY); if(bind(fd,(struct sockaddr*)&src,j_inet_addrlen(&src)) < 0) { close(fd); return NULL; } } /* set the socket to non-blocking before connecting */ #if defined(HAVE_FCNTL) flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); #elif defined(HAVE_IOCTL) flags = 1; ioctl(fd, FIONBIO, &flags); #endif /* set up address info */ j_inet_setport(&sa, port); /* try to connect */ flag = connect(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)); mio_debug(ZONE, "connect returned %d and %s", flag, MIO_STRERROR(MIO_ERROR)); /* already connected? great! */ if(flag == 0) { mio_fd = _mio_setup_fd(m,fd,app,arg); if(mio_fd != NULL) return mio_fd; } /* gotta wait till later */ #ifdef _WIN32 if(flag == -1 && WSAGetLastError() == WSAEWOULDBLOCK) #else if(flag == -1 && errno == EINPROGRESS) #endif { mio_fd = _mio_setup_fd(m,fd,app,arg); if(mio_fd != NULL) { mio_debug(ZONE, "connect processing non-blocking mode"); FD(m,mio_fd)->type = type_CONNECT; MIO_SET_WRITE(m,FD(m,mio_fd)); return mio_fd; } } /* bummer dude */ close(fd); return NULL; } /** adam */ static void _mio_free(mio_t m) { MIO_FREE_VARS(m); free(m); } /** eve */ static mio_t _mio_new(int maxfd) { static struct mio_st mio_impl = { _mio_free, _mio_listen, _mio_connect, _mio_setup_fd, _mio_app, _mio_close, _mio_write, _mio_read, _mio_run }; mio_t m; /* init winsock if we are in Windows */ #ifdef _WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD( 1, 1 ), &wsaData)) return NULL; #endif /* allocate and zero out main memory */ if((m = calloc(1, sizeof(struct mio_priv_st))) == NULL) { fprintf(stderr,"Cannot allocate MIO memory! Exiting.\n"); exit(EXIT_FAILURE); } /* set up our internal vars */ *m = &mio_impl; MIO(m)->maxfd = maxfd; MIO_INIT_VARS(m); return m; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_kqueue.c�������������������������������������������������������������0000664�0000000�0000000�00000000422�12614627753�0017670�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" #ifdef MIO_KQUEUE #include "mio_kqueue.h" #include "mio_impl.h" mio_t mio_kqueue_new(int maxfd) { return _mio_new(maxfd); } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_kqueue.h�������������������������������������������������������������0000664�0000000�0000000�00000012707�12614627753�0017706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* MIO backend for kqueue() */ #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #ifdef HAVE_SYS_EVENT_H #include <sys/event.h> #endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif #define MIO_FUNCS \ \ mio_priv_t dbjdebug; \ static mio_fd_t \ _mio_alloc_fd(mio_t m, int fd) \ { \ struct kevent events[2]; \ mio_priv_fd_t priv_fd; \ dbjdebug = m; \ priv_fd = malloc(sizeof(*priv_fd)); \ memset(priv_fd, 0, sizeof(*priv_fd)); \ priv_fd->mio_fd.fd = fd; \ EV_SET(&events[0], fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \ EV_SET(&events[1], fd, EVFILT_WRITE, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \ if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error creating kevents on fd %d (%d)", fd, errno); \ } \ return (mio_fd_t)priv_fd; \ } \ \ static void \ _mio_free_fd(mio_t m, mio_fd_t mfd) \ { \ int i; \ /* Unfortunately, the mio_impl.h api is a bit broken in that it \ * assumes that we can defer free until the end of the current iteration. \ * Unfortunately, with kqueue, a given fd may appear in the iteration loop \ * more than once, so we need to both defer free and also clear out any \ * other instances of the current fd in the return data. Fortunately, the \ * amount of data we ask for in each call to kevent is small and constant. \ */ \ for (i = 0; i < MIO(m)->nevents; i++) { \ if (MIO(m)->events[i].udata == mfd) { \ MIO(m)->events[i].udata = &MIO(m)->dummy; \ } \ } \ memset(mfd, 0x5a, sizeof(mio_priv_fd_t)); /* debugging only */ \ free(mfd); \ } \ \ static int \ _mio_check(mio_t m, int timeout) \ { \ struct timespec ts; \ int ret; \ ts.tv_nsec = 0; \ ts.tv_sec = timeout; \ ret = kevent(MIO(m)->kq, NULL, 0, MIO(m)->events, sizeof(MIO(m)->events)/sizeof(MIO(m)->events[0]), &ts); \ if (ret >= 0) \ MIO(m)->nevents = ret; \ return ret; \ } #define MIO_FD_VARS #define MIO_VARS \ int kq; \ int nevents; \ struct kevent events[32]; \ struct mio_priv_fd_st dummy; #define MIO_INIT_VARS(m) \ do { \ MIO(m)->nevents = 0; \ MIO(m)->dummy.type = type_CLOSED; \ if ((MIO(m)->kq = kqueue()) == -1) { \ mio_debug(ZONE,"internal error creating kqueue (%d)", errno); \ return NULL; \ } \ } while(0) #define MIO_FREE_VARS(m) close(MIO(m)->kq) #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(m,rfd) #define MIO_CAN_FREE(m) (MIO(m)->nevents == 0) #define MIO_FREE_FD(m, mfd) _mio_free_fd(m, mfd) #define MIO_REMOVE_FD(m, mfd) \ do { \ struct kevent events[2]; \ EV_SET(&events[0], mfd->mio_fd.fd, EVFILT_READ, EV_DELETE, 0, 0, mfd); \ EV_SET(&events[1], mfd->mio_fd.fd, EVFILT_WRITE, EV_DELETE, 0, 0, mfd); \ if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error deleting kevents on fd %d (%d)", mfd->mio_fd.fd, errno); \ } \ } while (0) /* * This could be tweaked to be more efficient and only apply filter changes * once every loop, but that can be done if testing shows it to be helpful */ #define MIO_SET_READ(m, mfd) \ do { \ struct kevent changelist; \ EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_ENABLE, 0, 0, mfd); \ if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \ } \ } while (0) #define MIO_SET_WRITE(m, mfd) \ do { \ struct kevent changelist; \ EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_ENABLE, 0, 0, mfd); \ if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \ } \ } while (0) #define MIO_UNSET_READ(m, mfd) \ do { \ struct kevent changelist; \ EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_DISABLE, 0, 0, mfd); \ if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \ } \ } while (0) #define MIO_UNSET_WRITE(m, mfd) \ do { \ struct kevent changelist; \ EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_DISABLE, 0, 0, mfd); \ if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \ mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \ } \ } while (0) #define MIO_INIT_ITERATOR(iter) \ int iter; #define MIO_ITERATE_RESULTS(m, retval, iter) \ for(iter = 0; (iter < retval) || ((MIO(m)->nevents = 0)); iter++) #define MIO_CAN_READ(m, iter) (MIO((m))->events[(iter)].filter == EVFILT_READ) #define MIO_CAN_WRITE(m, iter) (MIO((m))->events[(iter)].filter == EVFILT_WRITE) #define MIO_ITERATOR_FD(m, iter) ((mio_fd_t)(MIO(m)->events[(iter)].udata)) #define MIO_CHECK(m, t) _mio_check(m, t)���������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_poll.c���������������������������������������������������������������0000664�0000000�0000000�00000002175�12614627753�0017346�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" #ifdef MIO_POLL #include "mio_poll.h" #include "mio_impl.h" mio_t mio_poll_new(int maxfd) { return _mio_new(maxfd); } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_poll.h���������������������������������������������������������������0000664�0000000�0000000�00000012557�12614627753�0017360�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* MIO backend for poll() */ #ifdef HAVE_POLL_H # include <poll.h> #endif #define MIO_FUNCS \ static void _mio_fds_init(mio_priv_t m) \ { \ int fd; \ for(fd = 0; fd < m->maxfd; fd++) \ { \ m->pfds[fd].fd = -1; \ m->fds[fd].mio_fd.fd = fd; \ } \ m->highfd = 0; \ } \ \ static mio_fd_t _mio_alloc_fd(mio_priv_t m, int fd) \ { \ m->pfds[fd].fd = fd; \ m->pfds[fd].events = 0; \ if(fd > m->highfd) m->highfd = fd; \ return &m->fds[fd].mio_fd; \ } \ \ static int _mio_poll(mio_priv_t m, int t) \ { \ return poll(m->pfds, m->highfd + 1, t*1000); \ } #define MIO_FD_VARS #define MIO_VARS \ struct mio_priv_fd_st *fds; \ int highfd; \ struct pollfd *pfds; #define MIO_INIT_VARS(m) \ do { \ if((MIO(m)->fds = malloc(sizeof(struct mio_priv_fd_st) * maxfd)) == NULL) \ { \ mio_debug(ZONE,"internal error creating new mio"); \ free(m); \ return NULL; \ } \ memset(MIO(m)->fds, 0, sizeof(struct mio_priv_fd_st) * maxfd); \ \ if((MIO(m)->pfds = malloc(sizeof(struct pollfd) * maxfd)) == NULL) \ { \ mio_debug(ZONE, "internal error creating new mio"); \ free(MIO(m)->fds); \ free(m); \ return NULL; \ } \ memset(MIO(m)->pfds, 0, sizeof(struct pollfd) * maxfd); \ \ _mio_fds_init(MIO(m)); \ } while(0) #define MIO_FREE_VARS(m) \ do { \ free(MIO(m)->fds); \ free(MIO(m)->pfds); \ } while (0) #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(MIO(m), rfd) #define MIO_FREE_FD(m, mfd) #define MIO_REMOVE_FD(m, mfd) MIO(m)->pfds[mfd->mio_fd.fd].fd = -1 #define MIO_CHECK(m, t) _mio_poll(MIO(m), t) #define MIO_SET_READ(m, mfd) MIO(m)->pfds[mfd->mio_fd.fd].events |= POLLIN #define MIO_SET_WRITE(m, mfd) MIO(m)->pfds[mfd->mio_fd.fd].events |= POLLOUT #define MIO_UNSET_READ(m, mfd) MIO(m)->pfds[mfd->mio_fd.fd].events &= ~POLLIN #define MIO_UNSET_WRITE(m, mfd) MIO(m)->pfds[mfd->mio_fd.fd].events &= ~POLLOUT #define MIO_CAN_READ(m, iter) \ (MIO(m)->pfds[iter].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) #define MIO_CAN_WRITE(m, iter) (MIO(m)->pfds[iter].revents & POLLOUT) #define MIO_CAN_FREE(m) 1 #define MIO_INIT_ITERATOR(iter) \ int iter #define MIO_ITERATE_RESULTS(m, retval, iter) \ for(iter = 0; iter <= MIO(m)->highfd; iter++) #define MIO_ITERATOR_FD(m, iter) \ (&MIO(m)->fds[iter].mio_fd) �������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_select.c�������������������������������������������������������������0000664�0000000�0000000�00000002203�12614627753�0017647�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Christof Meerwald * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" #ifdef MIO_SELECT #include "mio_select.h" #include "mio_impl.h" mio_t mio_select_new(int maxfd) { return _mio_new(maxfd); } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_select.h�������������������������������������������������������������0000664�0000000�0000000�00000013442�12614627753�0017663�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* MIO backend for select() */ #ifdef HAVE_SYS_SELECT_H # include <sys/select.h> #endif #define MIO_FUNCS \ static void _mio_fds_init(mio_priv_t m) \ { \ int fd; \ for(fd = 0; fd < m->maxfd; fd++) \ { \ m->fds[fd].mio_fd.fd = fd; \ } \ m->highfd = 0; \ m->lowfd = m->maxfd; \ } \ \ static mio_fd_t _mio_alloc_fd(mio_priv_t m, int fd) \ { \ if(fd > m->highfd) m->highfd = fd; \ if(fd < m->lowfd) m->lowfd = fd; \ return &m->fds[fd].mio_fd; \ } \ \ static int _mio_select(mio_priv_t m, int t) \ { \ struct timeval tv; \ \ m->rfds_out = m->rfds_in; \ m->wfds_out = m->wfds_in; \ \ tv.tv_sec = t; \ tv.tv_usec = 0; \ return select(m->highfd + 1, &m->rfds_out, &m->wfds_out, NULL, &tv); \ } #define MIO_FD_VARS #define MIO_VARS \ struct mio_priv_fd_st *fds; \ int lowfd; \ int highfd; \ fd_set rfds_in, wfds_in, rfds_out, wfds_out; #define MIO_INIT_VARS(m) \ do { \ if (maxfd > FD_SETSIZE) \ { \ mio_debug(ZONE,"wanted MIO larger than %d file descriptors", FD_SETSIZE); \ free(m); \ return NULL; \ } \ \ if((MIO(m)->fds = calloc(1, sizeof(struct mio_priv_fd_st) * maxfd)) == NULL) \ { \ mio_debug(ZONE,"internal error creating new mio"); \ free(m); \ return NULL; \ } \ \ _mio_fds_init(MIO(m)); \ FD_ZERO(&MIO(m)->rfds_in); \ FD_ZERO(&MIO(m)->wfds_in); \ } while(0) #define MIO_FREE_VARS(m) free(MIO(m)->fds) #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(MIO(m), rfd) #define MIO_FREE_FD(m, mfd) #define MIO_REMOVE_FD(m, mfd) \ do { \ FD_CLR(mfd->mio_fd.fd, &MIO(m)->rfds_in); \ FD_CLR(mfd->mio_fd.fd, &MIO(m)->wfds_in); \ } while(0) #define MIO_CHECK(m, t) _mio_select(MIO(m), t) #define MIO_SET_READ(m, mfd) FD_SET(mfd->mio_fd.fd, &MIO(m)->rfds_in) #define MIO_SET_WRITE(m, mfd) FD_SET(mfd->mio_fd.fd, &MIO(m)->wfds_in) #define MIO_UNSET_READ(m, mfd) FD_CLR(mfd->mio_fd.fd, &MIO(m)->rfds_in) #define MIO_UNSET_WRITE(m, mfd) FD_CLR(mfd->mio_fd.fd, &MIO(m)->wfds_in) #define MIO_CAN_READ(m, iter) FD_ISSET(iter, &MIO(m)->rfds_out) #define MIO_CAN_WRITE(m, iter) FD_ISSET(iter, &MIO(m)->wfds_out) #define MIO_CAN_FREE(m) 1 #define MIO_INIT_ITERATOR(iter) \ int iter #define MIO_ITERATE_RESULTS(m, retval, iter) \ for(iter = MIO(m)->lowfd; iter <= MIO(m)->highfd; iter++) #define MIO_ITERATOR_FD(m, iter) \ (&MIO(m)->fds[iter].mio_fd) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_wsasync.c������������������������������������������������������������0000664�0000000�0000000�00000004335�12614627753�0020067�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Adam Strzelecki * * 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, MA02111-1307USA */ /* MIO -- Managed Input/Output --------------------------- */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio.h" #ifdef MIO_WSASYNC #include "mio_wsasync.h" #include "mio_impl.h" mio_t mio_wsasync_new(int maxfd) { return _mio_new(maxfd); } LONG CALLBACK _mio_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LONG lParam) { if(msg == WM_TIMER) { return 1; } else if(msg >= WM_MIO_EVENT) { mio_priv_t m = (mio_priv_t)(GetWindowLongPtr(hwnd, GWLP_USERDATA)); if(msg - WM_MIO_EVENT >= m->count) { mio_debug(ZONE, "mio event %d on socket id %d out of socket bounds %d", WSAGETSELECTEVENT(lParam), msg - WM_MIO_EVENT, m->count); return 0; } if(!m->fds[msg - WM_MIO_EVENT].event & WSAGETSELECTEVENT(lParam)) { mio_debug(ZONE, "unmatched mio event %d on socket #%d", WSAGETSELECTEVENT(lParam), m->fds[msg - WM_MIO_EVENT].mio_fd.fd); return 0; } m->select_fd = &m->fds[msg - WM_MIO_EVENT]; m->select_fd->revent = WSAGETSELECTEVENT(lParam); mio_debug(ZONE, "get mio event %d on socket #%d", m->select_fd->revent, m->select_fd->mio_fd.fd); \ return 1; } else if(msg == WM_CREATE) { SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams); } else { return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/mio/mio_wsasync.h������������������������������������������������������������0000664�0000000�0000000�00000027467�12614627753�0020107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Adam Strzelecki * * 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, MA02111-1307USA */ /* MIO backend for select() */ #ifdef HAVE_SYS_SELECT_H # include <sys/select.h> #endif #define WM_MIO_EVENT (WM_APP + 100) #define MIO_FUNCS \ static ATOM mio_class = NULL; \ \ LONG CALLBACK _mio_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LONG lParam); \ \ static mio_fd_t _mio_alloc_fd(mio_t m, int fd) \ { \ mio_priv_fd_t priv_fd = MIO(m)->next_free; \ \ if(priv_fd == NULL) \ return NULL; \ \ MIO(m)->next_free = priv_fd->next_free; \ priv_fd->mio_fd.fd = fd; \ priv_fd->next_free = NULL; \ \ return (mio_fd_t)priv_fd; \ } \ \ static void _mio_free_fd(mio_t m, mio_priv_fd_t priv_fd) \ { \ priv_fd->next_free = MIO(m)->next_free; \ priv_fd->mio_fd.fd = 0; \ priv_fd->revent = 0; \ priv_fd->event = 0; \ MIO(m)->next_free = priv_fd; \ } \ \ static int _mio_select(mio_priv_t m, int t) \ { \ MSG msg; int lResult = 0; \ MIO(m)->select_fd = NULL; \ MIO(m)->timer = SetTimer(MIO(m)->hwnd, \ MIO(m)->timer ? MIO(m)->timer : 0, 1000 * t, NULL); \ while(!lResult && GetMessage(&msg, NULL, 0, 0)) \ { \ TranslateMessage(&msg); \ lResult = DispatchMessage(&msg); \ } \ return MIO(m)->select_fd ? 1 : 0; \ } \ \ static mio_priv_fd_t _mio_peek(mio_priv_t m) \ { \ MSG msg; \ MIO(m)->select_fd = NULL; \ if(PeekMessage(&msg, MIO(m)->hwnd, WM_MIO_EVENT, WM_MIO_EVENT + MIO(m)->maxfd, PM_REMOVE)) \ { \ TranslateMessage(&msg); \ DispatchMessage(&msg); \ } \ return MIO(m)->select_fd; \ } #define MIO_FD_VARS \ struct mio_priv_fd_st *next_free; \ long event; \ long revent; \ int idx; #define MIO_VARS \ HWND hwnd; \ UINT_PTR timer; \ int defer_free; \ int count; \ mio_priv_fd_t select_fd; \ mio_priv_fd_t fds; \ mio_priv_fd_t next_free; #define MIO_INIT_VARS(m) \ do { \ int i; \ HINSTANCE hInstance = GetModuleHandle(NULL); \ MIO(m)->defer_free = 0; \ if(mio_class == NULL) { \ WNDCLASS wndclass; \ memset(&wndclass, 0, sizeof(WNDCLASS)); \ wndclass.style = CS_NOCLOSE; \ wndclass.lpfnWndProc = _mio_wnd_proc; \ wndclass.lpszClassName = "jabberd2mio"; \ wndclass.hInstance = hInstance; \ \ if((mio_class = RegisterClass(&wndclass)) == NULL) { \ mio_debug(ZONE, "cannot create listener class (%d, %x)", GetLastError(), hInstance); \ free(m); \ return NULL; \ } \ mio_debug(ZONE, "created listener class"); \ } \ MIO(m)->hwnd = CreateWindow("jabberd2mio", "jabberd2mio", \ 0, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, \ NULL, NULL, hInstance, m); \ if(MIO(m)->hwnd == NULL) { \ mio_debug(ZONE, "cannot create listener window (%d, %x)", GetLastError(), hInstance); \ free(m); \ return NULL; \ } \ mio_debug(ZONE, "created listener window (%x)", MIO(m)->hwnd); \ if((MIO(m)->fds = malloc(sizeof(struct mio_priv_fd_st) * maxfd)) == NULL) { \ mio_debug(ZONE, "cannot allocate descriptors table"); \ free(m); \ return NULL; \ } \ memset(MIO(m)->fds, 0, sizeof(struct mio_priv_fd_st) * maxfd); \ MIO(m)->count = maxfd; \ for(i = 0; i < maxfd; i++) \ MIO(m)->fds[i].idx = i; \ for(i = 0; i < maxfd - 1; i++) \ MIO(m)->fds[i].next_free = &(MIO(m)->fds[i + 1]); \ MIO(m)->fds[maxfd - 1].next_free = NULL; \ MIO(m)->next_free = &(MIO(m)->fds[0]); \ MIO(m)->select_fd = NULL; \ } while(0) #define MIO_FREE_VARS(m) \ do { \ DestroyWindow(MIO(m)->hwnd); \ free(MIO(m)->fds); \ } while(0) #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(MIO(m), rfd) #define MIO_FREE_FD(m, mfd) _mio_free_fd(m, mfd) #define MIO_DEQUEUE(m, mfd) \ if(mfd->event) { \ MSG msg; \ WSAAsyncSelect(mfd->mio_fd.fd, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, 0); \ while(PeekMessage(&msg, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, WM_MIO_EVENT + mfd->idx, PM_REMOVE)); \ } \ #define MIO_REMOVE_FD(m, mfd) MIO_DEQUEUE(m, mfd) #define MIO_CHECK(m, t) _mio_select(m, t) #define MIO_SET_READ(m, mfd) \ if(!(mfd->event & FD_READ)) { \ MIO_DEQUEUE(m, mfd); \ WSAAsyncSelect(mfd->mio_fd.fd, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, (mfd->event |= FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE)); \ } #define MIO_SET_WRITE(m, mfd) \ if(!(mfd->event & FD_WRITE)) { \ MIO_DEQUEUE(m, mfd); \ WSAAsyncSelect(mfd->mio_fd.fd, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, (mfd->event |= FD_WRITE|FD_CONNECT|FD_CLOSE)); \ } #define MIO_UNSET_READ(m, mfd) \ if(mfd->event & FD_READ) { \ mfd->event &= ~(FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE); \ if(mfd->event & FD_WRITE) \ mfd->event = FD_WRITE|FD_CONNECT|FD_CLOSE; \ MIO_DEQUEUE(m, mfd); \ WSAAsyncSelect(mfd->mio_fd.fd, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, mfd->event); \ } #define MIO_UNSET_WRITE(m, mfd) \ if(mfd->event & FD_WRITE) { \ mfd->event &= ~FD_WRITE; \ if(!(mfd->event & FD_READ)) \ mfd->event = 0; \ MIO_DEQUEUE(m, mfd); \ WSAAsyncSelect(mfd->mio_fd.fd, MIO(m)->hwnd, WM_MIO_EVENT + mfd->idx, mfd->event); \ } #define MIO_CAN_READ(m, iter) (iter->revent & (FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE)) #define MIO_CAN_WRITE(m, iter) ((iter->revent & FD_WRITE) || !(iter->revent & FD_READ) && (iter->revent & (FD_CONNECT|FD_CLOSE))) #define MIO_CAN_FREE(m) (!MIO(m)->defer_free) #define MIO_INIT_ITERATOR(iter) \ mio_priv_fd_t iter = NULL #define MIO_ITERATE_RESULTS(m, retval, iter) \ for(MIO(m)->defer_free = 1, iter = MIO(m)->select_fd; iter || ((MIO(m)->defer_free = 0)); iter = _mio_peek(m)) #define MIO_ITERATOR_FD(m, iter) \ (&iter->mio_fd) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016117�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/Makefile.am�����������������������������������������������������������0000664�0000000�0000000�00000000616�12614627753�0020156�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������AM_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -I@top_srcdir@ LIBTOOL += --quiet bin_PROGRAMS = router noinst_HEADERS = router.h router_SOURCES = aci.c main.c router.c user.c filter.c router_LDADD = $(top_builddir)/sx/libsx.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la if USE_LIBSUBST router_LDADD += $(top_builddir)/subst/libsubst.la endif ������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/aci.c�����������������������������������������������������������������0000664�0000000�0000000�00000007736�12614627753�0017034�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "router.h" /** aci manager */ typedef struct aci_user_st *aci_user_t; struct aci_user_st { char *name; aci_user_t next; }; xht aci_load(router_t r) { xht aci; int aelem, uelem, attr; char type[33]; aci_user_t list_head, list_tail, user; log_debug(ZONE, "loading aci"); aci = xhash_new(51); if((aelem = nad_find_elem(r->config->nad, 0, -1, "aci", 1)) < 0) return aci; aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 1); while(aelem >= 0) { if((attr = nad_find_attr(r->config->nad, aelem, -1, "type", NULL)) < 0) { aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0); continue; } list_head = NULL; list_tail = NULL; snprintf(type, 33, "%.*s", NAD_AVAL_L(r->config->nad, attr), NAD_AVAL(r->config->nad, attr)); log_debug(ZONE, "building list for '%s'", type); uelem = nad_find_elem(r->config->nad, aelem, -1, "user", 1); while(uelem >= 0) { if(NAD_CDATA_L(r->config->nad, uelem) > 0) { user = (aci_user_t) calloc(1, sizeof(struct aci_user_st)); user->name = (char *) malloc(sizeof(char) * (NAD_CDATA_L(r->config->nad, uelem) + 1)); sprintf(user->name, "%.*s", NAD_CDATA_L(r->config->nad, uelem), NAD_CDATA(r->config->nad, uelem)); if(list_tail != NULL) { list_tail->next = user; list_tail = user; } /* record the head of the list */ if(list_head == NULL) { list_head = user; list_tail = user; } log_debug(ZONE, "added '%s'", user->name); } uelem = nad_find_elem(r->config->nad, uelem, -1, "user", 0); } if(list_head != NULL) xhash_put(aci, pstrdup(xhash_pool(aci), type), (void *) list_head); aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0); } return aci; } /** see if a username is in an acl */ int aci_check(xht aci, const char *type, const char *name) { aci_user_t list, scan; log_debug(ZONE, "checking for '%s' in acl 'all'", name); list = (aci_user_t) xhash_get(aci, "all"); for(scan = list; scan != NULL; scan = scan->next) if(strcmp(scan->name, name) == 0) return 1; if(type != NULL) { log_debug(ZONE, "checking for '%s' in acl '%s'", name, type); list = (aci_user_t) xhash_get(aci, type); for(scan = list; scan != NULL; scan = scan->next) if(strcmp(scan->name, name) == 0) return 1; } return 0; } /** unload aci table */ void aci_unload(xht aci) { aci_user_t list, user; /* free list of users for each acl*/ if(xhash_iter_first(aci)) do { xhash_iter_get(aci, NULL, NULL, (void *) &list); while (list != NULL) { user = list; list = list->next; free(user->name); free(user); } } while(xhash_iter_next(aci)); xhash_free(aci); return; } ����������������������������������jabberd2-jabberd-2.3.4/router/filter.c��������������������������������������������������������������0000664�0000000�0000000�00000020220�12614627753�0017544�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2006 Tomasz Sterna * * 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, MA02111-1307USA */ #include "router.h" #include <fnmatch.h> /** filter manager */ void filter_unload(router_t r) { acl_t acl, tmp; acl = r->filter; while(acl != NULL) { tmp = acl->next; if(acl->from != NULL) free(acl->from); if(acl->to != NULL) free(acl->to); if(acl->what != NULL) free(acl->what); if(acl->redirect != NULL) free(acl->redirect); free(acl); acl = tmp; } r->filter = NULL; } int filter_load(router_t r) { const char *filterfile; FILE *f; long size; char *buf; nad_t nad; int i, nfilters, filter, from, to, what, redirect, error, log; acl_t list_tail, acl; log_debug(ZONE, "loading filter"); if(r->filter != NULL) filter_unload(r); filterfile = config_get_one(r->config, "aci.filter", 0); if(filterfile == NULL) filterfile = CONFIG_DIR "/router-filter.xml"; f = fopen(filterfile, "rb"); if(f == NULL) { log_write(r->log, LOG_NOTICE, "couldn't open filter file %s: %s", filterfile, strerror(errno)); r->filter_load = time(NULL); return 0; } fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); buf = (char *) malloc(sizeof(char) * size); if (fread(buf, 1, size, f) != size || ferror(f)) { log_write(r->log, LOG_ERR, "couldn't read from filter file: %s", strerror(errno)); free(buf); fclose(f); return 1; } fclose(f); nad = nad_parse(buf, size); if(nad == NULL) { log_write(r->log, LOG_ERR, "couldn't parse filter file"); free(buf); return 1; } free(buf); list_tail = NULL; log_debug(ZONE, "building filter list"); nfilters = 0; filter = nad_find_elem(nad, 0, -1, "rule", 1); while(filter >= 0) { from = nad_find_attr(nad, filter, -1, "from", NULL); to = nad_find_attr(nad, filter, -1, "to", NULL); what = nad_find_attr(nad, filter, -1, "what", NULL); redirect = nad_find_attr(nad, filter, -1, "redirect", NULL); error = nad_find_attr(nad, filter, -1, "error", NULL); log = nad_find_attr(nad, filter, -1, "log", NULL); acl = (acl_t) calloc(1, sizeof(struct acl_s)); if(from >= 0) { if (NAD_AVAL_L(nad, from) == 0 ) acl->from = NULL; else { acl->from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, from) + 1)); sprintf(acl->from, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from)); } } if(to >= 0) { if (NAD_AVAL_L(nad, to) == 0 ) acl->to = NULL; else { acl->to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, to) + 1)); sprintf(acl->to, "%.*s", NAD_AVAL_L(nad, to), NAD_AVAL(nad, to)); } } if(what >= 0) { if (NAD_AVAL_L(nad, what) == 0 || strncmp(NAD_AVAL(nad, what), "*", NAD_AVAL_L(nad, what)) == 0) acl->what = NULL; else { acl->what = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, what) + 1)); sprintf(acl->what, "%.*s", NAD_AVAL_L(nad, what), NAD_AVAL(nad, what)); } } if(redirect >= 0) { if (NAD_AVAL_L(nad, redirect) == 0) acl->redirect = NULL; else { acl->redirect_len = NAD_AVAL_L(nad, redirect); acl->redirect = (char *) malloc(sizeof(char) * (acl->redirect_len + 1)); sprintf(acl->redirect, "%.*s", acl->redirect_len, NAD_AVAL(nad, redirect)); acl->error = stanza_err_REDIRECT; } } if(error >= 0) { acl->error = stanza_err_NOT_ALLOWED; for(i=0; _stanza_errors[i].code != NULL; i++) { if(_stanza_errors[i].name != NULL && strncmp(_stanza_errors[i].name, NAD_AVAL(nad, error), NAD_AVAL_L(nad, error)) == 0) { acl->error = stanza_err_BAD_REQUEST + i; break; } } } if(log >= 0) { acl->log = ! strncasecmp(NAD_AVAL(nad, log), "YES", NAD_AVAL_L(nad, log)); acl->log |= ! strncasecmp(NAD_AVAL(nad, log), "ON", NAD_AVAL_L(nad, log)); } if(list_tail != NULL) { list_tail->next = acl; list_tail = acl; } /* record the head of the list */ if(r->filter == NULL) { r->filter = acl; list_tail = acl; } log_debug(ZONE, "added %s rule: from=%s, to=%s, what=%s, redirect=%s, error=%d, log=%s", (acl->error?"deny":"allow"), acl->from, acl->to, acl->what, acl->redirect, acl->error, (acl->log?"yes":"no")); nfilters++; filter = nad_find_elem(nad, filter, -1, "rule", 0); } nad_free(nad); log_write(r->log, LOG_NOTICE, "loaded filters (%d rules)", nfilters); r->filter_load = time(NULL); return 0; } int filter_packet(router_t r, nad_t nad) { acl_t acl; int ato, afrom, error = 0; char *cur, *to = NULL, *from = NULL; ato = nad_find_attr(nad, 1, -1, "to", NULL); afrom = nad_find_attr(nad, 1, -1, "from", NULL); if(ato >= 0 && NAD_AVAL_L(nad,ato) > 0) { to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, ato) + 1)); sprintf(to, "%.*s", NAD_AVAL_L(nad, ato), NAD_AVAL(nad, ato)); cur = strstr(to, "@"); /* skip node part */ if(cur != NULL) cur = strstr(cur, "/"); else cur = strstr(to, "/"); if(cur != NULL) *cur = '\0'; /* remove the resource part */ } if(afrom >= 0 && NAD_AVAL_L(nad,afrom) > 0) { from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, afrom) + 1)); sprintf(from, "%.*s", NAD_AVAL_L(nad, afrom), NAD_AVAL(nad, afrom)); cur = strstr(from, "@"); if(cur != NULL) cur = strstr(cur, "/"); else cur = strstr(from, "/"); if(cur != NULL) *cur = '\0'; } for(acl = r->filter; acl != NULL; acl = acl->next) { if( from == NULL && acl->from != NULL) continue; /* no match if NULL matched vs not-NULL */ if( to == NULL && acl->to != NULL ) continue; if( from != NULL && acl->from == NULL) continue; /* no match if not-NULL matched vs NULL */ if( to != NULL && acl->to == NULL ) continue; if( from != NULL && acl->from != NULL && fnmatch(acl->from, from, 0) != 0 ) continue; /* do filename-like match */ if( to != NULL && acl->to != NULL && fnmatch(acl->to, to, 0) != 0 ) continue; if( acl->what != NULL && nad_find_elem_path(nad, 0, -1, acl->what) < 0 ) continue; /* match packet type */ log_debug(ZONE, "matched packet %s->%s vs rule (%s %s->%s)", from, to, acl->what, acl->from, acl->to); if (acl->log) { if (acl->redirect) log_write(r->log, LOG_NOTICE, "filter: redirect packet from=%s to=%s - rule (from=%s to=%s what=%s), new to=%s", from, to, acl->from, acl->to, acl->what, acl->redirect); else log_write(r->log, LOG_NOTICE, "filter: %s packet from=%s to=%s - rule (from=%s to=%s what=%s)",(acl->error?"deny":"allow"), from, to, acl->from, acl->to, acl->what); } if (acl->redirect) nad_set_attr(nad, 0, -1, "to", acl->redirect, acl->redirect_len); error = acl->error; break; } if(to != NULL) free(to); if(from != NULL) free(from); return error; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/main.c����������������������������������������������������������������0000664�0000000�0000000�00000041424�12614627753�0017214�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "router.h" static sig_atomic_t router_shutdown = 0; static sig_atomic_t router_logrotate = 0; static void router_signal(int signum) { router_shutdown = 1; } static void router_signal_hup(int signum) { router_logrotate = 1; } static void router_signal_usr1(int signum) { set_debug_flag(0); } static void router_signal_usr2(int signum) { set_debug_flag(1); } /** store the process id */ static void _router_pidfile(router_t r) { const char *pidfile; FILE *f; pid_t pid; pidfile = config_get_one(r->config, "pidfile", 0); if(pidfile == NULL) return; pid = getpid(); if((f = fopen(pidfile, "w+")) == NULL) { log_write(r->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno)); return; } if(fprintf(f, "%d", pid) < 0) { log_write(r->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno)); fclose(f); return; } fclose(f); log_write(r->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile); } /** pull values out of the config file */ static void _router_config_expand(router_t r) { const char *str, *ip, *mask, *name, *target; config_elem_t elem; int i; alias_t alias; r->id = config_get_one(r->config, "id", 0); if(r->id == NULL) r->id = "router"; set_debug_log_from_config(r->config); r->log_type = log_STDOUT; if(config_get(r->config, "log") != NULL) { if((str = config_get_attr(r->config, "log", 0, "type")) != NULL) { if(strcmp(str, "file") == 0) r->log_type = log_FILE; else if(strcmp(str, "syslog") == 0) r->log_type = log_SYSLOG; } } if(r->log_type == log_SYSLOG) { r->log_facility = config_get_one(r->config, "log.facility", 0); r->log_ident = config_get_one(r->config, "log.ident", 0); if(r->log_ident == NULL) r->log_ident = "jabberd/router"; } else if(r->log_type == log_FILE) r->log_ident = config_get_one(r->config, "log.file", 0); r->local_ip = config_get_one(r->config, "local.ip", 0); if(r->local_ip == NULL) r->local_ip = "0.0.0.0"; r->local_port = j_atoi(config_get_one(r->config, "local.port", 0), 5347); r->local_secret = config_get_one(r->config, "local.secret", 0); r->local_pemfile = config_get_one(r->config, "local.pemfile", 0); r->local_private_key_password = config_get_one(r->config, "local.private_key_password", 0); r->local_ciphers = config_get_one(r->config, "local.ciphers", 0); r->io_max_fds = j_atoi(config_get_one(r->config, "io.max_fds", 0), 1024); elem = config_get(r->config, "io.limits.bytes"); if(elem != NULL) { r->byte_rate_total = j_atoi(elem->values[0], 0); if(r->byte_rate_total != 0) { r->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5); r->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } elem = config_get(r->config, "io.limits.connects"); if(elem != NULL) { r->conn_rate_total = j_atoi(elem->values[0], 0); if(r->conn_rate_total != 0) { r->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5); r->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } str = config_get_one(r->config, "io.access.order", 0); if(str == NULL || strcmp(str, "deny,allow") != 0) r->access = access_new(0); else r->access = access_new(1); elem = config_get(r->config, "io.access.allow"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_allow(r->access, ip, mask); } } elem = config_get(r->config, "io.access.deny"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_deny(r->access, ip, mask); } } /* aliases */ elem = config_get(r->config, "aliases.alias"); if(elem != NULL) for(i = 0; i < elem->nvalues; i++) { name = j_attr((const char **) elem->attrs[i], "name"); target = j_attr((const char **) elem->attrs[i], "target"); if(name == NULL || target == NULL) continue; alias = (alias_t) calloc(1, sizeof(struct alias_st)); alias->name = name; alias->target = target; alias->next = r->aliases; r->aliases = alias; } /* message logging to flat file */ r->message_logging_enabled = j_atoi(config_get_one(r->config, "message_logging.enabled", 0), 0); r->message_logging_file = config_get_one(r->config, "message_logging.file", 0); r->check_interval = j_atoi(config_get_one(r->config, "check.interval", 0), 60); r->check_keepalive = j_atoi(config_get_one(r->config, "check.keepalive", 0), 0); } static int _router_sx_sasl_callback(int cb, void *arg, void ** res, sx_t s, void *cbarg) { router_t r = (router_t) cbarg; sx_sasl_creds_t creds; static char buf[1024]; char *pass; switch(cb) { case sx_sasl_cb_GET_REALM: strcpy(buf, "jabberd-router"); *res = (void *)buf; return sx_sasl_ret_OK; break; case sx_sasl_cb_GET_PASS: creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); pass = xhash_get(r->users, creds->authnid); if(pass == NULL) return sx_sasl_ret_FAIL; *res = (void *)pass; return sx_sasl_ret_OK; break; case sx_sasl_cb_CHECK_PASS: creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); pass = xhash_get(r->users, creds->authnid); if(pass == NULL || strcmp(creds->pass, pass) != 0) return sx_sasl_ret_OK; return sx_sasl_ret_FAIL; break; case sx_sasl_cb_CHECK_AUTHZID: creds = (sx_sasl_creds_t) arg; if (strcmp(creds->authnid, creds->authzid) == 0) return sx_sasl_ret_OK; else return sx_sasl_ret_FAIL; break; case sx_sasl_cb_CHECK_MECH: if (strcasecmp((char *)arg,"DIGEST-MD5")==0) return sx_sasl_ret_OK; return sx_sasl_ret_FAIL; break; default: break; } return sx_sasl_ret_FAIL; } static void _router_time_checks(router_t r) { component_t target; time_t now; union xhashv xhv; now = time(NULL); /* loop the components and distribute an space on idle connections*/ if(xhash_iter_first(r->components)) do { xhv.comp_val = &target; xhash_iter_get(r->components, NULL, NULL, xhv.val); if(r->check_keepalive > 0 && target->last_activity > 0 && now > target->last_activity + r->check_keepalive && target->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", target->fd->fd); sx_raw_write(target->s, " ", 1); } } while(xhash_iter_next(r->components)); return; } JABBER_MAIN("jabberd2router", "Jabber 2 Router", "Jabber Open Source Server: Router", NULL) { router_t r; char *config_file; int optchar; rate_t rt; component_t comp; union xhashv xhv; int close_wait_max; const char *cli_id = 0; #ifdef POOL_DEBUG time_t pool_time = 0; #endif #ifdef HAVE_UMASK umask((mode_t) 0027); #endif srand(time(NULL)); #ifdef HAVE_WINSOCK2_H /* get winsock running */ { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* !!! tell user that we couldn't find a usable winsock dll */ return 0; } } #endif jabber_signal(SIGINT, router_signal); jabber_signal(SIGTERM, router_signal); #ifdef SIGHUP jabber_signal(SIGHUP, router_signal_hup); #endif #ifdef SIGPIPE jabber_signal(SIGPIPE, SIG_IGN); #endif jabber_signal(SIGUSR1, router_signal_usr1); jabber_signal(SIGUSR2, router_signal_usr2); r = (router_t) calloc(1, sizeof(struct router_st)); /* load our config */ r->config = config_new(); config_file = CONFIG_DIR "/router.xml"; /* cmdline parsing */ while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0) { switch(optchar) { case 'c': config_file = optarg; break; case 'D': #ifdef DEBUG set_debug_flag(1); #else printf("WARN: Debugging not enabled. Ignoring -D.\n"); #endif break; case 'i': cli_id = optarg; break; case 'h': case '?': default: fputs( "router - jabberd router (" VERSION ")\n" "Usage: router <options>\n" "Options are:\n" " -c <config> config file to use [default: " CONFIG_DIR "/router.xml]\n" " -i id Override <id> config element\n" #ifdef DEBUG " -D Show debug output\n" #endif , stdout); config_free(r->config); free(r); return 1; } } if(config_load_with_id(r->config, config_file, cli_id) != 0) { fputs("router: couldn't load config, aborting\n", stderr); config_free(r->config); free(r); return 2; } _router_config_expand(r); r->log = log_new(r->log_type, r->log_ident, r->log_facility); log_write(r->log, LOG_NOTICE, "starting up"); _router_pidfile(r); user_table_load(r); r->aci = aci_load(r); if(filter_load(r)) exit(1); r->conn_rates = xhash_new(101); r->components = xhash_new(101); r->routes = xhash_new(101); r->log_sinks = xhash_new(101); r->dead = jqueue_new(); r->closefd = jqueue_new(); r->deadroutes = jqueue_new(); r->sx_env = sx_env_new(); #ifdef HAVE_SSL if(r->local_pemfile != NULL) { r->sx_ssl = sx_env_plugin(r->sx_env, sx_ssl_init, NULL, r->local_pemfile, NULL, NULL, r->local_private_key_password, r->local_ciphers); if(r->sx_ssl == NULL) log_write(r->log, LOG_ERR, "failed to load SSL pemfile, SSL disabled"); } #endif /* get sasl online */ r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, "jabberd-router", _router_sx_sasl_callback, (void *) r); if(r->sx_sasl == NULL) { log_write(r->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); } r->mio = mio_new(r->io_max_fds); r->fd = mio_listen(r->mio, r->local_port, r->local_ip, router_mio_callback, (void *) r); if(r->fd == NULL) { log_write(r->log, LOG_ERR, "[%s, port=%d] unable to listen (%s)", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR)); exit(1); } log_write(r->log, LOG_NOTICE, "[%s, port=%d] listening for incoming connections", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR)); while(!router_shutdown) { mio_run(r->mio, 5); if(router_logrotate) { set_debug_log_from_config(r->config); log_write(r->log, LOG_NOTICE, "reopening log ..."); log_free(r->log); r->log = log_new(r->log_type, r->log_ident, r->log_facility); log_write(r->log, LOG_NOTICE, "log started"); log_write(r->log, LOG_NOTICE, "reloading filter ..."); filter_unload(r); filter_load(r); log_write(r->log, LOG_NOTICE, "reloading users ..."); user_table_unload(r); user_table_load(r); router_logrotate = 0; } /* cleanup dead sx_ts */ while(jqueue_size(r->dead) > 0) sx_free((sx_t) jqueue_pull(r->dead)); /* cleanup closed fd */ while(jqueue_size(r->closefd) > 0) mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd)); /* cleanup dead routes */ while(jqueue_size(r->deadroutes) > 0) routes_free((routes_t) jqueue_pull(r->deadroutes)); /* time checks */ if(r->check_interval > 0 && time(NULL) >= r->next_check) { log_debug(ZONE, "running time checks"); _router_time_checks(r); r->next_check = time(NULL) + r->check_interval; log_debug(ZONE, "next time check at %d", r->next_check); } #ifdef POOL_DEBUG if(time(NULL) > pool_time + 60) { pool_stat(1); pool_time = time(NULL); } #endif } log_write(r->log, LOG_NOTICE, "shutting down"); /* stop accepting new connections */ if (r->fd) { // HACK Do not call router_mio_callback(action_CLOSE) for listenning socket, Just close it and forget. mio_app(r->mio, r->fd, NULL, NULL); mio_close(r->mio, r->fd); } /* * !!! issue remote shutdowns to each service, so they can clean up. * we'll need to mio_run() until they all disconnect, so that * the the last packets (eg sm presence unavailables) can get to * their destinations */ close_wait_max = 30; /* time limit for component shutdown */ /* close connections to components */ xhv.comp_val = &comp; if(xhash_iter_first(r->components)) do { xhash_iter_get(r->components, NULL, NULL, xhv.val); log_debug(ZONE, "close component %p", comp); if (comp) sx_close(comp->s); mio_run(r->mio, 5000); if (1 > close_wait_max--) break; sleep(1); while(jqueue_size(r->closefd) > 0) mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd)); } while (xhash_iter_next(r->components)); xhash_free(r->components); /* cleanup dead sx_ts */ while(jqueue_size(r->dead) > 0) sx_free((sx_t) jqueue_pull(r->dead)); jqueue_free(r->dead); while(jqueue_size(r->closefd) > 0) mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd)); jqueue_free(r->closefd); /* cleanup dead routes - probably just showed up (route was just closed) */ while(jqueue_size(r->deadroutes) > 0) routes_free((routes_t) jqueue_pull(r->deadroutes)); jqueue_free(r->deadroutes); /* walk r->conn_rates and free */ xhv.rt_val = &rt; if(xhash_iter_first(r->conn_rates)) do { xhash_iter_get(r->conn_rates, NULL, NULL, xhv.val); rate_free(rt); } while(xhash_iter_next(r->conn_rates)); xhash_free(r->conn_rates); xhash_free(r->log_sinks); /* walk r->routes and free */ if (xhash_iter_first(r->routes)) do { routes_t p; xhash_iter_get(r->routes, NULL, NULL, (void *) &p); routes_free(p); } while(xhash_iter_next(r->routes)); xhash_free(r->routes); /* unload users */ user_table_unload(r); /* unload acls */ aci_unload(r->aci); /* unload filter */ filter_unload(r); sx_env_free(r->sx_env); mio_free(r->mio); access_free(r->access); log_free(r->log); config_free(r->config); free(r); #ifdef POOL_DEBUG pool_stat(1); #endif #ifdef HAVE_WINSOCK2_H WSACleanup(); #endif return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/router.c��������������������������������������������������������������0000664�0000000�0000000�00000123472�12614627753�0017614�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "router.h" #define MAX_JID 3072 // node(1023) + '@'(1) + domain(1023) + '/'(1) + resource(1023) + '\0'(1) #define MAX_MESSAGE 65535 #define SECS_PER_DAY 86400 #define BYTES_PER_MEG 1048576 /** info for broadcasts */ typedef struct broadcast_st { router_t r; component_t src; nad_t nad; } *broadcast_t; /** broadcast a packet */ static void _router_broadcast(const char *key, int keylen, void *val, void *arg) { int i; broadcast_t bc = (broadcast_t) arg; routes_t routes = (routes_t) val; for(i = 0; i < routes->ncomp; i++) { /* I don't care about myself or the elderly (!?) */ if(routes->comp[i] == bc->src || routes->comp[i]->legacy) continue; sx_nad_write(routes->comp[i]->s, nad_copy(bc->nad)); } } /** domain advertisement */ static void _router_advertise(router_t r, const char *domain, component_t src, int unavail) { struct broadcast_st bc; int ns; log_debug(ZONE, "advertising %s to all routes (unavail=%d)", domain, unavail); bc.r = r; bc.src = src; /* create a new packet */ bc.nad = nad_new(); ns = nad_add_namespace(bc.nad, uri_COMPONENT, NULL); nad_append_elem(bc.nad, ns, "presence", 0); nad_append_attr(bc.nad, -1, "from", domain); if(unavail) nad_append_attr(bc.nad, -1, "type", "unavailable"); xhash_walk(r->routes, _router_broadcast, (void *) &bc); nad_free(bc.nad); } /** tell a component about all the others */ static void _router_advertise_reverse(const char *key, int keylen, void *val, void *arg) { component_t dest = (component_t) arg; routes_t routes = (routes_t) val; int el, ns, i; nad_t nad; assert((int) (routes->name != NULL)); assert((int) (routes->comp != NULL)); assert(routes->ncomp); /* don't tell me about myself */ for(i = 0; i < routes->ncomp; i++) if(routes->comp[i] == dest) return; log_debug(ZONE, "informing component about %.*s", keylen, key); /* create a new packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); el = nad_append_elem(nad, ns, "presence", 0); nad_set_attr(nad, el, -1, "from", key, keylen); sx_nad_write(dest->s, nad); } static void _router_process_handshake(component_t comp, nad_t nad) { char *hash; int hashlen; /* must have a hash as cdata */ if(NAD_CDATA_L(nad, 0) != 40) { log_debug(ZONE, "handshake isn't long enough to be a sha1 hash"); sx_error(comp->s, stream_err_NOT_AUTHORIZED, "handshake isn't long enough to be a sha1 hash"); sx_close(comp->s); nad_free(nad); return; } /* make room for shahash_r to work .. needs at least 41 chars */ hashlen = strlen(comp->s->id) + strlen(comp->r->local_secret) + 1; if(hashlen < 41) hashlen = 41; /* build the creds and hash them */ hash = (char *) malloc(sizeof(char) * hashlen); sprintf(hash, "%s%s", comp->s->id, comp->r->local_secret); shahash_r(hash, hash); /* check */ log_debug(ZONE, "checking their hash %.*s against our hash %s", 40, NAD_CDATA(nad, 0), hash); if(strncmp(hash, NAD_CDATA(nad, 0), 40) == 0) { log_debug(ZONE, "handshake succeeded"); free(hash); /* respond */ nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(comp->s, nad); sx_auth(comp->s, "handshake", comp->s->req_to); return; } log_debug(ZONE, "auth failed"); free(hash); /* failed, let them know */ sx_error(comp->s, stream_err_NOT_AUTHORIZED, "hash didn't match, auth failed"); sx_close(comp->s); nad_free(nad); } void routes_free(routes_t routes) { if(routes->name) free((void*)routes->name); if(routes->comp) free(routes->comp); free(routes); } static int _route_add(xht hroutes, const char *name, component_t comp, route_type_t rtype) { routes_t routes; routes = xhash_get(hroutes, name); if(routes == NULL) { routes = (routes_t) calloc(1, sizeof(struct routes_st)); routes->name = strdup(name); routes->rtype = rtype; } routes->comp = (component_t *) realloc(routes->comp, sizeof(component_t *) * (routes->ncomp + 1)); routes->comp[routes->ncomp] = comp; routes->ncomp++; xhash_put(hroutes, routes->name, (void *) routes); if(routes->rtype != rtype) log_write(comp->r->log, LOG_ERR, "Mixed route types for '%s' bind request", name); return routes->ncomp; } static void _route_remove(xht hroutes, const char *name, component_t comp) { routes_t routes; int i; routes = xhash_get(hroutes, name); if(routes == NULL) return; if(routes->ncomp > 1) { for(i = 0; i < routes->ncomp; i++) { if(routes->comp[i] == comp) { if(i != routes->ncomp - 1) { routes->comp[i] = routes->comp[routes->ncomp - 1]; } routes->ncomp--; } } } else { jqueue_push(comp->r->deadroutes, (void *) routes, 0); xhash_zap(hroutes, name); } } static void _router_process_bind(component_t comp, nad_t nad) { int attr, multi, n; jid_t name; alias_t alias; char *user, *c; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on bind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } user = strdup(comp->s->auth_id); c = strchr(user, '@'); if(c != NULL) *c = '\0'; if(strcmp(user, name->domain) != 0 && !aci_check(comp->r->aci, "bind", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but their username (%s) is not permitted to bind other names", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } multi = nad_find_attr(nad, 0, -1, "multi", NULL); if(xhash_get(comp->r->routes, name->domain) != NULL && multi < 0) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but it's already bound", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but that name is aliased", comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } /* default route */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "default", 1) >= 0) { if(!aci_check(comp->r->aci, "default-route", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but their username (%s) is not permitted to set a default route", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } if(comp->r->default_route != NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but one already exists", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as default route", name->domain); comp->r->default_route = strdup(name->domain); } /* log sinks */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "log", 1) >= 0) { if(!aci_check(comp->r->aci, "log", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as a log sink, but their username (%s) is not permitted to do this", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as log sink", name->domain); xhash_put(comp->r->log_sinks, pstrdup(xhash_pool(comp->r->log_sinks), name->domain), (void *) comp); } free(user); n = _route_add(comp->r->routes, name->domain, comp, multi<0?route_SINGLE:route_MULTI_TO); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), name->domain), (void *) comp); if(n>1) log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", name->domain, n, comp->ip, comp->port); else log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", name->domain, comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* advertise name */ _router_advertise(comp->r, name->domain, comp, 0); /* tell the new component about everyone else */ xhash_walk(comp->r->routes, _router_advertise_reverse, (void *) comp); /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, name->domain) == 0) { _route_add(comp->r->routes, name->domain, comp, route_MULTI_TO); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp); log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, name->domain, comp->ip, comp->port); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } /* done with this */ jid_free(name); } static void _router_process_unbind(component_t comp, nad_t nad) { int attr; jid_t name; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on unbind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } if(xhash_get(comp->routes, name->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to unbind '%s', but it's not bound to this component", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "404", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } xhash_zap(comp->r->log_sinks, name->domain); _route_remove(comp->r->routes, name->domain, comp); xhash_zap(comp->routes, name->domain); if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain); free((void*)(comp->r->default_route)); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* deadvertise name */ if(xhash_get(comp->r->routes, name->domain) == NULL) _router_advertise(comp->r, name->domain, comp, 1); jid_free(name); } static void _router_comp_write(component_t comp, nad_t nad) { int attr; if(comp->tq != NULL) { log_debug(ZONE, "%s port %d is throttled, jqueueing packet", comp->ip, comp->port); jqueue_push(comp->tq, nad, 0); return; } /* packets go raw to normal components */ if(!comp->legacy) { sx_nad_write(comp->s, nad); return; } log_debug(ZONE, "packet for legacy component, munging"); attr = nad_find_attr(nad, 0, -1, "error", NULL); if(attr >= 0) { if(NAD_AVAL_L(nad, attr) == 3 && strncmp("400", NAD_AVAL(nad, attr), 3) == 0) stanza_error(nad, 1, stanza_err_BAD_REQUEST); else stanza_error(nad, 1, stanza_err_SERVICE_UNAVAILABLE); } sx_nad_write_elem(comp->s, nad, 1); } static void _router_route_log_sink(const char *key, int keylen, void *val, void *arg) { component_t comp = (component_t) val; nad_t nad = (nad_t) arg; log_debug(ZONE, "copying route to '%.*s' (%s, port %d)", keylen, key, comp->ip, comp->port); nad = nad_copy(nad); nad_set_attr(nad, 0, -1, "type", "log", 3); _router_comp_write(comp, nad); } static void _router_process_route(component_t comp, nad_t nad) { int atype, ato, afrom; unsigned int dest; struct jid_st sto, sfrom; jid_static_buf sto_buf, sfrom_buf; jid_t to = NULL, from = NULL; routes_t targets; component_t target; union xhashv xhv; /* init static jid */ jid_static(&sto,&sto_buf); jid_static(&sfrom,&sfrom_buf); if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) { log_debug(ZONE, "dropping error packet, trying to avoid loops"); nad_free(nad); return; } atype = nad_find_attr(nad, 0, -1, "type", NULL); ato = nad_find_attr(nad, 0, -1, "to", NULL); afrom = nad_find_attr(nad, 0, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); if(afrom >= 0) from = jid_reset(&sfrom, NAD_AVAL(nad, afrom), NAD_AVAL_L(nad, afrom)); /* unicast */ if(atype < 0) { if(to == NULL || from == NULL) { log_debug(ZONE, "unicast route with missing or invalid to or from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "unicast route from %s to %s", from->domain, to->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* filter it */ if(comp->r->filter != NULL) { int ret = filter_packet(comp->r, nad); if(ret == stanza_err_REDIRECT) { ato = nad_find_attr(nad, 0, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); } else if(ret > 0) { log_debug(ZONE, "packet filtered out: %s (%s)", _stanza_errors[ret - stanza_err_BAD_REQUEST].name, _stanza_errors[ret - stanza_err_BAD_REQUEST].code); nad_set_attr(nad, 0, -1, "error", _stanza_errors[ret - stanza_err_BAD_REQUEST].code, 3); _router_comp_write(comp, nad); return; } } /* find a target */ targets = xhash_get(comp->r->routes, to->domain); if(targets == NULL) { if(comp->r->default_route != NULL && strcmp(from->domain, comp->r->default_route) == 0) { log_debug(ZONE, "%s is unbound, bouncing", from->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } targets = xhash_get(comp->r->routes, comp->r->default_route); } if(targets == NULL) { log_debug(ZONE, "%s is unbound, and no default route, bouncing", to->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } /* copy to any log sinks */ if(xhash_count(comp->r->log_sinks) > 0) xhash_walk(comp->r->log_sinks, _router_route_log_sink, (void *) nad); /* get route candidate */ if(targets->ncomp == 1) { dest = 0; } else { switch(targets->rtype) { case route_MULTI_TO: ato = nad_find_attr(nad, 1, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { ato = nad_find_attr(nad, 1, -1, "target", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get destination for multiple route: %.*s", len, out); } } break; case route_MULTI_FROM: ato = nad_find_attr(nad, 1, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get source for multiple route: %.*s", len, out); } break; default: log_write(comp->r->log, LOG_ERR, "Multiple components bound to single component route '%s'", targets->name); /* simulate no 'to' info in this case */ } if(to->node == NULL || strlen(to->node) == 0) { /* no node in destination JID - going random */ dest = rand(); log_debug(ZONE, "randomized to %u %% %d = %d", dest, targets->ncomp, dest % targets->ncomp); } else { /* use JID hash */ unsigned char hashval[20]; unsigned int *val; int i; shahash_raw(jid_user(to), hashval); val = (unsigned int *) hashval; dest = *val; for(i=1; i < 20 / (sizeof(unsigned int)/sizeof(unsigned char)); i++, val++) { dest ^= *val; } dest >>= 2; log_debug(ZONE, "JID %s hashed to %u %% %d = %d", jid_user(to), dest, targets->ncomp, dest % targets->ncomp); /* jid_user() calls jid_expand() which may allocate some memory in _user and _full */ if (to->_user != NULL ) free(to->_user); if (to->_full != NULL ) free(to->_full); } dest = dest % targets->ncomp; } target = targets->comp[dest]; /* push it out */ log_debug(ZONE, "writing route for '%s'*%u to %s, port %d", to->domain, dest+1, target->ip, target->port); /* if logging enabled, log messages that match our criteria */ if (comp->r->message_logging_enabled && comp->r->message_logging_file != NULL) { int attr_msg_to; int attr_msg_from; int attr_route_to; int attr_route_from; jid_t jid_msg_from = NULL; jid_t jid_msg_to = NULL; jid_t jid_route_from = NULL; jid_t jid_route_to = NULL; if ((NAD_ENAME_L(nad, 1) == 7 && strncmp("message", NAD_ENAME(nad, 1), 7) == 0) && // has a "message" element ((attr_route_from = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) && ((attr_route_to = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) && ((strncmp(NAD_AVAL(nad, attr_route_to), "c2s", 3)) != 0) && // ignore messages to "c2s" or we'd have dups ((jid_route_from = jid_new(NAD_AVAL(nad, attr_route_from), NAD_AVAL_L(nad, attr_route_from))) != NULL) && // has valid JID source in route ((jid_route_to = jid_new(NAD_AVAL(nad, attr_route_to), NAD_AVAL_L(nad, attr_route_to))) != NULL) && // has valid JID destination in route ((attr_msg_from = nad_find_attr(nad, 1, -1, "from", NULL)) >= 0) && ((attr_msg_to = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0) && ((jid_msg_from = jid_new(NAD_AVAL(nad, attr_msg_from), NAD_AVAL_L(nad, attr_msg_from))) != NULL) && // has valid JID source in message ((jid_msg_to = jid_new(NAD_AVAL(nad, attr_msg_to), NAD_AVAL_L(nad, attr_msg_to))) != NULL)) // has valid JID dest in message { message_log(nad, comp->r, jid_full(jid_msg_from), jid_full(jid_msg_to)); } if (jid_msg_from != NULL) jid_free(jid_msg_from); if (jid_msg_to != NULL) jid_free(jid_msg_to); if (jid_route_from != NULL) jid_free(jid_route_from); if (jid_route_to != NULL) jid_free(jid_route_to); } _router_comp_write(target, nad); return; } /* broadcast */ if(NAD_AVAL_L(nad, atype) == 9 && strncmp("broadcast", NAD_AVAL(nad, atype), 9) == 0) { if(from == NULL) { log_debug(ZONE, "broadcast route with missing or invalid from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "broadcast route from %s", from->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* loop the components and distribute */ if(xhash_iter_first(comp->r->components)) do { xhv.comp_val = &target; xhash_iter_get(comp->r->components, NULL, NULL, xhv.val); if(target != comp) { log_debug(ZONE, "writing broadcast to %s, port %d", target->ip, target->port); _router_comp_write(target, nad_copy(nad)); } } while(xhash_iter_next(comp->r->components)); nad_free(nad); return; } log_debug(ZONE, "unknown route type '%.*s', dropping", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype)); nad_free(nad); } static void _router_process_throttle(component_t comp, nad_t nad) { jqueue_t tq; nad_t pkt; if(comp->tq == NULL) { _router_comp_write(comp, nad); log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] throttling packets on request", comp->ip, comp->port); comp->tq = jqueue_new(); } else { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] unthrottling packets on request", comp->ip, comp->port); tq = comp->tq; comp->tq = NULL; _router_comp_write(comp, nad); while((pkt = jqueue_pull(tq)) != NULL) _router_comp_write(comp, pkt); jqueue_free(tq); } } static int _router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { component_t comp = (component_t) arg; sx_buf_t buf = (sx_buf_t) data; int rlen, len, attr, ns, sns, n; sx_error_t *sxe; nad_t nad; struct jid_st sto, sfrom; jid_static_buf sto_buf, sfrom_buf; jid_t to, from; alias_t alias; /* init static jid */ jid_static(&sto,&sto_buf); jid_static(&sfrom,&sfrom_buf); switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(comp->r->mio, comp->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(comp->r->mio, comp->fd); break; case event_READ: log_debug(ZONE, "reading from %d", comp->fd->fd); /* check rate limits */ if(comp->rate != NULL) { if(rate_check(comp->rate) == 0) { /* inform the app if we haven't already */ if(!comp->rate_log) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] is being byte rate limited", comp->ip, comp->port); comp->rate_log = 1; } log_debug(ZONE, "%d is throttled, delaying read", comp->fd->fd); buf->len = 0; return 0; } /* find out how much we can have */ rlen = rate_left(comp->rate); if(rlen > buf->len) rlen = buf->len; } /* no limit, just read as much as we can */ else rlen = buf->len; /* do the read */ len = recv(comp->fd->fd, buf->data, rlen, 0); /* update rate limits */ if(comp->rate != NULL && len > 0) { comp->rate_log = 0; rate_add(comp->rate, len); } if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_debug(ZONE, "read failed: %s", strerror(errno)); sx_kill(comp->s); return -1; } else if(len == 0) { /* they went away */ sx_kill(comp->s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", comp->fd->fd); len = send(comp->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_debug(ZONE, "write failed: %s", strerror(errno)); sx_kill(comp->s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] error: %s (%s)", comp->ip, comp->port, sxe->generic, sxe->specific); break; case event_STREAM: /* legacy check */ if(s->ns == NULL || strcmp("jabber:component:accept", s->ns) != 0) return 0; /* component, old skool */ comp->legacy = 1; /* enabled? */ if(comp->r->local_secret == NULL) { sx_error(s, stream_err_INVALID_NAMESPACE, "support for legacy components not available"); /* !!! correct error? */ sx_close(s); return 0; } /* sanity */ if(s->req_to == NULL) { sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header"); sx_close(s); return 0; } break; case event_OPEN: log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] authenticated as %s", comp->ip, comp->port, comp->s->auth_id); /* make a route for legacy components */ if(comp->legacy) { for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, s->req_to) == 0) { sx_error(s, stream_err_HOST_UNKNOWN, "requested name is aliased"); /* !!! correct error? */ sx_close(s); return 0; } n = _route_add(comp->r->routes, s->req_to, comp, route_MULTI_FROM); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), s->req_to), (void *) comp); if(n>1) log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", s->req_to, n, comp->ip, comp->port); else log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", s->req_to, comp->ip, comp->port); /* advertise the name */ _router_advertise(comp->r, s->req_to, comp, 0); /* this is a legacy component, so we don't tell it about other routes */ /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, s->req_to) == 0) { _route_add(comp->r->routes, alias->name, comp, route_MULTI_FROM); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp); log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, s->req_to, comp->ip, comp->port); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } } break; case event_PACKET: nad = (nad_t) data; /* preauth */ if(comp->s->state == state_STREAM) { /* non-legacy components can't do anything before auth */ if(!comp->legacy) { log_debug(ZONE, "stream is preauth, dropping packet"); nad_free(nad); return 0; } /* watch for handshake requests */ if(NAD_ENAME_L(nad, 0) != 9 || strncmp("handshake", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) != 0) { log_debug(ZONE, "unknown preauth packet %.*s, dropping", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } /* process incoming handshakes */ _router_process_handshake(comp, nad); return 0; } /* legacy processing */ if(comp->legacy) { log_debug(ZONE, "packet from legacy component, munging it"); attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_reset(&sto, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'to' address on legacy packet, dropping it"); nad_free(nad); return 0; } attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_reset(&sfrom, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'from' address on legacy packet, dropping it"); nad_free(nad); return 0; } /* rewrite component packets into client packets */ ns = nad_find_namespace(nad, 0, "jabber:component:accept", NULL); if(ns >= 0) { if(nad->elems[0].ns == ns) nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; else { for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; } } ns = nad_find_namespace(nad, 0, uri_CLIENT, NULL); if(ns < 0) { ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad->scope = -1; nad->nss[ns].next = nad->elems[0].ns; nad->elems[0].ns = ns; } nad->elems[0].my_ns = ns; /* wrap up the packet */ ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_wrap_elem(nad, 0, ns, "route"); nad_set_attr(nad, 0, -1, "to", to->domain, 0); nad_set_attr(nad, 0, -1, "from", from->domain, 0); } /* top element must be router scoped */ if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) { log_debug(ZONE, "invalid packet namespace, dropping"); nad_free(nad); return 0; } /* bind a name to this component */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp("bind", NAD_ENAME(nad, 0), 4) == 0) { _router_process_bind(comp, nad); return 0; } /* unbind a name from this component */ if(NAD_ENAME_L(nad, 0) == 6 && strncmp("unbind", NAD_ENAME(nad, 0), 6) == 0) { _router_process_unbind(comp, nad); return 0; } /* route packets */ if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) { _router_process_route(comp, nad); return 0; } /* throttle packets */ if(NAD_ENAME_L(nad, 0) == 8 && strncmp("throttle", NAD_ENAME(nad, 0), 8) == 0) { _router_process_throttle(comp, nad); return 0; } log_debug(ZONE, "unknown packet, dropping"); nad_free(nad); return 0; case event_CLOSED: { /* close comp->fd by putting it in closefd ... unless it is already there */ _jqueue_node_t n; for (n = comp->r->closefd->front; n != NULL; n = n->prev) if (n->data == comp->fd) break; if (!n) jqueue_push(comp->r->closefd, (void *) comp->fd, 0 /*priority*/); return 0; } } return 0; } static int _router_accept_check(router_t r, mio_fd_t fd, const char *ip) { rate_t rt; if(access_check(r->access, ip) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd->fd, ip); return 1; } if(r->conn_rate_total != 0) { rt = (rate_t) xhash_get(r->conn_rates, ip); if(rt == NULL) { rt = rate_new(r->conn_rate_total, r->conn_rate_seconds, r->conn_rate_wait); xhash_put(r->conn_rates, pstrdup(xhash_pool(r->conn_rates), ip), (void *) rt); } if(rate_check(rt) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] is being rate limited", fd->fd, ip); return 1; } rate_add(rt, 1); } return 0; } static void _router_route_unbind_walker(const char *key, int keylen, void *val, void *arg) { component_t comp = (component_t) arg; char * local_key; xhash_zapx(comp->r->log_sinks, key, keylen); local_key = (char *) malloc(keylen + 1); memcpy(local_key, key, keylen); local_key[keylen] = 0; _route_remove(comp->r->routes, local_key, comp); xhash_zapx(comp->routes, key, keylen); if(comp->r->default_route != NULL && strlen(comp->r->default_route) == keylen && strncmp(key, comp->r->default_route, keylen) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%.*s] default route offline", keylen, key); free((void*)(comp->r->default_route)); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%.*s] offline", keylen, key); /* deadvertise name */ if(xhash_getx(comp->r->routes, key, keylen) == NULL) _router_advertise(comp->r, local_key, comp, 1); free(local_key); } int router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { component_t comp = (component_t) arg; router_t r = (router_t) arg; struct sockaddr_storage sa; socklen_t namelen = sizeof(sa); int port, nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); /* they did something */ comp->last_activity = time(NULL); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(comp->s); return 0; } return sx_can_read(comp->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); /* update activity timestamp */ comp->last_activity = time(NULL); return sx_can_write(comp->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); r = comp->r; log_write(r->log, LOG_NOTICE, "[%s, port=%d] disconnect", comp->ip, comp->port); /* unbind names */ xhash_walk(comp->routes, _router_route_unbind_walker, (void *) comp); /* deregister component */ xhash_zap(r->components, comp->ipport); xhash_free(comp->routes); if(comp->tq != NULL) /* !!! bounce packets */ jqueue_free(comp->tq); rate_free(comp->rate); jqueue_push(comp->r->dead, (void *) comp->s, 0); free(comp); break; case action_ACCEPT: log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(r->log, LOG_NOTICE, "[%s, port=%d] connect", (char *) data, port); if(_router_accept_check(r, fd, (char *) data) != 0) return 1; comp = (component_t) calloc(1, sizeof(struct component_st)); comp->r = r; comp->fd = fd; snprintf(comp->ip, INET6_ADDRSTRLEN, "%s", (char *) data); comp->port = port; snprintf(comp->ipport, INET6_ADDRSTRLEN + 6, "%s:%d", comp->ip, comp->port); comp->s = sx_new(r->sx_env, fd->fd, _router_sx_callback, (void *) comp); mio_app(m, fd, router_mio_callback, (void *) comp); if(r->byte_rate_total != 0) comp->rate = rate_new(r->byte_rate_total, r->byte_rate_seconds, r->byte_rate_wait); comp->routes = xhash_new(51); /* register component */ log_debug(ZONE, "new component (%p) \"%s\"", comp, comp->ipport); xhash_put(r->components, comp->ipport, (void *) comp); #ifdef HAVE_SSL sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER); #else sx_server_init(comp->s, SX_SASL_OFFER); #endif break; } return 0; } int message_log(nad_t nad, router_t r, const char *msg_from, const char *msg_to) { time_t t; struct tm *time_pos; char timestamp[25]; struct stat filestat; FILE *message_file; short int new_msg_file = 0; int i; int nad_body_len = 0; char *nad_body = NULL; int elem; assert((int) (nad != NULL)); // Find the message body elem = nad_find_elem(nad, 0, -1, "message", 1); if (elem >= 0) { elem = nad_find_elem(nad, elem, -1, "body", 1); } // Don't log anything if we found no NAD body if (elem == -1) { return 0; } nad_body_len = NAD_CDATA_L(nad, elem); nad_body = NAD_CDATA(nad, elem); // temporary replace line endings with 0x01, ASCII: <control> SOH <start of heading> for (i = 0; i < nad_body_len; i++) { if (nad_body[i] == '\n') { nad_body[i] = 0x01; } } // Log our message umask((mode_t) 0077); if (stat(r->message_logging_file, &filestat)) { new_msg_file = 1; } if ((message_file = fopen(r->message_logging_file, "a")) == NULL) { log_write(r->log, LOG_ERR, "Unable to open message log for writing: %s", strerror(errno)); return 1; } if (new_msg_file) { if (! fprintf(message_file, "# This message log is created by the jabberd router.\n")) { log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno)); return 1; } fprintf(message_file, "# See router.xml for logging options.\n"); fprintf(message_file, "# Format: DateTime FromJID ToJID MessageBody<line end>\n"); } /* ISO8601 timestamp */ t = time(NULL); time_pos = localtime(&t); if (strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S%z", time_pos) == 0) { log_write(r->log, LOG_ERR, "strftime failed: %s", strerror(errno)); } elem = fprintf(message_file, "%s %s %s %.*s\n", timestamp, msg_from, msg_to, nad_body_len, nad_body); fclose(message_file); // revert line endings for (i = 0; i < nad_body_len; i++) { if (nad_body[i] == 0x01) { nad_body[i] = '\n'; } } if (!elem) { log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno)); return 1; } return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/router.h��������������������������������������������������������������0000664�0000000�0000000�00000014525�12614627753�0017617�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /*! \mainpage jabberd - Jabber Open Source Server * * \section intro Introduction * * The jabberd project aims to provide an open-source server * implementation of the Jabber protocols for instant messaging * and XML routing. The goal of this project is to provide a * scalable, reliable, efficient and extensible server that * provides a complete set of features and is up to date with * the latest protocol revisions. * * The project web page:\n * http://jabberd2.xiaoka.com/ */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "sx/sx.h" #include "mio/mio.h" #include "util/util.h" #ifdef HAVE_SIGNAL_H # include <signal.h> #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif typedef struct router_st *router_t; typedef struct component_st *component_t; typedef struct routes_st *routes_t; typedef struct alias_st *alias_t; typedef struct acl_s *acl_t; struct acl_s { int error; char *redirect; int redirect_len; char *what; char *from; char *to; int log; acl_t next; }; struct router_st { /** our id */ const char *id; /** config */ config_t config; /** user table */ xht users; time_t users_load; /** user table */ acl_t filter; time_t filter_load; /** logging */ log_t log; /** log data */ log_type_t log_type; const char *log_facility; const char *log_ident; /** how we listen for stuff */ const char *local_ip; int local_port; const char *local_secret; const char *local_pemfile; const char *local_private_key_password; const char *local_ciphers; /** max file descriptors */ int io_max_fds; /** access controls */ access_t access; /** connection rates */ int conn_rate_total; int conn_rate_seconds; int conn_rate_wait; xht conn_rates; /** default byte rates (karma) */ int byte_rate_total; int byte_rate_seconds; int byte_rate_wait; /** sx environment */ sx_env_t sx_env; sx_plugin_t sx_ssl; sx_plugin_t sx_sasl; /** managed io */ mio_t mio; /** listening socket */ mio_fd_t fd; /** time checks */ int check_interval; int check_keepalive; time_t next_check; /** attached components, key is 'ip:port', var is component_t */ xht components; /** valid routes, key is route name (packet "to" address), var is component_t */ xht routes; /** default route, only one */ const char *default_route; /** log sinks, key is route name, var is component_t */ xht log_sinks; /** configured aliases */ alias_t aliases; /** access control lists */ xht aci; /** list of sx_t waiting to be cleaned up */ jqueue_t dead; /** list of mio_fd_t waiting to be closed */ jqueue_t closefd; /** list of routes_t waiting to be cleaned up */ jqueue_t deadroutes; /** simple message logging */ int message_logging_enabled; const char *message_logging_file; }; /** a single component */ struct component_st { router_t r; /** file descriptor */ mio_fd_t fd; /** remote ip and port */ char ip[INET6_ADDRSTRLEN]; int port; /** ip:port pair */ char ipport[INET6_ADDRSTRLEN + 6]; /** our stream */ sx_t s; /** rate limits */ rate_t rate; int rate_log; /** valid routes to this component, key is route name */ xht routes; /** true if this is an old component:accept stream */ int legacy; /** throttle queue */ jqueue_t tq; /** timestamps for idle timeouts */ time_t last_activity; }; /** route types */ typedef enum { route_SINGLE = 0x00, /**< single component route */ route_MULTI_TO = 0x10, /**< multi component route - route by 'to' */ route_MULTI_FROM = 0x11, /**< multi component route - route by 'from' */ } route_type_t; struct routes_st { const char *name; route_type_t rtype; component_t *comp; int ncomp; }; struct alias_st { const char *name; const char *target; alias_t next; }; int router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); void router_sx_handshake(sx_t s, sx_buf_t buf, void *arg); xht aci_load(router_t r); void aci_unload(xht aci); int aci_check(xht acls, const char *type, const char *name); int user_table_load(router_t r); void user_table_unload(router_t r); int filter_load(router_t r); void filter_unload(router_t r); int filter_packet(router_t r, nad_t nad); int message_log(nad_t nad, router_t r, const char *msg_from, const char *msg_to); void routes_free(routes_t routes); /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; char **char_val; component_t *comp_val; rate_t *rt_val; }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/router/user.c����������������������������������������������������������������0000664�0000000�0000000�00000006107�12614627753�0017245�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "router.h" /** user table manager */ int user_table_load(router_t r) { const char *userfile; FILE *f; long size; char *buf; nad_t nad; int nusers, user, name, secret; log_debug(ZONE, "loading user table"); if(r->users != NULL) xhash_free(r->users); r->users = xhash_new(51); userfile = config_get_one(r->config, "local.users", 0); if(userfile == NULL) userfile = CONFIG_DIR "/router-users.xml"; f = fopen(userfile, "rb"); if(f == NULL) { log_write(r->log, LOG_ERR, "couldn't open user table file %s: %s", userfile, strerror(errno)); return 1; } fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); buf = (char *) malloc(sizeof(char) * size); if (fread(buf, 1, size, f) != size || ferror(f)) { log_write(r->log, LOG_ERR, "couldn't read from user table file: %s", strerror(errno)); free(buf); fclose(f); return 1; } fclose(f); nad = nad_parse(buf, size); if(nad == NULL) { log_write(r->log, LOG_ERR, "couldn't parse user table"); free(buf); return 1; } free(buf); nusers = 0; user = nad_find_elem(nad, 0, -1, "user", 1); while(user >= 0) { name = nad_find_elem(nad, user, -1, "name", 1); secret = nad_find_elem(nad, user, -1, "secret", 1); if(name < 0 || secret < 0 || NAD_CDATA_L(nad, name) <= 0 || NAD_CDATA_L(nad, secret) <= 0) { log_write(r->log, LOG_ERR, "malformed user entry in user table file, skipping"); continue; } log_debug(ZONE, "remembering user '%.*s'", NAD_CDATA_L(nad, name), NAD_CDATA(nad, name)); xhash_put(r->users, pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, name), NAD_CDATA_L(nad, name)), pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, secret), NAD_CDATA_L(nad, secret))); nusers++; user = nad_find_elem(nad, user, -1, "user", 0); } nad_free(nad); log_write(r->log, LOG_NOTICE, "loaded user table (%d users)", nusers); r->users_load = time(NULL); return 0; } void user_table_unload(router_t r) { if(r->users != NULL) xhash_free(r->users); r->users = NULL; return; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015306�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/Makefile.am��������������������������������������������������������������0000664�0000000�0000000�00000000571�12614627753�0017345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������AM_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -I@top_srcdir@ LIBTOOL += --quiet bin_PROGRAMS = s2s noinst_HEADERS = s2s.h s2s_SOURCES = in.c main.c out.c router.c db.c util.c s2s_LDADD = $(top_builddir)/sx/libsx.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la if USE_LIBSUBST s2s_LDADD += $(top_builddir)/subst/libsubst.la endif ���������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/db.c���������������������������������������������������������������������0000664�0000000�0000000�00000004036�12614627753�0016042�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* * this is a minimal sx plugin that hacks the "jabber:server:dialback" * onto outgoing connections and adds "urn:xmpp:features:dialback" feature */ #include "s2s.h" #define S2S_DB_NS_DECL " xmlns:db='" uri_DIALBACK "'" #define S2S_DB_NS_DECL_LEN (uri_DIALBACK_L + 12) static void _s2s_db_header(sx_t s, sx_plugin_t p, sx_buf_t buf) { if(!(s->flags & S2S_DB_HEADER)) return; log_debug(ZONE, "hacking dialback namespace decl onto stream header"); /* get enough space */ _sx_buffer_alloc_margin(buf, 0, S2S_DB_NS_DECL_LEN + 2); /* overwrite the trailing ">" with a decl followed by a new ">" */ memcpy(&buf->data[buf->len - 1], S2S_DB_NS_DECL ">", S2S_DB_NS_DECL_LEN+1); buf->len += S2S_DB_NS_DECL_LEN; } /** sx features callback */ static void _s2s_db_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; ns = nad_add_namespace(nad, uri_URN_DIALBACK, NULL); nad_append_elem(nad, ns, "dialback", 1); nad_append_elem(nad, -1, "required", 2); } int s2s_db_init(sx_env_t env, sx_plugin_t p, va_list args) { log_debug(ZONE, "initialising dialback sx plugin"); p->header = _s2s_db_header; p->features = _s2s_db_features; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/in.c���������������������������������������������������������������������0000664�0000000�0000000�00000047621�12614627753�0016072�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "s2s.h" /* * we handle incoming connections, and the packets that arrive on them. * * action points: * * event_STREAM - new incoming connection * - create new dbconn (key stream id) * - DONE * * event_PACKET: <result from='them' to='us'>key</result> - auth request * - get dbconn for this sx * - if dbconn state is valid * - send result: <result to='them' from='us' type='valid'/> * - DONE * - out_packet(s2s, <verify to='them' from='us' id='stream id'>key</verify>) * - DONE * * event_PACKET: <verify from='them' to='us' id='123'>key</verify> - validate their key * - generate dbkey: sha1(secret+remote+id) * - if their key matches dbkey * - send them: <verify to='them' from='us' id='123' type='valid'/> * - else * - send them: <verify to='them' from='us' id='123' type='invalid'/> * - DONE * * event_PACKET - they're trying to send us something * - get dbconn for this sx * - if dbconn state is invalid * - drop packet * - DONE * - write packet to router * - DONE */ /* forward decls */ static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); static void _in_result(conn_t in, nad_t nad); static void _in_verify(conn_t in, nad_t nad); static void _in_packet(conn_t in, nad_t nad); int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { conn_t in = (conn_t) arg; s2s_t s2s = (s2s_t) arg; struct sockaddr_storage sa; socklen_t namelen = sizeof(sa); int port, nbytes, flags = 0; char ipport[INET6_ADDRSTRLEN + 17]; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(in->s); return 0; } return sx_can_read(in->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(in->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); if (fd == s2s->server_fd) break; /* !!! logging */ log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, in->ip, in->port, in->packet_count); jqueue_push(in->s2s->dead, (void *) in->s, 0); /* remove from open streams hash if online, or open connections if not */ if (in->online) xhash_zap(in->s2s->in, in->key); else { snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_zap(in->s2s->in_accept, ipport); } jqueue_push(in->s2s->dead_conn, (void *) in, 0); break; case action_ACCEPT: s2s = (s2s_t) arg; log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming connection", fd->fd, (char *) data, port); /* new conn */ in = (conn_t) calloc(1, sizeof(struct conn_st)); in->s2s = s2s; strncpy(in->ip, (char *) data, INET6_ADDRSTRLEN); in->port = port; in->states = xhash_new(101); in->states_time = xhash_new(101); in->fd = fd; in->init_time = time(NULL); in->s = sx_new(s2s->sx_env, in->fd->fd, _in_sx_callback, (void *) in); mio_app(m, in->fd, in_mio_callback, (void *) in); if(s2s->stanza_size_limit != 0) in->s->rbytesmax = s2s->stanza_size_limit; /* add to incoming connections hash */ snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_put(s2s->in_accept, pstrdup(xhash_pool(s2s->in_accept),ipport), (void *) in); flags = S2S_DB_HEADER; #ifdef HAVE_SSL if(s2s->sx_ssl != NULL) flags |= SX_SSL_STARTTLS_OFFER; #endif #ifdef HAVE_LIBZ if(s2s->compression) flags |= SX_COMPRESS_OFFER; #endif sx_server_init(in->s, flags); break; } return 0; } static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { conn_t in = (conn_t) arg; sx_buf_t buf = (sx_buf_t) data; int len; sx_error_t *sxe; nad_t nad; char ipport[INET6_ADDRSTRLEN + 17]; jid_t from; int attr; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(in->s2s->mio, in->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(in->s2s->mio, in->fd); break; case event_READ: log_debug(ZONE, "reading from %d", in->fd->fd); /* do the read */ len = recv(in->fd->fd, buf->data, buf->len, 0); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", in->fd->fd); len = send(in->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", in->fd->fd, in->ip, in->port, sxe->generic, sxe->specific); break; case event_STREAM: case event_OPEN: log_debug(ZONE, "STREAM or OPEN event from %s port %d (id %s)", in->ip, in->port, s->id); /* first time, bring them online */ if ((!in->online)||(strcmp(in->key,s->id)!=0)) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming stream online (id %s)", in->fd->fd, in->ip, in->port, s->id); in->online = 1; /* record the id */ if (in->key != NULL) { log_debug(ZONE,"adding new SSL stream id %s for stream id %s", s->id, in->key); /* remove the initial (non-SSL) stream id from the in connections hash */ xhash_zap(in->s2s->in, in->key); free((void*)in->key); } in->key = strdup(s->id); /* track it - add to open streams hash and remove from new connections hash */ xhash_put(in->s2s->in, in->key, (void *) in); snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_zap(in->s2s->in_accept, ipport); } break; case event_PACKET: /* we're counting packets */ in->packet_count++; in->s2s->packet_count++; nad = (nad_t) data; /* update last packet timestamp */ in->last_packet = time(NULL); /* dialback packets */ if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_DIALBACK) && strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_DIALBACK)) == 0 && (in->s2s->require_tls == 0 || s->ssf > 0)) { /* only result and verify mean anything */ if(NAD_ENAME_L(nad, 0) == 6) { if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) { _in_result(in, nad); return 0; } if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) { _in_verify(in, nad); return 0; } } log_debug(ZONE, "unknown dialback packet, dropping it"); nad_free(nad); return 0; } /* * not dialback, so it has to be a normal-ish jabber packet: * - jabber:client or jabber:server * - message, presence or iq * - has to and from attributes */ if(!( /* must be jabber:client or jabber:server */ NAD_ENS(nad, 0) >= 0 && ((NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_CLIENT)) == 0) || (NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_SERVER) && strncmp(uri_SERVER, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_SERVER)) == 0)) && ( /* can be message */ (NAD_ENAME_L(nad, 0) == 7 && strncmp("message", NAD_ENAME(nad, 0), 7) == 0) || /* or presence */ (NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) || /* or iq */ (NAD_ENAME_L(nad, 0) == 2 && strncmp("iq", NAD_ENAME(nad, 0), 2) == 0) ) && /* to and from required */ nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "from", NULL) >= 0 )) { log_debug(ZONE, "they sent us a non-jabber looking packet, dropping it"); nad_free(nad); return 0; } /* perform check against whitelist */ attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on incoming packet, attr is %d", attr); nad_free(nad); return 0; } if (in->s2s->enable_whitelist > 0 && (s2s_domain_in_whitelist(in->s2s, from->domain) == 0)) { log_write(in->s2s->log, LOG_NOTICE, "received a packet not from a whitelisted domain %s, dropping it", from->domain); jid_free(from); nad_free(nad); return 0; } jid_free(from); _in_packet(in, nad); return 0; case event_CLOSED: if (in->fd != NULL) { mio_close(in->s2s->mio, in->fd); in->fd = NULL; } return -1; } return 0; } /** auth requests */ static void _in_result(conn_t in, nad_t nad) { int attr, ns; jid_t from, to; char *rkey; nad_t verify; pkt_t pkt; time_t now; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on db result packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on db result packet"); jid_free(from); nad_free(nad); return; } rkey = s2s_route_key(NULL, to->domain, from->domain); log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] received dialback auth request for route '%s'", in->fd->fd, in->ip, in->port, rkey); /* get current state */ if((conn_state_t) xhash_get(in->states, rkey) == conn_VALID) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] route '%s' is already valid: sending valid", in->fd->fd, in->ip, in->port, rkey); /* its already valid, just reply right now */ stanza_tofrom(nad, 0); nad_set_attr(nad, 0, -1, "type", "valid", 5); nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(in->s, nad); free(rkey); jid_free(from); jid_free(to); return; } /* not valid, so we need to verify */ /* need the key */ if(NAD_CDATA_L(nad, 0) <= 0) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback key given with db result packet", in->fd->fd, in->ip, in->port, rkey); free(rkey); nad_free(nad); jid_free(from); jid_free(to); return; } log_debug(ZONE, "requesting verification for route %s", rkey); /* set the route status to INPROGRESS and set timestamp */ xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_INPROGRESS); /* record the time that we set conn_INPROGRESS state */ now = time(NULL); xhash_put(in->states_time, pstrdup(xhash_pool(in->states_time), rkey), (void *) now); free(rkey); /* new packet */ verify = nad_new(); ns = nad_add_namespace(verify, uri_DIALBACK, "db"); nad_append_elem(verify, ns, "verify", 0); nad_append_attr(verify, -1, "to", from->domain); nad_append_attr(verify, -1, "from", to->domain); nad_append_attr(verify, -1, "id", in->s->id); nad_append_cdata(verify, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0), 1); /* new packet */ pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); pkt->nad = verify; pkt->to = from; pkt->from = to; pkt->db = 1; /* its away */ out_packet(in->s2s, pkt); nad_free(nad); } /** validate their key */ static void _in_verify(conn_t in, nad_t nad) { int attr; jid_t from, to; char *id, *dbkey, *type; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on db verify packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on db verify packet"); jid_free(from); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr < 0) { log_debug(ZONE, "missing id on db verify packet"); jid_free(from); jid_free(to); nad_free(nad); return; } if(NAD_CDATA_L(nad, 0) <= 0) { log_debug(ZONE, "no cdata on db verify packet"); jid_free(from); jid_free(to); nad_free(nad); return; } /* extract the id */ id = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 1)); snprintf(id, NAD_AVAL_L(nad, attr) + 1, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); /* generate a dialback key */ dbkey = s2s_db_key(NULL, in->s2s->local_secret, from->domain, id); /* valid */ if(NAD_CDATA_L(nad, 0) == strlen(dbkey) && strncmp(dbkey, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)) == 0) { log_debug(ZONE, "valid dialback key %s, verify succeeded", dbkey); type = "valid"; } else { log_debug(ZONE, "invalid dialback key %s, verify failed", dbkey); type = "invalid"; } log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] checking dialback verification from %s: sending %s", in->fd->fd, in->ip, in->port, from->domain, type); log_debug(ZONE, "letting them know"); /* now munge the packet and send it back to them */ stanza_tofrom(nad, 0); nad_set_attr(nad, 0, -1, "type", type, 0); nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(in->s, nad); free(dbkey); free(id); jid_free(from); jid_free(to); return; } /** they're trying to send us something */ static void _in_packet(conn_t in, nad_t nad) { int elem, attr, ns, sns; jid_t from, to; char *rkey; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on incoming packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on incoming packet"); jid_free(from); nad_free(nad); return; } rkey = s2s_route_key(NULL, to->domain, from->domain); log_debug(ZONE, "received packet from %s for %s", in->key, rkey); /* drop packets received on routes not valid on that connection as per XMPP 8.3.10 */ if((conn_state_t) xhash_get(in->states, rkey) != conn_VALID) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dropping packet on unvalidated route: '%s'", in->fd->fd, in->ip, in->port, rkey); free(rkey); nad_free(nad); jid_free(from); jid_free(to); return; } free(rkey); /* its good, off to the router with it */ log_debug(ZONE, "incoming packet on valid route, preparing it for the router"); /* rewrite server packets into client packets */ ns = nad_find_namespace(nad, 0, uri_SERVER, NULL); if(ns >= 0) { if(nad->elems[0].ns == ns) nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; else { for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; } } /* * If stanza is not in any namespace (either because we removed the * jabber:server namespace above or because it's in the default * namespace for this stream) then this packet is intended to be * handled by sm (and not just routed through the server), so set the * jabber:client namespace. */ if(ns >= 0 || nad->elems[0].ns < 0) { ns = nad_add_namespace(nad, uri_CLIENT, NULL); for(elem = 0; elem < nad->ecur; elem++) if(nad->elems[elem].ns == ns) nad->elems[elem].ns = nad->nss[nad->elems[elem].ns].next; nad->nss[ns].next = nad->elems[0].ns; nad->elems[0].ns = ns; nad->scope = -1; } nad->elems[0].my_ns = nad->elems[0].ns; /* wrap up the packet */ ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_wrap_elem(nad, 0, ns, "route"); nad_set_attr(nad, 0, -1, "to", to->domain, 0); nad_set_attr(nad, 0, -1, "from", in->s2s->id, 0); /* route is from s2s, not packet source */ log_debug(ZONE, "sending packet to %s", to->domain); /* go */ sx_nad_write(in->s2s->router, nad); jid_free(from); jid_free(to); } ���������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/main.c�������������������������������������������������������������������0000664�0000000�0000000�00000130610�12614627753�0016377�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "s2s.h" #include <stringprep.h> #include <unistd.h> static sig_atomic_t s2s_shutdown = 0; sig_atomic_t s2s_lost_router = 0; static sig_atomic_t s2s_logrotate = 0; static void _s2s_signal(int signum) { s2s_shutdown = 1; s2s_lost_router = 0; } static void _s2s_signal_hup(int signum) { s2s_logrotate = 1; } static void _s2s_signal_usr1(int signum) { set_debug_flag(0); } static void _s2s_signal_usr2(int signum) { set_debug_flag(1); } static int _s2s_populate_whitelist_domains(s2s_t s2s, const char **values, int nvalues); /** store the process id */ static void _s2s_pidfile(s2s_t s2s) { const char *pidfile; FILE *f; pid_t pid; pidfile = config_get_one(s2s->config, "pidfile", 0); if(pidfile == NULL) return; pid = getpid(); if((f = fopen(pidfile, "w+")) == NULL) { log_write(s2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno)); return; } if(fprintf(f, "%d", pid) < 0) { log_write(s2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno)); fclose(f); return; } fclose(f); log_write(s2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile); } /** pull values out of the config file */ static void _s2s_config_expand(s2s_t s2s) { char *str, secret[41]; config_elem_t elem; int i, r; set_debug_log_from_config(s2s->config); s2s->id = config_get_one(s2s->config, "id", 0); if(s2s->id == NULL) s2s->id = "s2s"; s2s->router_ip = config_get_one(s2s->config, "router.ip", 0); if(s2s->router_ip == NULL) s2s->router_ip = "127.0.0.1"; s2s->router_port = j_atoi(config_get_one(s2s->config, "router.port", 0), 5347); s2s->router_user = config_get_one(s2s->config, "router.user", 0); if(s2s->router_user == NULL) s2s->router_user = "jabberd"; s2s->router_pass = config_get_one(s2s->config, "router.pass", 0); if(s2s->router_pass == NULL) s2s->router_pass = "secret"; s2s->router_pemfile = config_get_one(s2s->config, "router.pemfile", 0); s2s->router_cachain = config_get_one(s2s->config, "router.cachain", 0); s2s->router_private_key_password = config_get_one(s2s->config, "router.private_key_password", 0); s2s->router_ciphers = config_get_one(s2s->config, "router.ciphers", 0); s2s->retry_init = j_atoi(config_get_one(s2s->config, "router.retry.init", 0), 3); s2s->retry_lost = j_atoi(config_get_one(s2s->config, "router.retry.lost", 0), 3); if((s2s->retry_sleep = j_atoi(config_get_one(s2s->config, "router.retry.sleep", 0), 2)) < 1) s2s->retry_sleep = 1; s2s->router_default = config_count(s2s->config, "router.non-default") ? 0 : 1; s2s->log_type = log_STDOUT; if(config_get(s2s->config, "log") != NULL) { if((str = config_get_attr(s2s->config, "log", 0, "type")) != NULL) { if(strcmp(str, "file") == 0) s2s->log_type = log_FILE; else if(strcmp(str, "syslog") == 0) s2s->log_type = log_SYSLOG; } } if(s2s->log_type == log_SYSLOG) { s2s->log_facility = config_get_one(s2s->config, "log.facility", 0); s2s->log_ident = config_get_one(s2s->config, "log.ident", 0); if(s2s->log_ident == NULL) s2s->log_ident = "jabberd/s2s"; } else if(s2s->log_type == log_FILE) s2s->log_ident = config_get_one(s2s->config, "log.file", 0); s2s->packet_stats = config_get_one(s2s->config, "stats.packet", 0); /* * If no origin IP is specified, use local IP as the originating one: * it makes most sense, at least for SSL'ized connections. * APPLE: make origin an array of addresses so that both IPv4 and IPv6 can be specified. */ s2s->local_ip = config_get_one(s2s->config, "local.ip", 0); if(s2s->local_ip == NULL) s2s->local_ip = "0.0.0.0"; if((elem = config_get(s2s->config, "local.origins.ip")) != NULL) { s2s->origin_ips = elem->values; s2s->origin_nips = elem->nvalues; } if (s2s->origin_nips == 0) { s2s->origin_ips = (const char **)malloc(sizeof(s2s->origin_ips)); s2s->origin_ips[0] = strdup(s2s->local_ip); s2s->origin_nips = 1; } s2s->local_port = j_atoi(config_get_one(s2s->config, "local.port", 0), 0); if(config_get(s2s->config, "local.secret") != NULL) s2s->local_secret = strdup(config_get_one(s2s->config, "local.secret", 0)); else { for(i = 0; i < 40; i++) { r = (int) (36.0 * rand() / RAND_MAX); secret[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); } secret[40] = '\0'; s2s->local_secret = strdup(secret); } if(s2s->local_secret == NULL) s2s->local_secret = "secret"; s2s->local_pemfile = config_get_one(s2s->config, "local.pemfile", 0); s2s->local_cachain = config_get_one(s2s->config, "local.cachain", 0); s2s->local_verify_mode = j_atoi(config_get_one(s2s->config, "local.verify-mode", 0), 0); s2s->local_private_key_password = config_get_one(s2s->config, "local.private_key_password", 0); s2s->local_ciphers = config_get_one(s2s->config, "local.ciphers", 0); s2s->io_max_fds = j_atoi(config_get_one(s2s->config, "io.max_fds", 0), 1024); s2s->compression = (config_get(s2s->config, "io.compression") != NULL); s2s->stanza_size_limit = j_atoi(config_get_one(s2s->config, "io.limits.stanzasize", 0), 0); s2s->require_tls = j_atoi(config_get_one(s2s->config, "security.require_tls", 0), 0); s2s->enable_whitelist = j_atoi(config_get_one(s2s->config, "security.enable_whitelist", 0), 0); if((elem = config_get(s2s->config, "security.whitelist_domain")) != NULL) { _s2s_populate_whitelist_domains(s2s, elem->values, elem->nvalues); } s2s->check_interval = j_atoi(config_get_one(s2s->config, "check.interval", 0), 60); s2s->check_queue = j_atoi(config_get_one(s2s->config, "check.queue", 0), 60); s2s->check_keepalive = j_atoi(config_get_one(s2s->config, "check.keepalive", 0), 0); s2s->check_idle = j_atoi(config_get_one(s2s->config, "check.idle", 0), 86400); s2s->check_dnscache = j_atoi(config_get_one(s2s->config, "check.dnscache", 0), 300); s2s->retry_limit = j_atoi(config_get_one(s2s->config, "check.retry", 0), 300); if((elem = config_get(s2s->config, "lookup.srv")) != NULL) { s2s->lookup_srv = elem->values; s2s->lookup_nsrv = elem->nvalues; } s2s->resolve_aaaa = config_count(s2s->config, "lookup.resolve-ipv6") ? 1 : 0; s2s->dns_cache_enabled = config_count(s2s->config, "lookup.no-cache") ? 0 : 1; s2s->dns_bad_timeout = j_atoi(config_get_one(s2s->config, "lookup.bad-host-timeout", 0), 3600); s2s->dns_min_ttl = j_atoi(config_get_one(s2s->config, "lookup.min-ttl", 0), 30); if (s2s->dns_min_ttl < 5) s2s->dns_min_ttl = 5; s2s->dns_max_ttl = j_atoi(config_get_one(s2s->config, "lookup.max-ttl", 0), 86400); s2s->etc_hosts_ttl = j_atoi(config_get_one(s2s->config, "lookup.etc-hosts-ttl", 0), 86400); s2s->out_reuse = config_count(s2s->config, "out-conn-reuse") ? 1 : 0; } static void _s2s_hosts_expand(s2s_t s2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(s2s->config, "local.id"); if (elem) for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(s2s->hosts), sizeof(struct host_st)); if(!host) { log_write(s2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(s2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(s2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); host->host_private_key_password = j_attr((const char **) elem->attrs[i], "private-key-password"); host->host_ciphers = j_attr((const char **) elem->attrs[i], "ciphers"); #ifdef HAVE_SSL if(host->host_pemfile != NULL) { if(s2s->sx_ssl == NULL) { s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password, host->host_ciphers); if(s2s->sx_ssl == NULL) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } else { if(sx_ssl_server_addcert(s2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password, host->host_ciphers) != 0) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif /* insert into vHosts xhash */ xhash_put(s2s->hosts, pstrdup(xhash_pool(s2s->hosts), id), host); log_write(s2s->log, LOG_NOTICE, "[%s] configured; realm=%s", id, host->realm); } } static int _s2s_router_connect(s2s_t s2s) { log_write(s2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", s2s->router_ip, s2s->router_port); s2s->fd = mio_connect(s2s->mio, s2s->router_port, s2s->router_ip, NULL, s2s_router_mio_callback, (void *) s2s); if(s2s->fd == NULL) { if(errno == ECONNREFUSED) s2s_lost_router = 1; log_write(s2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR); return 1; } s2s->router = sx_new(s2s->sx_env, s2s->fd->fd, s2s_router_sx_callback, (void *) s2s); sx_client_init(s2s->router, 0, NULL, NULL, NULL, "1.0"); return 0; } int _s2s_check_conn_routes(s2s_t s2s, conn_t conn, const char *direction) { char *rkey; int rkeylen; conn_state_t state; time_t now, dialback_time; now = time(NULL); if(xhash_iter_first(conn->states)) do { /* retrieve state in a separate operation, as sizeof(int) != sizeof(void *) on 64-bit platforms, so passing a pointer to state in xhash_iter_get is unsafe */ xhash_iter_get(conn->states, (const char **) &rkey, &rkeylen, NULL); state = (conn_state_t) xhash_getx(conn->states, rkey, rkeylen); if (state == conn_INPROGRESS) { dialback_time = (time_t) xhash_getx(conn->states_time, rkey, rkeylen); if(now > dialback_time + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback for %s route '%.*s' timed out", conn->fd->fd, conn->ip, conn->port, direction, rkeylen, rkey); xhash_zapx(conn->states, rkey, rkeylen); xhash_zapx(conn->states_time, rkey, rkeylen); /* stream error */ sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback timed out"); /* close connection as per XMPP/RFC3920 */ sx_close(conn->s); /* indicate that we closed the connection */ return 0; } } } while(xhash_iter_next(conn->states)); /* all ok */ return 1; } static void _s2s_time_checks(s2s_t s2s) { conn_t conn; time_t now; char *rkey, *key; int keylen; jqueue_t q; dnscache_t dns; char *c; int c_len; union xhashv xhv; now = time(NULL); /* queue expiry */ if(s2s->check_queue > 0) { if(xhash_iter_first(s2s->outq)) do { xhv.jq_val = &q; xhash_iter_get(s2s->outq, (const char **) &rkey, &keylen, xhv.val); log_debug(ZONE, "running time checks for %.*s", keylen, rkey); c = memchr(rkey, '/', keylen); c++; c_len = keylen - (c - rkey); /* dns lookup timeout check first */ dns = xhash_getx(s2s->dnscache, c, c_len); if(dns != NULL && dns->pending) { log_debug(ZONE, "dns lookup pending for %.*s", c_len, c); if(now > dns->init_time + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "dns lookup for %.*s timed out", c_len, c); /* bounce queue */ out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_NOT_FOUND); /* expire pending dns entry */ xhash_zap(s2s->dnscache, dns->name); xhash_free(dns->results); if (dns->query != NULL) { if (dns->query->query != NULL) dns_cancel(NULL, dns->query->query); xhash_free(dns->query->hosts); xhash_free(dns->query->results); free((void*)dns->query->name); free(dns->query); } free(dns); } continue; } /* get the conn */ conn = xhash_getx(s2s->out_dest, c, c_len); if(conn == NULL) { if(jqueue_size(q) > 0) { /* no pending conn? perhaps it failed? */ log_debug(ZONE, "no pending connection for %.*s, bouncing %i packets in queue", c_len, c, jqueue_size(q)); /* bounce queue */ out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_TIMEOUT); } continue; } /* connect timeout check */ if(!conn->online && now > conn->init_time + s2s->check_queue) { dnsres_t bad; char *ipport; log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connection to %s timed out", conn->fd->fd, conn->ip, conn->port, c); if (s2s->dns_bad_timeout > 0) { /* mark this host as bad */ ipport = dns_make_ipport(conn->ip, conn->port); bad = xhash_get(s2s->dns_bad, ipport); if (bad == NULL) { bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st)); bad->key = ipport; xhash_put(s2s->dns_bad, ipport, bad); } else { free(ipport); } bad->expiry = time(NULL) + s2s->dns_bad_timeout; } /* close connection as per XMPP/RFC3920 */ /* the close function will retry or bounce the queue */ sx_close(conn->s); } } while(xhash_iter_next(s2s->outq)); } /* expiry of connected routes in conn_INPROGRESS state */ if(s2s->check_queue > 0) { /* outgoing connections */ if(s2s->out_reuse) { if(xhash_iter_first(s2s->out_host)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking dialback state for outgoing conn %.*s", keylen, key); if (_s2s_check_conn_routes(s2s, conn, "outgoing")) { log_debug(ZONE, "checking pending verify requests for outgoing conn %.*s", keylen, key); if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port); sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out"); sx_close(conn->s); } } } while(xhash_iter_next(s2s->out_host)); } else { if(xhash_iter_first(s2s->out_dest)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking dialback state for outgoing conn %s (%s)", conn->dkey, conn->key); if (_s2s_check_conn_routes(s2s, conn, "outgoing")) { log_debug(ZONE, "checking pending verify requests for outgoing conn %s (%s)", conn->dkey, conn->key); if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port); sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out"); sx_close(conn->s); } } } while(xhash_iter_next(s2s->out_dest)); } /* incoming open streams */ if(xhash_iter_first(s2s->in)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking dialback state for incoming conn %.*s", keylen, key); if (_s2s_check_conn_routes(s2s, conn, "incoming")) /* if the connection is still valid, check that dialbacks have been initiated */ if(!xhash_count(conn->states) && now > conn->init_time + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback started", conn->fd->fd, conn->ip, conn->port); sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "no dialback initiated"); sx_close(conn->s); } } while(xhash_iter_next(s2s->in)); /* incoming open connections (not yet streams) */ if(xhash_iter_first(s2s->in_accept)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->in_accept, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking stream connection state for incoming conn %i", conn->fd->fd); if(!conn->online && now > conn->init_time + s2s->check_queue) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] stream initiation timed out", conn->fd->fd, conn->ip, conn->port); sx_close(conn->s); } } while(xhash_iter_next(s2s->in_accept)); } /* keepalives */ if(s2s->out_reuse) { if(xhash_iter_first(s2s->out_host)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val); if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", conn->fd->fd); sx_raw_write(conn->s, " ", 1); } } while(xhash_iter_next(s2s->out_host)); } else { if(xhash_iter_first(s2s->out_dest)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val); if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", conn->fd->fd); sx_raw_write(conn->s, " ", 1); } } while(xhash_iter_next(s2s->out_dest)); } /* idle timeouts - disconnect connections through which no packets have been sent for <idle> seconds */ if(s2s->check_idle > 0) { /* outgoing connections */ if(s2s->out_reuse) { if(xhash_iter_first(s2s->out_host)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking idle state for %.*s", keylen, key); if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); sx_close(conn->s); } } while(xhash_iter_next(s2s->out_host)); } else { if(xhash_iter_first(s2s->out_dest)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking idle state for %s (%s)", conn->dkey, conn->key); if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); sx_close(conn->s); } } while(xhash_iter_next(s2s->out_dest)); } /* incoming connections */ if(xhash_iter_first(s2s->in)) do { xhv.conn_val = &conn; xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val); log_debug(ZONE, "checking idle state for %.*s", keylen, key); if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port); sx_close(conn->s); } } while(xhash_iter_next(s2s->in)); } return; } static void _s2s_dns_expiry(s2s_t s2s) { time_t now; dnscache_t dns = NULL; dnsres_t res = NULL; union xhashv xhv; now = time(NULL); /* dnscache timeouts */ if(xhash_iter_first(s2s->dnscache)) do { xhv.dns_val = &dns; xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val); if (dns && !dns->pending && now > dns->expiry) { log_debug(ZONE, "expiring DNS cache for %s", dns->name); xhash_iter_zap(s2s->dnscache); xhash_free(dns->results); if (dns->query != NULL) { if (dns->query->query != NULL) dns_cancel(NULL, dns->query->query); xhash_free(dns->query->hosts); xhash_free(dns->query->results); free((void*)dns->query->name); free(dns->query); } free(dns); } else if (dns == NULL) { xhash_iter_zap(s2s->dnscache); } } while(xhash_iter_next(s2s->dnscache)); if(xhash_iter_first(s2s->dns_bad)) do { xhv.dnsres_val = &res; xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val); if (res && now > res->expiry) { log_debug(ZONE, "expiring DNS bad host %s", res->key); xhash_iter_zap(s2s->dns_bad); free((void*)res->key); free(res); } else if (res == NULL) { xhash_iter_zap(s2s->dns_bad); } } while(xhash_iter_next(s2s->dns_bad)); } /** responses from the resolver */ static int _mio_resolver_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); dns_ioevent(0, time(NULL)); default: break; } return 0; } /* Populate the whitelist_domains array with the config file values */ int _s2s_populate_whitelist_domains(s2s_t s2s, const char **values, int nvalues) { int i, j; int elem_len; s2s->whitelist_domains = (char **)malloc(sizeof(char*) * (nvalues)); memset(s2s->whitelist_domains, 0, (sizeof(char *) * (nvalues))); for (i = 0, j = 0; i < nvalues; i++) { elem_len = strlen(values[i]); if (elem_len > MAX_DOMAIN_LEN) { log_debug(ZONE, "whitelist domain element is too large, skipping"); continue; } if (elem_len == 0) { log_debug(ZONE, "whitelist domain element is blank, skipping"); continue; } s2s->whitelist_domains[j] = (char *) malloc(sizeof(char) * (elem_len+1)); strncpy(s2s->whitelist_domains[j], values[i], elem_len); s2s->whitelist_domains[j][elem_len] = '\0'; log_debug(ZONE, "s2s whitelist domain read from file: %s\n", s2s->whitelist_domains[j]); j++; } s2s->n_whitelist_domains = j; log_debug(ZONE, "n_whitelist_domains = %d", s2s->n_whitelist_domains); return 0; } /* Compare a domain with whitelist values. The whitelist values may be FQDN or domain only (with no prepended hostname). returns 1 on match, 0 on failure to match */ int s2s_domain_in_whitelist(s2s_t s2s, const char *in_domain) { int segcount = 0; int dotcount; char **segments = NULL; char **dst = NULL; char *seg_tmp = NULL; int seg_tmp_len; char matchstr[MAX_DOMAIN_LEN + 1]; int domain_index; int x, i; int wl_index; int wl_len; int matchstr_len; char domain[1024]; char *domain_ptr = &domain[0]; int domain_len; strncpy(domain, in_domain, sizeof(domain)); domain[sizeof(domain)-1] = '\0'; domain_len = strlen((const char *)&domain); if (domain_len <= 0) { log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is empty"); return 0; } if (domain_len > MAX_DOMAIN_LEN) { log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is longer than %s chars", MAX_DOMAIN_LEN); return 0; } // first try matching the FQDN with whitelist domains if (s2s->n_whitelist_domains <= 0) return 0; for (wl_index =0; wl_index < s2s->n_whitelist_domains; wl_index++) { wl_len = strlen(s2s->whitelist_domains[wl_index]); if (!strncmp((const char *)&domain, s2s->whitelist_domains[wl_index], (domain_len > wl_len) ? domain_len : wl_len)) { log_debug(ZONE, "domain \"%s\" matches whitelist entry", &domain); return 1; } else { //log_debug(ZONE, "domain: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &domain, strlen((const char *)&domain), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index])); } } // break domain into segments for domain-only comparision for (dotcount = 0, x = 0; domain[x] != '\0'; x++) { if (domain[x] == '.') dotcount++; } segments = (char **)malloc(sizeof(char*) * (dotcount + 1)); if (segments == NULL) { log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error"); return 0; } memset((char **)segments, 0, (sizeof(char*) * (dotcount + 1))); do { if (segcount > (dotcount+1)) { log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: did not malloc enough room for domain segments; should never get here"); if (seg_tmp != NULL) { free(seg_tmp); seg_tmp = NULL; } for (x = 0; x < segcount; x++) { free(segments[x]); segments[x] = NULL; } free(segments); segments = NULL; return 0; } seg_tmp = strsep(&domain_ptr, "."); if (seg_tmp == NULL) { break; } seg_tmp_len = strlen(seg_tmp); if (seg_tmp_len > MAX_DOMAIN_LEN) { log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: domain contains a segment greater than %s chars", MAX_DOMAIN_LEN); if (seg_tmp != NULL) { free(seg_tmp); seg_tmp = NULL; } for (x = 0; x < segcount; x++) { free(segments[x]); segments[x] = NULL; } free(segments); segments = NULL; return 0; } dst = &segments[segcount]; *dst = (char *)malloc(seg_tmp_len + 1); if (*dst != NULL) { strncpy(*dst, seg_tmp, seg_tmp_len + 1); (*dst)[seg_tmp_len] = '\0'; } else { if (seg_tmp != NULL) { free(seg_tmp); seg_tmp = NULL; } for (x = 0; x < segcount; x++) { free(segments[x]); segments[x] = NULL; } free(segments); segments = NULL; log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error"); return 0; } segcount++; } while (seg_tmp != NULL); if (segcount > 1) { for (domain_index = segcount-2; domain_index > 0; domain_index--) { matchstr[0] = '\0'; for (i = domain_index; i < segcount; i++) { if (i > domain_index) { strncat((char *)&matchstr, ".", sizeof(matchstr)); matchstr[sizeof(matchstr)-1] = '\0'; } strncat((char *)&matchstr, (char *)segments[i], sizeof(matchstr)-strlen(matchstr)-1); matchstr[sizeof(matchstr)-1] = '\0'; } for (wl_index = 0; wl_index < s2s->n_whitelist_domains; wl_index++) { wl_len = strlen(s2s->whitelist_domains[wl_index]); matchstr_len = strlen((const char *)&matchstr); if (!strncmp((const char *)&matchstr, s2s->whitelist_domains[wl_index], (wl_len > matchstr_len ? wl_len : matchstr_len))) { log_debug(ZONE, "matchstr \"%s\" matches whitelist entry", &matchstr); for (x = 0; x < segcount; x++) { free(segments[x]); segments[x] = NULL; } free(segments); segments = NULL; return 1; } else { //log_debug(ZONE, "matchstr: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &matchstr, strlen((const char *)&matchstr), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index])); } } } } for (x = 0; x < segcount; x++) { free(segments[x]); segments[x] = NULL; } free(segments); segments = NULL; return 0; } JABBER_MAIN("jabberd2s2s", "Jabber 2 S2S", "Jabber Open Source Server: Server to Server", "jabberd2router\0") { s2s_t s2s; char *config_file; int optchar; conn_t conn; jqueue_t q; dnscache_t dns; dnsres_t res; union xhashv xhv; time_t check_time = 0, now = 0; const char *cli_id = 0; #ifdef HAVE_UMASK umask((mode_t) 0027); #endif srand(time(NULL)); #ifdef HAVE_WINSOCK2_H /* get winsock running */ { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* !!! tell user that we couldn't find a usable winsock dll */ return 0; } } #endif jabber_signal(SIGINT, _s2s_signal); jabber_signal(SIGTERM, _s2s_signal); #ifdef SIGHUP jabber_signal(SIGHUP, _s2s_signal_hup); #endif #ifdef SIGPIPE jabber_signal(SIGPIPE, SIG_IGN); #endif jabber_signal(SIGUSR1, _s2s_signal_usr1); jabber_signal(SIGUSR2, _s2s_signal_usr2); s2s = (s2s_t) calloc(1, sizeof(struct s2s_st)); /* load our config */ s2s->config = config_new(); config_file = CONFIG_DIR "/s2s.xml"; /* cmdline parsing */ while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0) { switch(optchar) { case 'c': config_file = optarg; break; case 'D': #ifdef DEBUG set_debug_flag(1); #else printf("WARN: Debugging not enabled. Ignoring -D.\n"); #endif break; case 'i': cli_id = optarg; break; case 'h': case '?': default: fputs( "s2s - jabberd server-to-server connector (" VERSION ")\n" "Usage: s2s <options>\n" "Options are:\n" " -c <config> config file to use [default: " CONFIG_DIR "/s2s.xml]\n" " -i id Override <id> config element\n" #ifdef DEBUG " -D Show debug output\n" #endif , stdout); config_free(s2s->config); free(s2s); return 1; } } if(config_load_with_id(s2s->config, config_file, cli_id) != 0) { fputs("s2s: couldn't load config, aborting\n", stderr); config_free(s2s->config); free(s2s); return 2; } _s2s_config_expand(s2s); s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility); log_write(s2s->log, LOG_NOTICE, "starting up (interval=%i, queue=%i, keepalive=%i, idle=%i)", s2s->check_interval, s2s->check_queue, s2s->check_keepalive, s2s->check_idle); _s2s_pidfile(s2s); s2s->outq = xhash_new(401); s2s->out_host = xhash_new(401); s2s->out_dest = xhash_new(401); s2s->in = xhash_new(401); s2s->in_accept = xhash_new(401); s2s->dnscache = xhash_new(401); s2s->dns_bad = xhash_new(401); s2s->dead = jqueue_new(); s2s->dead_conn = jqueue_new(); s2s->sx_env = sx_env_new(); #ifdef HAVE_SSL /* get the ssl context up and running */ if(s2s->local_pemfile != NULL) { s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->local_pemfile, s2s->local_cachain, s2s->local_verify_mode, s2s->local_private_key_password, s2s->local_ciphers); if(s2s->sx_ssl == NULL) { log_write(s2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to peers"); s2s->local_pemfile = NULL; } else log_debug(ZONE, "loaded pemfile for SSL connections to peers"); } /* try and get something online, so at least we can encrypt to the router */ if(s2s->sx_ssl == NULL && s2s->router_pemfile != NULL) { s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->router_pemfile, s2s->router_cachain, NULL, s2s->router_private_key_password, s2s->router_ciphers); if(s2s->sx_ssl == NULL) { log_write(s2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted"); s2s->router_pemfile = NULL; } } #endif #ifdef HAVE_LIBZ /* get compression up and running */ if(s2s->compression) sx_env_plugin(s2s->sx_env, sx_compress_init); #endif /* get sasl online */ s2s->sx_sasl = sx_env_plugin(s2s->sx_env, sx_sasl_init, "xmpp", NULL, NULL); if(s2s->sx_sasl == NULL) { log_write(s2s->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); } /* hosts mapping */ s2s->hosts = xhash_new(1021); _s2s_hosts_expand(s2s); s2s->sx_db = sx_env_plugin(s2s->sx_env, s2s_db_init); s2s->mio = mio_new(s2s->io_max_fds); if((s2s->udns_fd = dns_init(NULL, 1)) < 0) { log_write(s2s->log, LOG_ERR, "unable to initialize dns library, aborting"); exit(1); } s2s->udns_mio_fd = mio_register(s2s->mio, s2s->udns_fd, _mio_resolver_callback, (void *) s2s); s2s->retry_left = s2s->retry_init; _s2s_router_connect(s2s); while(!s2s_shutdown) { mio_run(s2s->mio, dns_timeouts(0, 5, time(NULL))); now = time(NULL); if(s2s_logrotate) { set_debug_log_from_config(s2s->config); log_write(s2s->log, LOG_NOTICE, "reopening log ..."); log_free(s2s->log); s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility); log_write(s2s->log, LOG_NOTICE, "log started"); s2s_logrotate = 0; } if(s2s_lost_router) { if(s2s->retry_left < 0) { log_write(s2s->log, LOG_NOTICE, "attempting reconnect"); sleep(s2s->retry_sleep); s2s_lost_router = 0; if (s2s->router) sx_free(s2s->router); _s2s_router_connect(s2s); } else if(s2s->retry_left == 0) { s2s_shutdown = 1; } else { log_write(s2s->log, LOG_NOTICE, "attempting reconnect (%d left)", s2s->retry_left); s2s->retry_left--; sleep(s2s->retry_sleep); s2s_lost_router = 0; if (s2s->router) sx_free(s2s->router); _s2s_router_connect(s2s); } } /* this has to be read unconditionally - we could receive replies to queries we cancelled */ mio_read(s2s->mio, s2s->udns_mio_fd); /* cleanup dead sx_ts */ while(jqueue_size(s2s->dead) > 0) sx_free((sx_t) jqueue_pull(s2s->dead)); /* cleanup dead conn_ts */ while(jqueue_size(s2s->dead_conn) > 0) { conn = (conn_t) jqueue_pull(s2s->dead_conn); xhash_free(conn->states); xhash_free(conn->states_time); xhash_free(conn->routes); free((void*)conn->key); free((void*)conn->dkey); free(conn); } /* time checks */ if(s2s->check_interval > 0 && now >= s2s->next_check) { log_debug(ZONE, "running time checks"); _s2s_time_checks(s2s); s2s->next_check = now + s2s->check_interval; log_debug(ZONE, "next time check at %d", s2s->next_check); } /* dnscache expiry */ if(s2s->check_dnscache > 0 && now >= s2s->next_expiry) { log_debug(ZONE, "running dns expiry"); _s2s_dns_expiry(s2s); s2s->next_expiry = now + s2s->check_dnscache; log_debug(ZONE, "next dns expiry at %d", s2s->next_expiry); } if(now > check_time + 60) { #ifdef POOL_DEBUG pool_stat(1); #endif if(s2s->packet_stats != NULL) { int fd = open(s2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if(fd) { char buf[100]; int len = snprintf(buf, 100, "%lld\n", s2s->packet_count); write(fd, buf, len); close(fd); } else { log_write(s2s->log, LOG_ERR, "failed to write packet statistics to: %s", s2s->packet_stats); s2s_shutdown = 1; } } check_time = now; } } log_write(s2s->log, LOG_NOTICE, "shutting down"); /* close active streams gracefully */ xhv.conn_val = &conn; if(s2s->out_reuse) { if(xhash_iter_first(s2s->out_host)) do { xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val); if(conn) { sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); sx_close(conn->s); } } while(xhash_iter_next(s2s->out_host)); } else { if(xhash_iter_first(s2s->out_dest)) do { xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val); if(conn) { sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); sx_close(conn->s); } } while(xhash_iter_next(s2s->out_dest)); } if(xhash_iter_first(s2s->in)) do { xhash_iter_get(s2s->in, NULL, NULL, xhv.val); if(conn) { sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown"); out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); sx_close(conn->s); } } while(xhash_iter_next(s2s->in)); if(xhash_iter_first(s2s->in_accept)) do { xhash_iter_get(s2s->in_accept, NULL, NULL, xhv.val); if(conn) { out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE); sx_close(conn->s); } } while(xhash_iter_next(s2s->in_accept)); /* remove dead streams */ while(jqueue_size(s2s->dead) > 0) sx_free((sx_t) jqueue_pull(s2s->dead)); /* cleanup dead conn_ts */ while(jqueue_size(s2s->dead_conn) > 0) { conn = (conn_t) jqueue_pull(s2s->dead_conn); xhash_free(conn->states); xhash_free(conn->states_time); xhash_free(conn->routes); if(conn->key != NULL) free((void*)conn->key); if(conn->dkey != NULL) free((void*)conn->dkey); free(conn); } /* free outgoing queues */ xhv.jq_val = &q; if(xhash_iter_first(s2s->outq)) do { xhash_iter_get(s2s->outq, NULL, NULL, xhv.val); while (jqueue_size(q) > 0) out_pkt_free((pkt_t) jqueue_pull(q)); free(q->key); jqueue_free(q); } while(xhash_iter_next(s2s->outq)); /* walk & free resolve queues */ xhv.dns_val = &dns; if(xhash_iter_first(s2s->dnscache)) do { xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val); xhash_free(dns->results); if (dns->query != NULL) { if (dns->query->query != NULL) dns_cancel(NULL, dns->query->query); xhash_free(dns->query->hosts); xhash_free(dns->query->results); free((void*)dns->query->name); free(dns->query); } free(dns); } while(xhash_iter_next(s2s->dnscache)); xhv.dnsres_val = &res; if(xhash_iter_first(s2s->dns_bad)) do { xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val); free((void*)res->key); free(res); } while(xhash_iter_next(s2s->dns_bad)); if (dns_active(NULL) > 0) log_debug(ZONE, "there are still active dns queries (%d)", dns_active(NULL)); dns_close(NULL); /* close mio */ mio_close(s2s->mio, s2s->udns_mio_fd); if(s2s->fd != NULL) mio_close(s2s->mio, s2s->fd); if(s2s->server_fd != NULL) mio_close(s2s->mio, s2s->server_fd); /* free hashes */ xhash_free(s2s->outq); xhash_free(s2s->out_host); xhash_free(s2s->out_dest); xhash_free(s2s->in); xhash_free(s2s->in_accept); xhash_free(s2s->dnscache); xhash_free(s2s->dns_bad); xhash_free(s2s->hosts); jqueue_free(s2s->dead); jqueue_free(s2s->dead_conn); sx_free(s2s->router); sx_env_free(s2s->sx_env); mio_free(s2s->mio); log_free(s2s->log); config_free(s2s->config); free((void*)s2s->local_secret); free(s2s); #ifdef POOL_DEBUG pool_stat(1); #endif return 0; } ������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/out.c��������������������������������������������������������������������0000664�0000000�0000000�00000200303�12614627753�0016257�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #define _GNU_SOURCE #include <string.h> #include "s2s.h" #include <idna.h> /* * we handle packets going from the router to the world, and stuff * that comes in on connections we initiated. * * action points: * * out_packet(s2s, nad) - send this packet out * - extract to domain * - get dbconn for this domain using out_route * - if dbconn not available bounce packet * - DONE * - if conn in progress (tcp) * - add packet to queue for this domain * - DONE * - if dbconn state valid for this domain, or packet is dialback * - send packet * - DONE * - if dbconn state invalid for this domain * - bounce packet (502) * - DONE * - add packet to queue for this domain * - if dbconn state inprogress for this domain * - DONE * - out_dialback(dbconn, from, to) * * out_route(s2s, route, out, allow_bad) * - if dbconn not found * - check internal resolver cache for domain * - if not found * - ask resolver for name * - DONE * - if outgoing ip/port is to be reused * - get dbconn for any valid ip/port * - if dbconn not found * - create new dbconn * - initiate connect to ip/port * - DONE * - create new dbconn * - initiate connect to ip/port * - DONE * * out_dialback(dbconn, from, to) - initiate dialback * - generate dbkey: sha1(secret+remote+stream id) * - send auth request: <result to='them' from='us'>dbkey</result> * - set dbconn state for this domain to inprogress * - DONE * * out_resolve(s2s, query) - responses from resolver * - store ip/port/ttl in resolver cache * - flush domain queue -> out_packet(s2s, domain) * - DONE * * event_STREAM - ip/port open * - get dbconn for this sx * - for each route handled by this conn, out_dialback(dbconn, from, to) * - DONE * * event_PACKET: <result from='them' to='us' type='xxx'/> - response to our auth request * - get dbconn for this sx * - if type valid * - set dbconn state for this domain to valid * - flush dbconn queue for this domain -> out_packet(s2s, pkt) * - DONE * - set dbconn state for this domain to invalid * - bounce dbconn queue for this domain (502) * - DONE * * event_PACKET: <verify from='them' to='us' id='123' type='xxx'/> - incoming stream authenticated * - get dbconn for given id * - if type is valid * - set dbconn state for this domain to valid * - send result: <result to='them' from='us' type='xxx'/> * - DONE */ /* forward decls */ static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); static void _out_result(conn_t out, nad_t nad); static void _out_verify(conn_t out, nad_t nad); static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data); static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data); /** queue the packet */ static void _out_packet_queue(s2s_t s2s, pkt_t pkt) { char *rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain); jqueue_t q = (jqueue_t) xhash_get(s2s->outq, rkey); if(q == NULL) { log_debug(ZONE, "creating new out packet queue for '%s'", rkey); q = jqueue_new(); q->key = rkey; xhash_put(s2s->outq, q->key, (void *) q); } else { free(rkey); } log_debug(ZONE, "queueing packet for '%s'", q->key); jqueue_push(q, (void *) pkt, 0); } static void _out_dialback(conn_t out, const char *rkey, int rkeylen) { char *c, *dbkey, *tmp; nad_t nad; int elem, ns; int from_len, to_len; time_t now; now = time(NULL); c = memchr(rkey, '/', rkeylen); from_len = c - rkey; c++; to_len = rkeylen - (c - rkey); /* kick off the dialback */ tmp = strndup(c, to_len); dbkey = s2s_db_key(NULL, out->s2s->local_secret, tmp, out->s->id); free(tmp); nad = nad_new(); /* request auth */ ns = nad_add_namespace(nad, uri_DIALBACK, "db"); elem = nad_append_elem(nad, ns, "result", 0); nad_set_attr(nad, elem, -1, "from", rkey, from_len); nad_set_attr(nad, elem, -1, "to", c, to_len); nad_append_cdata(nad, dbkey, strlen(dbkey), 1); log_debug(ZONE, "sending auth request for %.*s (key %s)", rkeylen, rkey, dbkey); log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] sending dialback auth request for route '%.*s'", out->fd->fd, out->ip, out->port, rkeylen, rkey); /* off it goes */ sx_nad_write(out->s, nad); free(dbkey); /* we're in progress now */ xhash_put(out->states, pstrdupx(xhash_pool(out->states), rkey, rkeylen), (void *) conn_INPROGRESS); /* record the time that we set conn_INPROGRESS state */ xhash_put(out->states_time, pstrdupx(xhash_pool(out->states_time), rkey, rkeylen), (void *) now); } void _out_dns_mark_bad(conn_t out) { if (out->s2s->dns_bad_timeout > 0) { dnsres_t bad; char *ipport; /* mark this host as bad */ ipport = dns_make_ipport(out->ip, out->port); bad = xhash_get(out->s2s->dns_bad, ipport); if (bad == NULL) { bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st)); bad->key = ipport; xhash_put(out->s2s->dns_bad, ipport, bad); } bad->expiry = time(NULL) + out->s2s->dns_bad_timeout; } } int dns_select(s2s_t s2s, char *ip, int *port, time_t now, dnscache_t dns, int allow_bad) { /* list of results */ dnsres_t l_reuse[DNS_MAX_RESULTS]; dnsres_t l_aaaa[DNS_MAX_RESULTS]; dnsres_t l_a[DNS_MAX_RESULTS]; dnsres_t l_bad[DNS_MAX_RESULTS]; /* running weight sums of results */ int rw_reuse[DNS_MAX_RESULTS]; int rw_aaaa[DNS_MAX_RESULTS]; int rw_a[DNS_MAX_RESULTS]; int s_reuse = 0, s_aaaa = 0, s_a = 0, s_bad = 0; /* count */ int p_reuse = 0, p_aaaa = 0, p_a = 0; /* list prio */ int wt_reuse = 0, wt_aaaa = 0, wt_a = 0; /* weight total */ int c_expired_good = 0; union xhashv xhv; dnsres_t res; const char *ipport; int ipport_len; char *c; int c_len; char *tmp; /* for all results: * - if not expired * - put highest priority reuseable addrs into list1 * - put highest priority ipv6 addrs into list2 * - put highest priority ipv4 addrs into list3 * - put bad addrs into list4 * - pick weighted random entry from first non-empty list */ if (dns->results == NULL) { log_debug(ZONE, "negative cache entry for '%s'", dns->name); return -1; } log_debug(ZONE, "selecting DNS result for '%s'", dns->name); xhv.dnsres_val = &res; if (xhash_iter_first(dns->results)) { dnsres_t bad = NULL; do { xhash_iter_get(dns->results, (const char **) &ipport, &ipport_len, xhv.val); if (s2s->dns_bad_timeout > 0) bad = xhash_getx(s2s->dns_bad, ipport, ipport_len); if (now > res->expiry) { /* good host? */ if (bad == NULL) c_expired_good++; log_debug(ZONE, "host '%s' expired", res->key); continue; } else if (bad != NULL && !(now > bad->expiry)) { /* bad host (connection failure) */ l_bad[s_bad++] = res; log_debug(ZONE, "host '%s' bad", res->key); } else if (s2s->out_reuse && xhash_getx(s2s->out_host, ipport, ipport_len) != NULL) { /* existing connection */ log_debug(ZONE, "host '%s' exists", res->key); if (s_reuse == 0 || p_reuse > res->prio) { p_reuse = res->prio; s_reuse = 0; wt_reuse = 0; log_debug(ZONE, "reset prio list, using prio %d", res->prio); } if (res->prio <= p_reuse) { l_reuse[s_reuse] = res; wt_reuse += res->weight; rw_reuse[s_reuse] = wt_reuse; s_reuse++; log_debug(ZONE, "added host with weight %d (%d), running weight %d", (res->weight >> 8), res->weight, wt_reuse); } else { log_debug(ZONE, "ignored host with prio %d", res->prio); } } else if (memchr(ipport, ':', ipport_len) != NULL) { /* ipv6 */ log_debug(ZONE, "host '%s' IPv6", res->key); if (s_aaaa == 0 || p_aaaa > res->prio) { p_aaaa = res->prio; s_aaaa = 0; wt_aaaa = 0; log_debug(ZONE, "reset prio list, using prio %d", res->prio); } if (res->prio <= p_aaaa) { l_aaaa[s_aaaa] = res; wt_aaaa += res->weight; rw_aaaa[s_aaaa] = wt_aaaa; s_aaaa++; log_debug(ZONE, "added host with weight %d (%d), running weight %d", (res->weight >> 8), res->weight, wt_aaaa); } else { log_debug(ZONE, "ignored host with prio %d", res->prio); } } else { /* ipv4 */ log_debug(ZONE, "host '%s' IPv4", res->key); if (s_a == 0 || p_a > res->prio) { p_a = res->prio; s_a = 0; wt_a = 0; log_debug(ZONE, "reset prio list, using prio %d", res->prio); } if (res->prio <= p_a) { l_a[s_a] = res; wt_a += res->weight; rw_a[s_a] = wt_a; s_a++; log_debug(ZONE, "added host with weight %d (%d), running weight %d", (res->weight >> 8), res->weight, wt_a); } else { log_debug(ZONE, "ignored host with prio %d", res->prio); } } } while(xhash_iter_next(dns->results)); } /* pick a result at weighted random (RFC 2782) * all weights are guaranteed to be >= 16 && <= 16776960 * (assuming max 50 hosts, the total/running sums won't exceed 2^31) */ ipport = NULL; if (s_reuse > 0) { int i, r; log_debug(ZONE, "using existing hosts, total weight %d", wt_reuse); assert((wt_reuse + 1) > 0); r = rand() % (wt_reuse + 1); log_debug(ZONE, "random number %d", r); for (i = 0; i < s_reuse; i++) if (rw_reuse[i] >= r) { log_debug(ZONE, "selected host '%s', running weight %d", l_reuse[i]->key, rw_reuse[i]); ipport = l_reuse[i]->key; break; } } else if (s_aaaa > 0 && (s_a == 0 || p_aaaa <= p_a)) { int i, r; log_debug(ZONE, "using IPv6 hosts, total weight %d", wt_aaaa); assert((wt_aaaa + 1) > 0); r = rand() % (wt_aaaa + 1); log_debug(ZONE, "random number %d", r); for (i = 0; i < s_aaaa; i++) if (rw_aaaa[i] >= r) { log_debug(ZONE, "selected host '%s', running weight %d", l_aaaa[i]->key, rw_aaaa[i]); ipport = l_aaaa[i]->key; break; } } else if (s_a > 0) { int i, r; log_debug(ZONE, "using IPv4 hosts, total weight %d", wt_a); assert((wt_a + 1) > 0); r = rand() % (wt_a + 1); log_debug(ZONE, "random number %d", r); for (i = 0; i < s_a; i++) if (rw_a[i] >= r) { log_debug(ZONE, "selected host '%s', running weight %d", l_a[i]->key, rw_a[i]); ipport = l_a[i]->key; break; } } else if (s_bad > 0) { ipport = l_bad[rand() % s_bad]->key; log_debug(ZONE, "using bad hosts, allow_bad=%d", allow_bad); /* there are expired good hosts, expire cache immediately */ if (c_expired_good > 0) { log_debug(ZONE, "expiring this DNS cache entry, %d expired hosts", c_expired_good); dns->expiry = 0; } if (!allow_bad) return -1; } /* results cannot all expire before the collection does */ assert(ipport != NULL); /* copy the ip and port to the packet */ ipport_len = strlen(ipport); c = strchr(ipport, '/'); strncpy(ip, ipport, c-ipport); ip[c-ipport] = '\0'; c++; c_len = ipport_len - (c - ipport); tmp = strndup(c, c_len); *port = atoi(tmp); free(tmp); return 0; } /** find/make a connection for a route */ int out_route(s2s_t s2s, const char *route, int routelen, conn_t *out, int allow_bad) { dnscache_t dns; char ipport[INET6_ADDRSTRLEN + 16], *dkey, *c; time_t now; int reuse = 0; char ip[INET6_ADDRSTRLEN] = {0}; int port, c_len, from_len; c = memchr(route, '/', routelen); from_len = c - route; c++; c_len = routelen - (c - route); dkey = strndup(c, c_len); log_debug(ZONE, "trying to find connection for '%s'", dkey); *out = (conn_t) xhash_get(s2s->out_dest, dkey); if(*out == NULL) { log_debug(ZONE, "connection for '%s' not found", dkey); /* check resolver cache for ip/port */ dns = xhash_get(s2s->dnscache, dkey); if(dns == NULL) { /* new resolution */ log_debug(ZONE, "no dns for %s, preparing for resolution", dkey); dns = (dnscache_t) calloc(1, sizeof(struct dnscache_st)); strcpy(dns->name, dkey); xhash_put(s2s->dnscache, dns->name, (void *) dns); #if 0 /* this is good for testing */ dns->pending = 0; strcpy(dns->ip, "127.0.0.1"); dns->port = 3000; dns->expiry = time(NULL) + 99999999; #endif } /* resolution in progress */ if(dns->pending) { log_debug(ZONE, "pending resolution"); free(dkey); return 0; } /* has it expired (this is 0 for new cache objects, so they're always expired */ now = time(NULL); /* each entry must be expired no earlier than the collection */ if(now > dns->expiry) { /* resolution required */ log_debug(ZONE, "requesting resolution for %s", dkey); dns->init_time = time(NULL); dns->pending = 1; dns_resolve_domain(s2s, dns); free(dkey); return 0; } /* dns is valid */ if (dns_select(s2s, ip, &port, now, dns, allow_bad)) { /* failed to find anything acceptable */ free(dkey); return -1; } /* re-request resolution if dns_select expired the data */ if (now > dns->expiry) { /* resolution required */ log_debug(ZONE, "requesting resolution for %s", dkey); dns->init_time = time(NULL); dns->pending = 1; dns_resolve_domain(s2s, dns); free(dkey); return 0; } /* generate the ip/port pair, this is the hash key for the conn */ snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", ip, port); /* try to re-use an existing connection */ if (s2s->out_reuse) *out = (conn_t) xhash_get(s2s->out_host, ipport); if (*out != NULL) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] using connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey); /* associate existing connection with domain */ xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out); reuse = 1; } else{ /* no conn, create one */ *out = (conn_t) calloc(1, sizeof(struct conn_st)); (*out)->s2s = s2s; (*out)->key = strdup(ipport); if (s2s->out_reuse) (*out)->dkey = NULL; else (*out)->dkey = dkey; strcpy((*out)->ip, ip); (*out)->port = port; (*out)->states = xhash_new(101); (*out)->states_time = xhash_new(101); (*out)->routes = xhash_new(101); (*out)->init_time = time(NULL); if (s2s->out_reuse) xhash_put(s2s->out_host, (*out)->key, (void *) *out); xhash_put(s2s->out_dest, s2s->out_reuse ? pstrdup(xhash_pool((*out)->routes), dkey) : dkey, (void *) *out); xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1); /* connect */ log_debug(ZONE, "initiating connection to %s", ipport); /* APPLE: multiple origin_ips may be specified; use IPv6 if possible or otherwise IPv4 */ int ip_is_v6 = 0; if (strchr(ip, ':') != NULL) ip_is_v6 = 1; int i; for (i = 0; i < s2s->origin_nips; i++) { // only bother with mio_connect if the src and dst IPs are of the same type if ((ip_is_v6 && (strchr(s2s->origin_ips[i], ':') != NULL)) || // both are IPv6 (! ip_is_v6 && (strchr(s2s->origin_ips[i], ':') == NULL))) // both are IPv4 (*out)->fd = mio_connect(s2s->mio, port, ip, s2s->origin_ips[i], _out_mio_callback, (void *) *out); if ((*out)->fd != NULL) break; } if ((*out)->fd == NULL) { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] mio_connect error: %s (%d)", -1, (*out)->ip, (*out)->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); _out_dns_mark_bad(*out); if (s2s->out_reuse) xhash_zap(s2s->out_host, (*out)->key); xhash_zap(s2s->out_dest, dkey); xhash_free((*out)->states); xhash_free((*out)->states_time); xhash_free((*out)->routes); free((void*)(*out)->key); free((void*)(*out)->dkey); free(*out); *out = NULL; /* try again without allowing bad hosts */ return out_route(s2s, route, routelen, out, 0); } else { log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing connection for '%s'", (*out)->fd->fd, (*out)->ip, (*out)->port, dkey); (*out)->s = sx_new(s2s->sx_env, (*out)->fd->fd, _out_sx_callback, (void *) *out); #ifdef HAVE_SSL /* Send a stream version of 1.0 if we can do STARTTLS */ if(s2s->sx_ssl != NULL) { sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, dkey, pstrdupx(xhash_pool((*out)->routes), route, from_len), "1.0"); } else { sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL); } #else sx_client_init((*out)->s, S2S_DB_HEADER, uri_SERVER, NULL, NULL, NULL); #endif /* dkey is now used by the hash table */ return 0; } } } else { log_debug(ZONE, "connection for '%s' found (%d %s/%d)", dkey, (*out)->fd->fd, (*out)->ip, (*out)->port); } /* connection in progress, or re-using connection: add to routes list */ if (!(*out)->online || reuse) { if (xhash_getx((*out)->routes, route, routelen) == NULL) xhash_put((*out)->routes, pstrdupx(xhash_pool((*out)->routes), route, routelen), (void *) 1); } free(dkey); return 0; } void out_pkt_free(pkt_t pkt) { nad_free(pkt->nad); jid_free(pkt->from); jid_free(pkt->to); free(pkt); } /** send a packet out */ int out_packet(s2s_t s2s, pkt_t pkt) { char *rkey; int rkeylen; conn_t out; conn_state_t state; int ret; /* perform check against whitelist */ if (s2s->enable_whitelist > 0 && (pkt->to->domain != NULL) && (s2s_domain_in_whitelist(s2s, pkt->to->domain) == 0)) { log_write(s2s->log, LOG_NOTICE, "sending a packet to domain not in the whitelist, dropping it"); if (pkt->to != NULL) jid_free(pkt->to); if (pkt->from != NULL) jid_free(pkt->from); if (pkt->nad != NULL) nad_free(pkt->nad); free(pkt); return 0; } /* new route key */ rkey = s2s_route_key(NULL, pkt->from->domain, pkt->to->domain); rkeylen = strlen(rkey); /* get a connection */ ret = out_route(s2s, rkey, rkeylen, &out, 1); if (out == NULL) { /* connection not available, queue packet */ _out_packet_queue(s2s, pkt); /* check if out_route was successful in attempting a connection */ if (ret) { /* bounce queue */ out_bounce_route_queue(s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); free(rkey); return -1; } free(rkey); return 0; } /* connection in progress */ if(!out->online) { log_debug(ZONE, "connection in progress, queueing packet"); _out_packet_queue(s2s, pkt); free(rkey); return 0; } /* connection state */ state = (conn_state_t) xhash_get(out->states, rkey); /* valid conns or dialback packets */ if(state == conn_VALID || pkt->db) { log_debug(ZONE, "writing packet for %s to outgoing conn %d", rkey, out->fd->fd); /* send it straight out */ if(pkt->db) { /* if this is a db:verify packet, increment counter and set timestamp */ if(NAD_ENAME_L(pkt->nad, 0) == 6 && strncmp("verify", NAD_ENAME(pkt->nad, 0), 6) == 0) { out->verify++; out->last_verify = time(NULL); } /* dialback packet */ sx_nad_write(out->s, pkt->nad); } else { /* if the outgoing stanza has a jabber:client namespace, remove it so that the stream jabber:server namespaces will apply (XMPP 11.2.2) */ int ns = nad_find_namespace(pkt->nad, 1, uri_CLIENT, NULL); if(ns >= 0) { /* clear the namespaces of elem 0 (internal route element) and elem 1 (message|iq|presence) */ pkt->nad->elems[0].ns = -1; pkt->nad->elems[0].my_ns = -1; pkt->nad->elems[1].ns = -1; pkt->nad->elems[1].my_ns = -1; } /* send it out */ sx_nad_write_elem(out->s, pkt->nad, 1); } /* update timestamp */ out->last_packet = time(NULL); jid_free(pkt->from); jid_free(pkt->to); free(pkt); free(rkey); return 0; } /* can't be handled yet, queue */ _out_packet_queue(s2s, pkt); /* if dialback is in progress, then we're done for now */ if(state == conn_INPROGRESS) { free(rkey); return 0; } /* this is a new route - send dialback auth request to piggyback on the existing connection */ if (out->s2s->require_tls == 0 || out->s->ssf > 0) { _out_dialback(out, rkey, rkeylen); } free(rkey); return 0; } char *dns_make_ipport(const char *host, int port) { char *c; assert(port > 0 && port < 65536); c = (char *) malloc(strlen(host) + 7); sprintf(c, "%s/%d", host, port); return c; } static void _dns_add_result(dnsquery_t query, const char *ip, int port, int prio, int weight, unsigned int ttl) { char *ipport = dns_make_ipport(ip, port); dnsres_t res = xhash_get(query->results, ipport); if (res != NULL) { if (prio < res->prio) res->prio = prio; if (prio < res->prio) { /* duplicate host at lower prio - reset weight */ res->weight = weight; } else if (prio == res->prio) { /* duplicate host at same prio - add to weight */ res->weight += weight; if (res->weight > (65535 << 8)) res->weight = (65535 << 8); } if (ttl > res->expiry) res->expiry = ttl; if (ttl > query->expiry) query->expiry = ttl; log_debug(ZONE, "dns result updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, res->prio, (res->weight >> 8), res->expiry); } else if (xhash_count(query->results) < DNS_MAX_RESULTS) { res = pmalloc(xhash_pool(query->results), sizeof(struct dnsres_st)); res->key = pstrdup(xhash_pool(query->results), ipport); res->prio = prio; res->weight = weight; res->expiry = ttl; if (ttl > query->expiry) query->expiry = ttl; xhash_put(query->results, res->key, res); log_debug(ZONE, "dns result added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, res->prio, (res->weight >> 8), res->expiry); } else { log_debug(ZONE, "dns result ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, prio, (weight >> 8), ttl); } free(ipport); } static void _dns_add_host(dnsquery_t query, const char *ip, int port, int prio, int weight, unsigned int ttl) { char *ipport = dns_make_ipport(ip, port); dnsres_t res = xhash_get(query->hosts, ipport); /* update host weights: * RFC 2482 "In the presence of records containing weights greater * than 0, records with weight 0 should have a very small chance of * being selected." * 0 -> 16 * 1-65535 -> 256-16776960 */ if (weight == 0) weight = 1 << 4; else weight <<= 8; if (res != NULL) { if (prio < res->prio) res->prio = prio; if (prio < res->prio) { /* duplicate host at lower prio - reset weight */ res->weight = weight; } else if (prio == res->prio) { /* duplicate host at same prio - add to weight */ res->weight += weight; if (res->weight > (65535 << 8)) res->weight = (65535 << 8); } if (ttl > res->expiry) res->expiry = ttl; log_debug(ZONE, "dns host updated for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, res->prio, (res->weight >> 8), res->expiry); } else if (xhash_count(query->hosts) < DNS_MAX_RESULTS) { res = pmalloc(xhash_pool(query->hosts), sizeof(struct dnsres_st)); res->key = pstrdup(xhash_pool(query->hosts), ipport); res->prio = prio; res->weight = weight; res->expiry = ttl; xhash_put(query->hosts, res->key, res); log_debug(ZONE, "dns host added for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, res->prio, (res->weight >> 8), res->expiry); } else { log_debug(ZONE, "dns host ignored for %s@%p: %s (%d/%d/%d)", query->name, query, ipport, prio, (weight >> 8), ttl); } free(ipport); } /* this function is called with a NULL ctx to start the SRV process */ static void _dns_result_srv(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data) { dnsquery_t query = data; assert(query != NULL); query->query = NULL; if (ctx != NULL && result == NULL) { log_debug(ZONE, "dns failure for %s@%p: SRV %s (%d)", query->name, query, query->s2s->lookup_srv[query->srv_i], dns_status(ctx)); } else if (result != NULL) { int i; log_debug(ZONE, "dns response for %s@%p: SRV %s %d (%d)", query->name, query, result->dnssrv_qname, result->dnssrv_nrr, result->dnssrv_ttl); for (i = 0; i < result->dnssrv_nrr; i++) { if (strlen(result->dnssrv_srv[i].name) > 0 && result->dnssrv_srv[i].port > 0 && result->dnssrv_srv[i].port < 65536) { log_debug(ZONE, "dns response for %s@%p: SRV %s[%d] %s/%d (%d/%d)", query->name, query, result->dnssrv_qname, i, result->dnssrv_srv[i].name, result->dnssrv_srv[i].port, result->dnssrv_srv[i].priority, result->dnssrv_srv[i].weight); _dns_add_host(query, result->dnssrv_srv[i].name, result->dnssrv_srv[i].port, result->dnssrv_srv[i].priority, result->dnssrv_srv[i].weight, result->dnssrv_ttl); } } free(result); } /* check next SRV service name */ query->srv_i++; if (query->srv_i < query->s2s->lookup_nsrv) { log_debug(ZONE, "dns request for %s@%p: SRV %s", query->name, query, query->s2s->lookup_srv[query->srv_i]); query->query = dns_submit_srv(NULL, query->name, query->s2s->lookup_srv[query->srv_i], "tcp", DNS_NOSRCH, _dns_result_srv, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_srv(ctx, NULL, query); } else { /* no more SRV records to check, resolve hosts */ if (xhash_count(query->hosts) > 0) { _dns_result_a(NULL, NULL, query); /* no SRV records returned, resolve hostname */ } else { query->cur_host = strdup(query->name); query->cur_port = 5269; query->cur_prio = 0; query->cur_weight = 0; query->cur_expiry = 0; if (query->s2s->resolve_aaaa) { log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->name); query->query = dns_submit_a6(NULL, query->name, DNS_NOSRCH, _dns_result_aaaa, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_aaaa(ctx, NULL, query); } else { log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->name); query->query = dns_submit_a4(NULL, query->name, DNS_NOSRCH, _dns_result_a, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_a(ctx, NULL, query); } } } } static void _dns_result_aaaa(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data) { dnsquery_t query = data; char ip[INET6_ADDRSTRLEN]; int i; assert(query != NULL); query->query = NULL; if (ctx != NULL && result == NULL) { log_debug(ZONE, "dns failure for %s@%p: AAAA %s (%d)", query->name, query, query->cur_host, dns_status(ctx)); } else if (result != NULL) { log_debug(ZONE, "dns response for %s@%p: AAAA %s %d (%d)", query->name, query, result->dnsa6_qname, result->dnsa6_nrr, result->dnsa6_ttl); if (query->cur_expiry > 0 && result->dnsa6_ttl > query->cur_expiry) result->dnsa6_ttl = query->cur_expiry; for (i = 0; i < result->dnsa6_nrr; i++) { if (inet_ntop(AF_INET6, &result->dnsa6_addr[i], ip, INET6_ADDRSTRLEN) != NULL) { log_debug(ZONE, "dns response for %s@%p: AAAA %s[%d] %s/%d", query->name, query, result->dnsa6_qname, i, ip, query->cur_port); _dns_add_result(query, ip, query->cur_port, query->cur_prio, query->cur_weight, result->dnsa6_ttl); } } } if (query->cur_host != NULL) { /* do ipv4 resolution too */ log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host); query->query = dns_submit_a4(NULL, query->cur_host, DNS_NOSRCH, _dns_result_a, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_a(ctx, NULL, query); } else { /* uh-oh */ log_debug(ZONE, "dns result for %s@%p: AAAA host vanished...", query->name, query); _dns_result_a(NULL, NULL, query); } free(result); } /* try /etc/hosts if the A process did not return any results */ static int _etc_hosts_lookup(const char *cszName, char *szIP, const int ciMaxIPLen) { #define EHL_LINE_LEN 260 int iSuccess = 0; size_t iLen; char szLine[EHL_LINE_LEN + 1]; /* one extra for the space character (*) */ char *pcStart, *pcEnd; FILE *fHosts; do { /* initialization */ fHosts = NULL; /* sanity checks */ if ((cszName == NULL) || (szIP == NULL) || (ciMaxIPLen <= 0)) break; szIP[0] = 0; /* open the hosts file */ #ifdef _WIN32 pcStart = getenv("WINDIR"); if (pcStart != NULL) { sprintf(szLine, "%s\\system32\\drivers\\etc\\hosts", pcStart); } else { strcpy(szLine, "C:\\WINDOWS\\system32\\drivers\\etc\\hosts"); } #else strcpy(szLine, "/etc/hosts"); #endif fHosts = fopen(szLine, "r"); if (fHosts == NULL) break; /* read line by line ... */ while (fgets(szLine, EHL_LINE_LEN, fHosts) != NULL) { /* remove comments */ pcStart = strchr (szLine, '#'); if (pcStart != NULL) *pcStart = 0; strcat(szLine, " "); /* append a space character for easier parsing (*) */ /* first to appear: IP address */ iLen = strspn(szLine, "1234567890."); if ((iLen < 7) || (iLen > 15)) /* superficial test for anything between x.x.x.x and xxx.xxx.xxx.xxx */ continue; pcEnd = szLine + iLen; *pcEnd = 0; pcEnd++; /* not beyond the end of the line yet (*) */ /* check strings separated by blanks, tabs or newlines */ pcStart = pcEnd + strspn(pcEnd, " \t\n"); while (*pcStart != 0) { pcEnd = pcStart + strcspn(pcStart, " \t\n"); *pcEnd = 0; pcEnd++; /* not beyond the end of the line yet (*) */ if (strcasecmp(pcStart, cszName) == 0) { strncpy(szIP, szLine, ciMaxIPLen - 1); szIP[ciMaxIPLen - 1] = '\0'; iSuccess = 1; break; } pcStart = pcEnd + strspn(pcEnd, " \t\n"); } if (iSuccess) break; } } while (0); if (fHosts != NULL) fclose(fHosts); return (iSuccess); } /* this function is called with a NULL ctx to start the A/AAAA process */ static void _dns_result_a(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data) { dnsquery_t query = data; assert(query != NULL); query->query = NULL; if (ctx != NULL && result == NULL) { #define DRA_IP_LEN 16 char szIP[DRA_IP_LEN]; if (_etc_hosts_lookup (query->name, szIP, DRA_IP_LEN)) { log_debug(ZONE, "/etc/lookup for %s@%p: %s (%d)", query->name, query, szIP, query->s2s->etc_hosts_ttl); _dns_add_result (query, szIP, query->cur_port, query->cur_prio, query->cur_weight, query->s2s->etc_hosts_ttl); } else { log_debug(ZONE, "dns failure for %s@%p: A %s (%d)", query->name, query, query->cur_host, dns_status(ctx)); } } else if (result != NULL) { char ip[INET_ADDRSTRLEN]; int i; log_debug(ZONE, "dns response for %s@%p: A %s %d (%d)", query->name, query, result->dnsa4_qname, result->dnsa4_nrr, result->dnsa4_ttl); if (query->cur_expiry > 0 && result->dnsa4_ttl > query->cur_expiry) result->dnsa4_ttl = query->cur_expiry; for (i = 0; i < result->dnsa4_nrr; i++) { if (inet_ntop(AF_INET, &result->dnsa4_addr[i], ip, INET_ADDRSTRLEN) != NULL) { log_debug(ZONE, "dns response for %s@%p: A %s[%d] %s/%d", query->name, query, result->dnsa4_qname, i, ip, query->cur_port); _dns_add_result(query, ip, query->cur_port, query->cur_prio, query->cur_weight, result->dnsa4_ttl); } } free(result); } /* resolve the next host in the list */ if (xhash_iter_first(query->hosts)) { char *ipport, *c, *tmp; int ipport_len, ip_len, port_len; dnsres_t res; union xhashv xhv; xhv.dnsres_val = &res; /* get the first entry */ xhash_iter_get(query->hosts, (const char **) &ipport, &ipport_len, xhv.val); /* remove the host from the list */ xhash_iter_zap(query->hosts); c = memchr(ipport, '/', ipport_len); ip_len = c - ipport; c++; port_len = ipport_len - (c - ipport); /* resolve hostname */ free((void*)query->cur_host); query->cur_host = strndup(ipport, ip_len); tmp = strndup(c, port_len); query->cur_port = atoi(tmp); free(tmp); query->cur_prio = res->prio; query->cur_weight = res->weight; query->cur_expiry = res->expiry; log_debug(ZONE, "dns ttl for %s@%p limited to %d", query->name, query, query->cur_expiry); if (query->s2s->resolve_aaaa) { log_debug(ZONE, "dns request for %s@%p: AAAA %s", query->name, query, query->cur_host); query->query = dns_submit_a6(NULL, query->cur_host, DNS_NOSRCH, _dns_result_aaaa, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_aaaa(ctx, NULL, query); } else { log_debug(ZONE, "dns request for %s@%p: A %s", query->name, query, query->cur_host); query->query = dns_submit_a4(NULL, query->cur_host, DNS_NOSRCH, _dns_result_a, query); /* if submit failed, call ourselves with a NULL result */ if (query->query == NULL) _dns_result_a(ctx, NULL, query); } /* finished */ } else { time_t now = time(NULL); char *domain; free((void*)query->cur_host); query->cur_host = NULL; log_debug(ZONE, "dns requests for %s@%p complete: %d (%d)", query->name, query, xhash_count(query->results), query->expiry); /* update query TTL */ if (query->expiry > query->s2s->dns_max_ttl) query->expiry = query->s2s->dns_max_ttl; if (query->expiry < query->s2s->dns_min_ttl) query->expiry = query->s2s->dns_min_ttl; query->expiry += now; /* update result TTLs - the query expiry MUST NOT be longer than all result expiries */ if (xhash_iter_first(query->results)) { union xhashv xhv; dnsres_t res; xhv.dnsres_val = &res; do { xhash_iter_get(query->results, NULL, NULL, xhv.val); if (res->expiry > query->s2s->dns_max_ttl) res->expiry = query->s2s->dns_max_ttl; if (res->expiry < query->s2s->dns_min_ttl) res->expiry = query->s2s->dns_min_ttl; res->expiry += now; } while(xhash_iter_next(query->results)); } xhash_free(query->hosts); query->hosts = NULL; if (idna_to_unicode_8z8z(query->name, &domain, 0) != IDNA_SUCCESS) { log_write(query->s2s->log, LOG_ERR, "idna dns decode for %s failed", query->name); /* fake empty results to shortcut resolution failure */ xhash_free(query->results); query->results = xhash_new(71); query->expiry = time(NULL) + 99999999; domain = strdup(query->name); } out_resolve(query->s2s, domain, query->results, query->expiry); free(domain); free((void*)query->name); free(query); } } void dns_resolve_domain(s2s_t s2s, dnscache_t dns) { dnsquery_t query = (dnsquery_t) calloc(1, sizeof(struct dnsquery_st)); char *name; query->s2s = s2s; query->results = xhash_new(71); if (idna_to_ascii_8z(dns->name, &name, 0) != IDNA_SUCCESS) { log_write(s2s->log, LOG_ERR, "idna dns encode for %s failed", dns->name); /* shortcut resolution failure */ query->expiry = time(NULL) + 99999999; out_resolve(query->s2s, dns->name, query->results, query->expiry); return; } query->name = name; query->hosts = xhash_new(71); query->srv_i = -1; query->expiry = 0; query->cur_host = NULL; query->cur_port = 0; query->cur_expiry = 0; query->query = NULL; dns->query = query; log_debug(ZONE, "dns resolve for %s@%p started", query->name, query); /* - resolve all SRV records to host/port * - if no results, include domain/5269 * - resolve all host/port combinations * - return result */ _dns_result_srv(NULL, NULL, query); } /** responses from the resolver */ void out_resolve(s2s_t s2s, const char *domain, xht results, time_t expiry) { dnscache_t dns; /* no results, resolve failed */ if(xhash_count(results) == 0) { dns = xhash_get(s2s->dnscache, domain); if (dns != NULL) { /* store negative DNS cache */ xhash_free(dns->results); dns->query = NULL; dns->results = NULL; dns->expiry = expiry; dns->pending = 0; } log_write(s2s->log, LOG_NOTICE, "dns lookup for %s failed", domain); /* bounce queue */ out_bounce_domain_queues(s2s, domain, stanza_err_REMOTE_SERVER_NOT_FOUND); xhash_free(results); return; } log_write(s2s->log, LOG_NOTICE, "dns lookup for %s returned %d result%s (ttl %d)", domain, xhash_count(results), xhash_count(results)!=1?"s":"", expiry - time(NULL)); /* get the cache entry */ dns = xhash_get(s2s->dnscache, domain); if(dns == NULL) { /* retry using punycode */ char *punydomain; if (idna_to_ascii_8z(domain, &punydomain, 0) == IDNA_SUCCESS) { dns = xhash_get(s2s->dnscache, punydomain); free(punydomain); } } if(dns == NULL) { log_write(s2s->log, LOG_ERR, "weird, never requested %s resolution", domain); return; } /* fill it out */ xhash_free(dns->results); dns->query = NULL; dns->results = results; dns->expiry = expiry; dns->pending = 0; out_flush_domain_queues(s2s, domain); /* delete the cache entry if caching is disabled */ if (!s2s->dns_cache_enabled && !dns->pending) { xhash_free(dns->results); xhash_zap(s2s->dnscache, domain); free(dns); } } /** mio callback for outgoing conns */ static int _out_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { conn_t out = (conn_t) arg; char ipport[INET6_ADDRSTRLEN + 17]; int nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); /* they did something */ out->last_activity = time(NULL); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(out->s); return 0; } return sx_can_read(out->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); /* update activity timestamp */ out->last_activity = time(NULL); return sx_can_write(out->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); jqueue_push(out->s2s->dead, (void *) out->s, 0); log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, out->ip, out->port, out->packet_count); if (out->s2s->out_reuse) { /* generate the ip/port pair */ snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", out->ip, out->port); xhash_zap(out->s2s->out_host, ipport); } if (xhash_iter_first(out->routes)) { char *rkey; int rkeylen; char *c; int c_len; /* remove all the out_dest entries */ do { xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); c = memchr(rkey, '/', rkeylen); c++; c_len = rkeylen - (c - rkey); log_debug(ZONE, "route '%.*s'", rkeylen, rkey); if (xhash_getx(out->s2s->out_dest, c, c_len) != NULL) { log_debug(ZONE, "removing dest entry for '%.*s'", c_len, c); xhash_zapx(out->s2s->out_dest, c, c_len); } } while(xhash_iter_next(out->routes)); } if (xhash_iter_first(out->routes)) { char *rkey; int rkeylen; jqueue_t q; int npkt; /* retry all the routes */ do { xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); q = xhash_getx(out->s2s->outq, rkey, rkeylen); if (out->s2s->retry_limit > 0 && q != NULL && jqueue_age(q) > out->s2s->retry_limit) { log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] retry limit reached for '%.*s' queue", fd->fd, out->ip, out->port, rkeylen, rkey); q = NULL; } if (q != NULL && (npkt = jqueue_size(q)) > 0 && xhash_get(out->states, rkey) != (void*) conn_INPROGRESS) { conn_t retry; log_debug(ZONE, "retrying connection for '%.*s' queue", rkeylen, rkey); if (!out_route(out->s2s, rkey, rkeylen, &retry, 0)) { log_debug(ZONE, "retry successful"); if (retry != NULL) { /* flush queue */ out_flush_route_queue(out->s2s, rkey, rkeylen); } } else { log_debug(ZONE, "retry failed"); /* bounce queue */ out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); _out_dns_mark_bad(out); } } else { /* bounce queue */ out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_REMOTE_SERVER_TIMEOUT); _out_dns_mark_bad(out); } } while(xhash_iter_next(out->routes)); } jqueue_push(out->s2s->dead_conn, (void *) out, 0); case action_ACCEPT: break; } return 0; } void send_dialbacks(conn_t out) { char *rkey; int rkeylen; if (out->s2s->dns_bad_timeout > 0) { dnsres_t bad = xhash_get(out->s2s->dns_bad, out->key); if (bad != NULL) { log_debug(ZONE, "removing bad host entry for '%s'", out->key); xhash_zap(out->s2s->dns_bad, out->key); free((void*)bad->key); free(bad); } } if (xhash_iter_first(out->routes)) { log_debug(ZONE, "sending dialback packets for %s", out->key); do { xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); _out_dialback(out, rkey, rkeylen); } while(xhash_iter_next(out->routes)); } return; } static int _out_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { conn_t out = (conn_t) arg; sx_buf_t buf = (sx_buf_t) data; int len, ns, elem, starttls = 0; sx_error_t *sxe; nad_t nad; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(out->s2s->mio, out->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(out->s2s->mio, out->fd); break; case event_READ: log_debug(ZONE, "reading from %d", out->fd->fd); /* do the read */ len = recv(out->fd->fd, buf->data, buf->len, 0); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", out->fd->fd, out->ip, out->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); if (!out->online) { _out_dns_mark_bad(out); } sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", out->fd->fd); len = send(out->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", out->fd->fd, out->ip, out->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); if (!out->online) { _out_dns_mark_bad(out); } sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", out->fd->fd, out->ip, out->port, sxe->generic, sxe->specific); /* mark as bad if we did not manage to connect or there is unrecoverable stream error */ if (!out->online || (sxe->code == SX_ERR_STREAM && (strstr(sxe->specific, "host-gone") || /* it's not there now */ strstr(sxe->specific, "host-unknown") || /* they do not service the host */ strstr(sxe->specific, "not-authorized") || /* they do not want us there */ strstr(sxe->specific, "see-other-host") || /* we do not support redirections yet */ strstr(sxe->specific, "system-shutdown") || /* they are going down */ strstr(sxe->specific, "policy-violation") || /* they do not want us there */ strstr(sxe->specific, "remote-connection-failed") || /* the required remote entity is gone */ strstr(sxe->specific, "unsupported-encoding") || /* they do not like our encoding */ strstr(sxe->specific, "undefined-condition") || /* something bad happend */ strstr(sxe->specific, "internal-server-error") || /* that server is broken */ strstr(sxe->specific, "unsupported-version") /* they do not support our stream version */ ))) { _out_dns_mark_bad(out); } sx_kill(s); return -1; case event_OPEN: log_debug(ZONE, "OPEN event for %s", out->key); break; case event_STREAM: /* check stream version - NULl = pre-xmpp (some jabber1 servers) */ log_debug(ZONE, "STREAM event for %s stream version is %s", out->key, out->s->res_version); /* first time, bring them online */ if(!out->online) { log_debug(ZONE, "outgoing conn to %s is online", out->key); /* if no stream version from either side, kick off dialback for each route, */ /* otherwise wait for stream features */ if (((out->s->res_version==NULL) || (out->s2s->sx_ssl == NULL)) && out->s2s->require_tls == 0) { log_debug(ZONE, "no stream version, sending dialbacks for %s immediately", out->key); out->online = 1; send_dialbacks(out); } else log_debug(ZONE, "outgoing conn to %s - waiting for STREAM features", out->key); } break; case event_PACKET: /* we're counting packets */ out->packet_count++; out->s2s->packet_count++; nad = (nad_t) data; /* watch for the features packet - STARTTLS and/or SASL*/ if ((out->s->res_version!=NULL) && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS) && strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) == 0 && NAD_ENAME_L(nad, 0) == 8 && strncmp("features", NAD_ENAME(nad, 0), 8) == 0) { log_debug(ZONE, "got the stream features packet"); #ifdef HAVE_SSL /* starttls if we can */ if(out->s2s->sx_ssl != NULL && s->ssf == 0) { ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); if(ns >= 0) { elem = nad_find_elem(nad, 0, ns, "starttls", 1); if(elem >= 0) { log_debug(ZONE, "got STARTTLS in stream features"); if(sx_ssl_client_starttls(out->s2s->sx_ssl, s, out->s2s->local_pemfile, out->s2s->local_private_key_password) == 0) { starttls = 1; nad_free(nad); return 0; } log_write(out->s2s->log, LOG_ERR, "unable to establish encrypted session with peer"); } } } /* If we're not establishing a starttls connection, send dialbacks */ if (!starttls) { if (out->s2s->require_tls == 0 || s->ssf > 0) { log_debug(ZONE, "No STARTTLS, sending dialbacks for %s", out->key); out->online = 1; send_dialbacks(out); } else { log_debug(ZONE, "No STARTTLS, dialbacks disabled for non-TLS connections, cannot complete negotiation"); } } #else if (out->s2s->require_tls == 0) { out->online = 1; send_dialbacks(out); } #endif } /* we only accept dialback packets */ if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != uri_DIALBACK_L || strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), uri_DIALBACK_L) != 0) { log_debug(ZONE, "got a non-dialback packet on an outgoing conn, dropping it"); nad_free(nad); return 0; } /* and then only result and verify */ if(NAD_ENAME_L(nad, 0) == 6) { if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) { _out_result(out, nad); return 0; } if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) { _out_verify(out, nad); return 0; } } log_debug(ZONE, "unknown dialback packet, dropping it"); nad_free(nad); return 0; case event_CLOSED: if (out->fd != NULL) { mio_close(out->s2s->mio, out->fd); out->fd = NULL; } return -1; } return 0; } /** process incoming auth responses */ static void _out_result(conn_t out, nad_t nad) { int attr; jid_t from, to; char *rkey; int rkeylen; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on db result packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on db result packet"); jid_free(from); nad_free(nad); return; } rkey = s2s_route_key(NULL, to->domain, from->domain); rkeylen = strlen(rkey); /* key is valid */ if(nad_find_attr(nad, 0, -1, "type", "valid") >= 0 && xhash_get(out->states, rkey) == (void*) conn_INPROGRESS) { log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now valid %s", out->fd->fd, out->ip, out->port, rkey, _sx_flags(out->s)); xhash_put(out->states, pstrdup(xhash_pool(out->states), rkey), (void *) conn_VALID); /* !!! small leak here */ log_debug(ZONE, "%s valid, flushing queue", rkey); /* flush the queue */ out_flush_route_queue(out->s2s, rkey, rkeylen); free(rkey); jid_free(from); jid_free(to); nad_free(nad); return; } /* invalid */ log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] outgoing route '%s' is now invalid", out->fd->fd, out->ip, out->port, rkey); /* close connection */ log_write(out->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] closing connection", out->fd->fd, out->ip, out->port); /* report stream error */ sx_error(out->s, stream_err_INVALID_ID, "dialback negotiation failed"); /* close the stream */ sx_close(out->s); /* bounce queue */ out_bounce_route_queue(out->s2s, rkey, rkeylen, stanza_err_SERVICE_UNAVAILABLE); free(rkey); jid_free(from); jid_free(to); nad_free(nad); } /** incoming stream authenticated */ static void _out_verify(conn_t out, nad_t nad) { int attr, ns; jid_t from, to; conn_t in; char *rkey; int valid; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on db verify packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on db verify packet"); jid_free(from); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr < 0) { log_debug(ZONE, "missing id on db verify packet"); jid_free(from); jid_free(to); nad_free(nad); return; } /* get the incoming conn */ in = xhash_getx(out->s2s->in, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); if(in == NULL) { log_debug(ZONE, "got a verify for incoming conn %.*s, but it doesn't exist, dropping the packet", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); jid_free(from); jid_free(to); nad_free(nad); return; } rkey = s2s_route_key(NULL, to->domain, from->domain); attr = nad_find_attr(nad, 0, -1, "type", "valid"); if(attr >= 0 && xhash_get(in->states, rkey) == (void*) conn_INPROGRESS) { xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_VALID); log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now valid %s", in->fd->fd, in->ip, in->port, rkey, _sx_flags(in->s)); valid = 1; } else { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming route '%s' is now invalid", in->fd->fd, in->ip, in->port, rkey); valid = 0; } free(rkey); nad_free(nad); /* decrement outstanding verify counter */ --out->verify; /* let them know what happened */ nad = nad_new(); ns = nad_add_namespace(nad, uri_DIALBACK, "db"); nad_append_elem(nad, ns, "result", 0); nad_append_attr(nad, -1, "to", from->domain); nad_append_attr(nad, -1, "from", to->domain); nad_append_attr(nad, -1, "type", valid ? "valid" : "invalid"); /* off it goes */ sx_nad_write(in->s, nad); /* if invalid, close the stream */ if (!valid) { /* generate stream error */ sx_error(in->s, stream_err_INVALID_ID, "dialback negotiation failed"); /* close the incoming stream */ sx_close(in->s); } jid_free(from); jid_free(to); } /* bounce all packets in the queues for domain */ int out_bounce_domain_queues(s2s_t s2s, const char *domain, int err) { char *rkey; int rkeylen; int pktcount = 0; if (xhash_iter_first(s2s->outq)) { do { xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL); if(s2s_route_key_match(NULL, (char *) domain, rkey, rkeylen)) pktcount += out_bounce_route_queue(s2s, rkey, rkeylen, err); } while(xhash_iter_next(s2s->outq)); } return pktcount; } /* bounce all packets in the queue for route */ int out_bounce_route_queue(s2s_t s2s, const char *rkey, int rkeylen, int err) { jqueue_t q; pkt_t pkt; int pktcount = 0; q = xhash_getx(s2s->outq, rkey, rkeylen); if(q == NULL) return 0; while((pkt = jqueue_pull(q)) != NULL) { /* only packets with content, in namespace jabber:client and not already errors */ if(pkt->nad->ecur > 1 && NAD_NURI_L(pkt->nad, NAD_ENS(pkt->nad, 1)) == strlen(uri_CLIENT) && strncmp(NAD_NURI(pkt->nad, NAD_ENS(pkt->nad, 1)), uri_CLIENT, strlen(uri_CLIENT)) == 0 && nad_find_attr(pkt->nad, 0, -1, "error", NULL) < 0) { sx_nad_write(s2s->router, stanza_tofrom(stanza_tofrom(stanza_error(pkt->nad, 1, err), 1), 0)); pktcount++; } else nad_free(pkt->nad); jid_free(pkt->to); jid_free(pkt->from); free(pkt); } /* delete queue and remove domain from queue hash */ log_debug(ZONE, "deleting out packet queue for %.*s", rkeylen, rkey); rkey = q->key; jqueue_free(q); xhash_zap(s2s->outq, rkey); free((void*)rkey); return pktcount; } int out_bounce_conn_queues(conn_t out, int err) { char *rkey; int rkeylen; int pktcount = 0; /* bounce queues for all domains handled by this connection - iterate through routes */ if (xhash_iter_first(out->routes)) { do { xhash_iter_get(out->routes, (const char **) &rkey, &rkeylen, NULL); pktcount += out_bounce_route_queue(out->s2s, rkey, rkeylen, err); } while(xhash_iter_next(out->routes)); } return pktcount; } void out_flush_domain_queues(s2s_t s2s, const char *domain) { char *rkey; int rkeylen; char *c; int c_len; if (xhash_iter_first(s2s->outq)) { do { xhash_iter_get(s2s->outq, (const char **) &rkey, &rkeylen, NULL); c = memchr(rkey, '/', rkeylen); c++; c_len = rkeylen - (c - rkey); if (strncmp(domain, c, c_len) == 0) out_flush_route_queue(s2s, rkey, rkeylen); } while(xhash_iter_next(s2s->outq)); } } void out_flush_route_queue(s2s_t s2s, const char *rkey, int rkeylen) { jqueue_t q; pkt_t pkt; int npkt, i, ret; q = xhash_getx(s2s->outq, rkey, rkeylen); if(q == NULL) return; npkt = jqueue_size(q); log_debug(ZONE, "flushing %d packets for '%.*s' to out_packet", npkt, rkeylen, rkey); for(i = 0; i < npkt; i++) { pkt = jqueue_pull(q); if(pkt) { ret = out_packet(s2s, pkt); if (ret) { /* uh-oh. the queue was deleted... q and pkt have been freed if q->key == rkey, rkey has also been freed */ return; } } } /* delete queue for route and remove route from queue hash */ if (jqueue_size(q) == 0) { log_debug(ZONE, "deleting out packet queue for '%.*s'", rkeylen, rkey); rkey = q->key; jqueue_free(q); xhash_zap(s2s->outq, rkey); free((void*)rkey); } else { log_debug(ZONE, "emptied queue gained more packets..."); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/router.c�����������������������������������������������������������������0000664�0000000�0000000�00000027142�12614627753�0017000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "s2s.h" /** our master callback */ int s2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { s2s_t s2s = (s2s_t) arg; sx_buf_t buf = (sx_buf_t) data; sx_error_t *sxe; nad_t nad; int len, ns, elem, attr, i; pkt_t pkt; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(s2s->mio, s2s->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(s2s->mio, s2s->fd); break; case event_READ: log_debug(ZONE, "reading from %d", s2s->fd->fd); /* do the read */ len = recv(s2s->fd->fd, buf->data, buf->len, 0); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(s2s->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", s2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", s2s->fd->fd); len = send(s2s->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_write(s2s->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", s2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(s2s->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific); if(sxe->code == SX_ERR_AUTH) sx_close(s); break; case event_STREAM: break; case event_OPEN: log_write(s2s->log, LOG_NOTICE, "connection to router established"); /* set connection attempts counter */ s2s->retry_left = s2s->retry_lost; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "bind", 0); nad_append_attr(nad, -1, "name", s2s->id); if(s2s->router_default) nad_append_elem(nad, ns, "default", 1); log_debug(ZONE, "requesting component bind for '%s'", s2s->id); sx_nad_write(s2s->router, nad); break; case event_PACKET: nad = (nad_t) data; /* drop unqualified packets */ if(NAD_ENS(nad, 0) < 0) { nad_free(nad); return 0; } /* watch for the features packet */ if(s->state == state_STREAM) { if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) { log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping"); nad_free(nad); return 0; } #ifdef HAVE_SSL /* starttls if we can */ if(s2s->sx_ssl != NULL && s2s->router_pemfile != NULL && s->ssf == 0) { ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); if(ns >= 0) { elem = nad_find_elem(nad, 0, ns, "starttls", 1); if(elem >= 0) { if(sx_ssl_client_starttls(s2s->sx_ssl, s, s2s->router_pemfile, s2s->router_private_key_password) == 0) { nad_free(nad); return 0; } log_write(s2s->log, LOG_NOTICE, "unable to establish encrypted session with router"); } } } #endif /* !!! pull the list of mechanisms, and choose the best one. * if there isn't an appropriate one, error and bail */ /* authenticate */ sx_sasl_auth(s2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", s2s->router_user, s2s->router_pass); nad_free(nad); return 0; } /* watch for the bind response */ if(s->state == state_OPEN && !s2s->online) { if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) { log_debug(ZONE, "got a packet from router, but we're not online, dropping"); nad_free(nad); return 0; } /* catch errors */ attr = nad_find_attr(nad, 0, -1, "error", NULL); if(attr >= 0) { log_write(s2s->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); exit(1); } log_debug(ZONE, "coming online"); /* if we're coming online for the first time, setup listening sockets */ if(s2s->server_fd == 0) { if(s2s->local_port != 0) { s2s->server_fd = mio_listen(s2s->mio, s2s->local_port, s2s->local_ip, in_mio_callback, (void *) s2s); if(s2s->server_fd == NULL) { log_write(s2s->log, LOG_ERR, "[%s, port=%d] failed to listen", s2s->local_ip, s2s->local_port); exit(1); } else log_write(s2s->log, LOG_NOTICE, "[%s, port=%d] listening for connections", s2s->local_ip, s2s->local_port); } } /* we're online */ s2s->online = s2s->started = 1; log_write(s2s->log, LOG_NOTICE, "ready for connections", s2s->id); nad_free(nad); return 0; } log_debug(ZONE, "got a packet"); /* sanity checks */ if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) { log_debug(ZONE, "unknown namespace, dropping packet"); nad_free(nad); return 0; } if(NAD_ENAME_L(nad, 0) != 5 || strncmp("route", NAD_ENAME(nad, 0), 5) != 0) { log_debug(ZONE, "dropping non-route packet"); nad_free(nad); return 0; } if(nad_find_attr(nad, 0, -1, "type", NULL) >= 0) { log_debug(ZONE, "dropping non-unicast packet"); nad_free(nad); return 0; } /* packets to us */ attr = nad_find_attr(nad, 0, -1, "to", NULL); if(NAD_AVAL_L(nad, attr) == strlen(s2s->id) && strncmp(s2s->id, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0) { log_debug(ZONE, "dropping unknown or invalid packet for s2s component proper"); nad_free(nad); return 0; } /* mangle error packet to create bounce */ if((attr = nad_find_attr(nad, 0, -1, "error", NULL)) >= 0) { log_debug(ZONE, "bouncing error packet"); elem = stanza_err_REMOTE_SERVER_NOT_FOUND; if(attr >= 0) { for(i=0; _stanza_errors[i].code != NULL; i++) if(strncmp(_stanza_errors[i].code, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0) { elem = stanza_err_BAD_REQUEST + i; break; } } stanza_tofrom(stanza_tofrom(stanza_error(nad, 1, elem), 1), 0); if( (elem = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0 ) nad_set_attr(nad, 0, -1, "to", NAD_AVAL(nad, elem), NAD_AVAL_L(nad, elem)); } /* new packet */ pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); pkt->nad = nad; if((attr = nad_find_attr(pkt->nad, 1, -1, "from", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) pkt->from = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); else { attr = nad_find_attr(nad, 0, -1, "from", NULL); pkt->from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); } if((attr = nad_find_attr(pkt->nad, 1, -1, "to", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) pkt->to = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); else { attr = nad_find_attr(nad, 0, -1, "to", NULL); pkt->to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); } /* change the packet so it looks like it came to us, so the router won't reject it if we bounce it later */ nad_set_attr(nad, 0, -1, "to", s2s->id, 0); /* flag dialback */ if(NAD_NURI_L(pkt->nad, 0) == uri_DIALBACK_L && strncmp(uri_DIALBACK, NAD_NURI(pkt->nad, 0), uri_DIALBACK_L) == 0) pkt->db = 1; /* send it out */ out_packet(s2s, pkt); return 0; case event_CLOSED: mio_close(s2s->mio, s2s->fd); s2s->fd = NULL; return -1; } return 0; } int s2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { s2s_t s2s = (s2s_t) arg; int nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(s2s->router); return 0; } return sx_can_read(s2s->router); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(s2s->router); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); log_write(s2s->log, LOG_NOTICE, "connection to router closed"); s2s_lost_router = 1; /* we're offline */ s2s->online = 0; break; case action_ACCEPT: break; } return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/s2s/s2s.h��������������������������������������������������������������������0000664�0000000�0000000�00000025720�12614627753�0016174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "mio/mio.h" #include "sx/sx.h" #ifdef HAVE_SIGNAL_H # include <signal.h> #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #include <udns.h> /* forward decl */ typedef struct host_st *host_t; typedef struct s2s_st *s2s_t; typedef struct pkt_st *pkt_t; typedef struct conn_st *conn_t; typedef struct dnsquery_st *dnsquery_t; typedef struct dnscache_st *dnscache_t; typedef struct dnsres_st *dnsres_t; struct host_st { /** our realm */ const char *realm; /** starttls pemfile */ const char *host_pemfile; /** certificate chain */ const char *host_cachain; /** verify-mode */ int host_verify_mode; /** private key password */ char *host_private_key_password; /** list of TLS ciphers */ const char *host_ciphers; }; struct s2s_st { /** our id (hostname) with the router */ const char *id; /** how to connect to the router */ const char *router_ip; int router_port; const char *router_user; const char *router_pass; const char *router_pemfile; const char *router_cachain; const char *router_private_key_password; const char *router_ciphers; int router_default; /** mio context */ mio_t mio; /** sx environment */ sx_env_t sx_env; sx_plugin_t sx_ssl; sx_plugin_t sx_sasl; sx_plugin_t sx_db; /** router's conn */ sx_t router; mio_fd_t fd; /** listening sockets */ mio_fd_t server_fd; /** config */ config_t config; /** logging */ log_t log; /** log data */ log_type_t log_type; const char *log_facility; const char *log_ident; /** packet counter */ long long int packet_count; const char *packet_stats; /** connect retry */ int retry_init; int retry_lost; int retry_sleep; int retry_left; /** ip/port to listen on */ const char *local_ip; int local_port; /** ip(s) to originate connections from */ const char **origin_ips; int origin_nips; /** dialback secret */ const char *local_secret; /** pemfile for peer connections */ const char *local_pemfile; /** private key password for local pemfile, if encrypted */ const char *local_private_key_password; /** certificate chain */ const char *local_cachain; /** verify-mode */ int local_verify_mode; /** list of TLS ciphers */ const char *local_ciphers; /** hosts mapping */ xht hosts; /** max file descriptors */ int io_max_fds; /** maximum stanza size */ int stanza_size_limit; /** enable Stream Compression */ int compression; /** srvs to lookup */ const char **lookup_srv; int lookup_nsrv; /** if we resolve AAAA records */ int resolve_aaaa; /** dns ttl limits */ int dns_min_ttl; int dns_max_ttl; /** /etc/hosts ttl limits */ int etc_hosts_ttl; /** time checks */ int check_interval; int check_queue; int check_invalid; int check_keepalive; int check_idle; int check_dnscache; int retry_limit; time_t last_queue_check; time_t last_invalid_check; time_t next_check; time_t next_expiry; /** Apple security options */ int require_tls; int enable_whitelist; /*const*/ char **whitelist_domains; // TODO clarify if need to be const int n_whitelist_domains; /** list of sx_t on the way out */ jqueue_t dead; /** list of conn_t on the way out */ jqueue_t dead_conn; /** this is true if we've connected to the router at least once */ int started; /** true if we're bound in the router */ int online; /** queues of packets waiting to go out (key is route) */ xht outq; /** reuse outgoing conns keyed by ip/port */ int out_reuse; /** outgoing conns (key is ip/port) */ xht out_host; /** outgoing conns (key is dest) */ xht out_dest; /** incoming conns (key is stream id) */ xht in; /** incoming conns prior to stream initiation (key is ip/port) */ xht in_accept; /** udns fds */ int udns_fd; mio_fd_t udns_mio_fd; /** dns resolution cache */ xht dnscache; int dns_cache_enabled; /** dns resolution bad host cache */ xht dns_bad; int dns_bad_timeout; }; struct pkt_st { nad_t nad; jid_t from; jid_t to; int db; char ip[INET6_ADDRSTRLEN+1]; int port; }; typedef enum { conn_NONE, conn_INPROGRESS, conn_VALID, conn_INVALID } conn_state_t; struct conn_st { s2s_t s2s; const char *key; const char *dkey; sx_t s; mio_fd_t fd; char ip[INET6_ADDRSTRLEN+1]; int port; /** states of outgoing dialbacks (key is local/remote) */ xht states; /** time of the last state change (key is local/remote) */ xht states_time; /** routes that this conn handles (key is local/remote) */ xht routes; time_t init_time; int online; /** number and last timestamp of outstanding db:verify requests */ int verify; time_t last_verify; /** timestamps for idle timeouts */ time_t last_activity; time_t last_packet; unsigned int packet_count; }; #define DNS_MAX_RESULTS 50 /** dns query data */ struct dnsquery_st { s2s_t s2s; /** domain name */ const char *name; /** srv lookup index */ int srv_i; /** srv lookup results (key host/port) */ xht hosts; /** current host lookup name */ const char *cur_host; /** current host lookup port */ int cur_port; /** current host max expiry */ time_t cur_expiry; /** current host priority */ int cur_prio; /** current host weight */ int cur_weight; /** host lookup results (key ip/port) */ xht results; /** time that all entries expire */ time_t expiry; /** set when we're waiting for a resolve response */ struct dns_query *query; }; /** one item in the dns resolution cache */ struct dnscache_st { /** the name proper */ char name[1024]; /** results (key ip/port) */ xht results; /** time that this entry expires */ time_t expiry; time_t init_time; /** set when we're waiting for a resolve response */ int pending; dnsquery_t query; }; /** dns resolution results */ struct dnsres_st { /** ip/port */ const char *key; /** host priority */ int prio; /** host weight */ int weight; /** time that this entry expires */ time_t expiry; }; extern sig_atomic_t s2s_lost_router; int s2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); int s2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); int s2s_domain_in_whitelist(s2s_t s2s, const char *in_domain); char *s2s_route_key(pool_t p, const char *local, const char *remote); int s2s_route_key_match(char *local, const char *remote, const char *rkey, int rkeylen); char *s2s_db_key(pool_t p, const char *secret, const char *remote, const char *id); char *dns_make_ipport(const char* host, int port); int out_packet(s2s_t s2s, pkt_t pkt); int out_route(s2s_t s2s, const char *route, int routelen, conn_t *out, int allow_bad); int dns_select(s2s_t s2s, char* ip, int* port, time_t now, dnscache_t dns, int allow_bad); void dns_resolve_domain(s2s_t s2s, dnscache_t dns); void out_resolve(s2s_t s2s, const char *domain, xht results, time_t expiry); void out_dialback(s2s_t s2s, pkt_t pkt); int out_bounce_domain_queues(s2s_t s2s, const char *domain, int err); int out_bounce_route_queue(s2s_t s2s, const char *rkey, int rkeylen, int err); int out_bounce_conn_queues(conn_t out, int err); void out_flush_domain_queues(s2s_t s2s, const char *domain); void out_flush_route_queue(s2s_t s2s, const char *rkey, int rkeylen); int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); /* sx flag for outgoing dialback streams */ #define S2S_DB_HEADER (1<<10) /* max length of FQDN for whitelist matching */ #define MAX_DOMAIN_LEN 1023 int s2s_db_init(sx_env_t env, sx_plugin_t p, va_list args); /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; char **char_val; conn_t *conn_val; conn_state_t *state_val; jqueue_t *jq_val; dnscache_t *dns_val; dnsres_t *dnsres_val; }; void out_pkt_free(pkt_t pkt); ������������������������������������������������jabberd2-jabberd-2.3.4/s2s/util.c�������������������������������������������������������������������0000664�0000000�0000000�00000004546�12614627753�0016440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #define _GNU_SOURCE #include <string.h> #include "s2s.h" /** generate a local/remote route key */ char *s2s_route_key(pool_t p, const char *local, const char *remote) { char *key; if(local == NULL) local = ""; if(remote == NULL) remote = ""; if(p == NULL) key = (char *) malloc(strlen(local) + strlen(remote) + 2); else key = (char *) pmalloc(p, strlen(local) + strlen(remote) + 2); sprintf(key, "%s/%s", local, remote); return key; } /** match route key - used for searching route hash */ int s2s_route_key_match(char *local, const char *remote, const char *rkey, int rkeylen) { char *klocal, *kremote; int ret; klocal = strndup(rkey, rkeylen); kremote = strchr(klocal, '/'); if(kremote != NULL) *kremote++ = '\0'; ret = (local == NULL || (klocal != NULL && !strcmp(local, klocal))) && (remote == NULL || (kremote != NULL && !strcmp(remote, kremote))); free(klocal); return ret; } /** generate a dialback key */ char *s2s_db_key(pool_t p, const char *secret, const char *remote, const char *id) { char hash[41], buf[1024]; _sx_debug(ZONE, "generating dialback key, secret %s, remote %s, id %s", secret, remote, id); shahash_r(secret, hash); snprintf(buf, 1024, "%s%s", hash, remote); shahash_r(buf, hash); snprintf(buf, 1024, "%s%s", hash, id); shahash_r(buf, hash); _sx_debug(ZONE, "dialback key generated: %s", hash); if(p == NULL) return strdup(hash); else return pstrdup(p, hash); } ����������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/��������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015216�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/Makefile.am���������������������������������������������������������������0000664�0000000�0000000�00000012716�12614627753�0017261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet bin_PROGRAMS = sm pkglib_LTLIBRARIES = mod_active.la \ mod_announce.la \ mod_amp.la \ mod_deliver.la \ mod_disco.la \ mod_echo.la \ mod_help.la \ mod_iq-last.la \ mod_iq-ping.la \ mod_iq-private.la \ mod_iq-time.la \ mod_iq-vcard.la \ mod_iq-version.la \ mod_offline.la \ mod_pep.la \ mod_presence.la \ mod_privacy.la \ mod_roster.la \ mod_roster-publish.la \ mod_session.la \ mod_status.la \ mod_template-roster.la \ mod_vacation.la \ mod_validate.la noinst_HEADERS = sm.h sm_SOURCES = aci.c \ dispatch.c \ feature.c \ main.c \ mm.c \ pkt.c \ pres.c \ sess.c \ sm.c \ user.c sm_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -DLIBRARY_DIR=\"$(pkglibdir)\" -I@top_srcdir@ sm_LDFLAGS = -export-dynamic sm_LDADD = $(top_builddir)/sx/libsx.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/storage/libstorage.la if USE_LIBSUBST sm_LDADD += $(top_builddir)/subst/libsubst.la endif mod_active_la_SOURCES = mod_active.c mod_active_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_active_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_announce_la_SOURCES = mod_announce.c mod_announce_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_announce_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_amp_la_SOURCES = mod_amp.c mod_amp_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_amp_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_deliver_la_SOURCES = mod_deliver.c mod_deliver_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_deliver_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_disco_la_SOURCES = mod_disco.c mod_disco_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_disco_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_echo_la_SOURCES = mod_echo.c mod_echo_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_echo_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_help_la_SOURCES = mod_help.c mod_help_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_help_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_last_la_SOURCES = mod_iq_last.c mod_iq_last_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_last_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_ping_la_SOURCES = mod_iq_ping.c mod_iq_ping_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_ping_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_private_la_SOURCES = mod_iq_private.c mod_iq_private_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_private_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_time_la_SOURCES = mod_iq_time.c mod_iq_time_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_time_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_vcard_la_SOURCES = mod_iq_vcard.c mod_iq_vcard_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_vcard_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_iq_version_la_SOURCES = mod_iq_version.c mod_iq_version_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_iq_version_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_offline_la_SOURCES = mod_offline.c mod_offline_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_offline_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_pep_la_SOURCES = mod_pep.c mod_pep_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_pep_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_presence_la_SOURCES = mod_presence.c mod_presence_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_presence_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_privacy_la_SOURCES = mod_privacy.c mod_privacy_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_privacy_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_roster_la_SOURCES = mod_roster.c mod_roster_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_roster_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_roster_publish_la_SOURCES = mod_roster_publish.c mod_roster_publish_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_roster_publish_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_session_la_SOURCES = mod_session.c mod_session_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_session_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_status_la_SOURCES = mod_status.c mod_status_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_status_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_template_roster_la_SOURCES = mod_template_roster.c mod_template_roster_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_template_roster_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_vacation_la_SOURCES = mod_vacation.c mod_vacation_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_vacation_la_LIBADD = $(top_builddir)/subst/libsubst.la endif mod_validate_la_SOURCES = mod_validate.c mod_validate_la_LDFLAGS = -module -export-dynamic if USE_LIBSUBST mod_validate_la_LIBADD = $(top_builddir)/subst/libsubst.la endif ��������������������������������������������������jabberd2-jabberd-2.3.4/sm/aci.c���������������������������������������������������������������������0000664�0000000�0000000�00000007565�12614627753�0016133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/aci.c * @brief access control manager * @author Robert Norris * $Date: 2005/09/10 10:23:50 $ * $Revision: 1.16 $ */ xht aci_load(sm_t sm) { xht acls; int aelem, jelem, attr; char type[33]; jid_t list, jid; log_debug(ZONE, "loading aci"); acls = xhash_new(51); if((aelem = nad_find_elem(sm->config->nad, 0, -1, "aci", 1)) < 0) return acls; aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 1); while(aelem >= 0) { list = NULL; if((attr = nad_find_attr(sm->config->nad, aelem, -1, "type", NULL)) < 0) { aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); continue; } snprintf(type, 33, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr)); log_debug(ZONE, "building list for '%s'", type); jelem = nad_find_elem(sm->config->nad, aelem, -1, "jid", 1); while(jelem >= 0) { if(NAD_CDATA_L(sm->config->nad, jelem) > 0) { jid = jid_new(NAD_CDATA(sm->config->nad, jelem), NAD_CDATA_L(sm->config->nad, jelem)); list = jid_append(list, jid); log_debug(ZONE, "added '%s'", jid_user(jid)); jid_free(jid); } jelem = nad_find_elem(sm->config->nad, jelem, -1, "jid", 0); } if(list != NULL) { xhash_put(acls, pstrdup(xhash_pool(acls), type), (void *) list); } aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); } return acls; } /** see if a jid is in an acl */ int aci_check(xht acls, const char *type, jid_t jid) { jid_t list, dup; dup = jid_dup(jid); if (dup->resource[0]) { /* resourceless version */ dup->resource[0] = '\0'; dup->dirty = 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_full(jid)); list = (jid_t) xhash_get(acls, "all"); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_user(dup)); if(jid_search(list, dup)) { jid_free(dup); return 1; } if(type != NULL) { log_debug(ZONE, "checking for '%s' in acl '%s'", jid_full(jid), type); list = (jid_t) xhash_get(acls, type); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl '%s'", jid_user(dup), type); if(jid_search(list, dup)) { jid_free(dup); return 1; } } jid_free(dup); return 0; } void aci_unload(xht acls) { jid_t list, jid; log_debug(ZONE, "unloading acls"); if(xhash_iter_first(acls)) do { xhash_iter_get(acls, NULL, NULL, (void *) &list); while (list != NULL) { jid = list; list = list->next; jid_free(jid); } } while(xhash_iter_next(acls)); return; } �������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/dispatch.c����������������������������������������������������������������0000664�0000000�0000000�00000011653�12614627753�0017167�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/dispatch.c * @brief packet dispatcher * @author Robert Norris * $Date: 2005/09/09 05:31:04 $ * $Revision: 1.18 $ */ /** main packet dispatcher */ void dispatch(sm_t sm, pkt_t pkt) { user_t user; mod_ret_t ret; /* handle broadcasts */ if(pkt->rtype == route_BROADCAST) { log_debug(ZONE, "can't handle broadcast routes (yet), dropping"); pkt_free(pkt); return; } /* routing errors, add a im error */ if(pkt->rtype & route_ERROR) { int i, aerror, stanza_err; aerror = nad_find_attr(pkt->nad, 0, -1, "error", NULL); stanza_err = stanza_err_REMOTE_SERVER_NOT_FOUND; if(aerror >= 0) { for(i=0; _stanza_errors[i].code != NULL; i++) if(strncmp(_stanza_errors[i].code, NAD_AVAL(pkt->nad, aerror), NAD_AVAL_L(pkt->nad, aerror)) == 0) { stanza_err = stanza_err_BAD_REQUEST + i; break; } } if(pkt_error(pkt, stanza_err) == NULL) return; } /* * - if its from the router (non-route) it goes straight to pkt_router * - hand it to in_router chain * - if its for the sm itself (no user), hand it to the pkt_sm chain * - find the user * - hand to pkt_user */ /* non route packets are special-purpose things from the router */ if(!(pkt->rtype & route_UNICAST)) { ret = mm_pkt_router(pkt->sm->mm, pkt); switch(ret) { case mod_HANDLED: break; case mod_PASS: default: /* don't ever bounce these */ pkt_free(pkt); break; } return; } /* preprocessing */ if (pkt != NULL && pkt->sm != NULL) { ret = mm_in_router(pkt->sm->mm, pkt); switch(ret) { case mod_HANDLED: return; case mod_PASS: break; default: pkt_router(pkt_error(pkt, -ret)); return; } } /* has to come from someone and be directed to someone */ if(pkt->from == NULL || pkt->to == NULL) { pkt_router(pkt_error(pkt, stanza_err_BAD_REQUEST)); return; } /* packet is for the sm itself */ if(*pkt->to->node == '\0') { ret = mm_pkt_sm(pkt->sm->mm, pkt); switch(ret) { case mod_HANDLED: break; case mod_PASS: /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */ if(pkt->type == pkt_IQ_RESULT) { pkt_free(pkt); break; } else ret = -stanza_err_FEATURE_NOT_IMPLEMENTED; default: pkt_router(pkt_error(pkt, -ret)); break; } return; } /* get the user */ user = user_load(sm, pkt->to); if(user == NULL) { if(pkt->type & pkt_PRESENCE && pkt->type != pkt_PRESENCE_PROBE) { pkt_free(pkt); return; } if(pkt->type == pkt_PRESENCE_PROBE) { pkt_router(pkt_create(pkt->sm, "presence", "unsubscribed", jid_full(pkt->from), jid_full(pkt->to))); pkt_free(pkt); return; } pkt_router(pkt_error(pkt, stanza_err_SERVICE_UNAVAILABLE)); return; } if (pkt->sm != NULL) { ret = mm_pkt_user(pkt->sm->mm, user, pkt); switch(ret) { case mod_HANDLED: break; case mod_PASS: /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */ if(pkt->type == pkt_IQ_RESULT) { pkt_free(pkt); break; } else ret = -stanza_err_FEATURE_NOT_IMPLEMENTED; default: pkt_router(pkt_error(pkt, -ret)); break; } } /* if they have no sessions, they were only loaded to do delivery, so free them */ if(user->sessions == NULL) user_free(user); } �������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/feature.c�����������������������������������������������������������������0000664�0000000�0000000�00000003536�12614627753�0017024�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/feature.c * @brief feature registration * @author Robert Norris * $Date: 2005/08/17 11:10:12 $ * $Revision: 1.9 $ */ /* * these are simple wrappers around xhash for the moment. perhaps a little * redundant, but they will give a good abstraction, and make it easier to * add stuff in the future .. f-neg comes to mind. */ /** register a feature */ void feature_register(sm_t sm, const char *feature) { log_debug(ZONE, "registering feature %s", feature); xhash_put(sm->features, pstrdup(xhash_pool(sm->features), feature), (void *) ((long) xhash_get(sm->features, feature) + 1)); } /** unregister feature */ void feature_unregister(sm_t sm, const char *feature) { int refcount = (int) (long) xhash_get(sm->features, feature); log_debug(ZONE, "unregistering feature %s", feature); if (refcount == 1) { xhash_zap(sm->features, feature); } else if (refcount > 1) { xhash_put(sm->features, feature, (void *) ((long) refcount - 1)); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/main.c��������������������������������������������������������������������0000664�0000000�0000000�00000033532�12614627753�0016314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" #include <stringprep.h> /** @file sm/main.c * @brief initialisation * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.57 $ */ static sig_atomic_t sm_shutdown = 0; static sig_atomic_t sm_logrotate = 0; static sm_t sm = NULL; static char* config_file; static void _sm_signal(int signum) { sm_shutdown = 1; sm_lost_router = 0; } static void _sm_signal_hup(int signum) { config_t conf; log_write(sm->log, LOG_NOTICE, "HUP handled. reloading modules..."); sm_logrotate = 1; /* reload dynamic modules */ conf = config_new(); if (conf && config_load(conf, config_file) == 0) { config_free(sm->config); sm->config = conf; /*_sm_config_expand(sm);*/ /* we want to reload modules only */ } else { log_write(sm->log, LOG_WARNING, "couldn't reload config (%s)", config_file); if (conf) config_free(conf); } mm_free(sm->mm); sm->mm = mm_new(sm); } static void _sm_signal_usr1(int signum) { set_debug_flag(0); } static void _sm_signal_usr2(int signum) { set_debug_flag(1); } /** store the process id */ static void _sm_pidfile(sm_t sm) { const char *pidfile; FILE *f; pid_t pid; pidfile = config_get_one(sm->config, "pidfile", 0); if(pidfile == NULL) return; pid = getpid(); if((f = fopen(pidfile, "w+")) == NULL) { log_write(sm->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno)); return; } if(fprintf(f, "%d", pid) < 0) { log_write(sm->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno)); fclose(f); return; } fclose(f); log_write(sm->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile); } /** pull values out of the config file */ static void _sm_config_expand(sm_t sm) { char *str; config_elem_t elem; set_debug_log_from_config(sm->config); sm->id = config_get_one(sm->config, "id", 0); if(sm->id == NULL) sm->id = "sm"; sm->router_ip = config_get_one(sm->config, "router.ip", 0); if(sm->router_ip == NULL) sm->router_ip = "127.0.0.1"; sm->router_port = j_atoi(config_get_one(sm->config, "router.port", 0), 5347); sm->router_user = config_get_one(sm->config, "router.user", 0); if(sm->router_user == NULL) sm->router_user = "jabberd"; sm->router_pass = config_get_one(sm->config, "router.pass", 0); if(sm->router_pass == NULL) sm->router_pass = "secret"; sm->router_pemfile = config_get_one(sm->config, "router.pemfile", 0); sm->router_private_key_password = config_get_one(sm->config, "router.private_key_password", 0); sm->router_ciphers = config_get_one(sm->config, "router.ciphers", 0); sm->retry_init = j_atoi(config_get_one(sm->config, "router.retry.init", 0), 3); sm->retry_lost = j_atoi(config_get_one(sm->config, "router.retry.lost", 0), 3); if((sm->retry_sleep = j_atoi(config_get_one(sm->config, "router.retry.sleep", 0), 2)) < 1) sm->retry_sleep = 1; sm->log_type = log_STDOUT; if(config_get(sm->config, "log") != NULL) { if((str = config_get_attr(sm->config, "log", 0, "type")) != NULL) { if(strcmp(str, "file") == 0) sm->log_type = log_FILE; else if(strcmp(str, "syslog") == 0) sm->log_type = log_SYSLOG; } } if(sm->log_type == log_SYSLOG) { sm->log_facility = config_get_one(sm->config, "log.facility", 0); sm->log_ident = config_get_one(sm->config, "log.ident", 0); if(sm->log_ident == NULL) sm->log_ident = "jabberd/sm"; } else if(sm->log_type == log_FILE) sm->log_ident = config_get_one(sm->config, "log.file", 0); elem = config_get(sm->config, "storage.limits.queries"); if(elem != NULL) { sm->query_rate_total = j_atoi(elem->values[0], 0); if(sm->query_rate_total != 0) { sm->query_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5); sm->query_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 60); } } } static void _sm_hosts_expand(sm_t sm) { config_elem_t elem; char id[1024]; int i; elem = config_get(sm->config, "local.id"); if(!elem) { /* use SM id */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), sm->id), sm); log_write(sm->log, LOG_NOTICE, "id: %s", sm->id); return; } for(i = 0; i < elem->nvalues; i++) { /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } /* insert into vHosts xhash */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), id), sm); log_write(sm->log, LOG_NOTICE, "[%s] configured", id); } } static int _sm_router_connect(sm_t sm) { log_write(sm->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", sm->router_ip, sm->router_port); sm->fd = mio_connect(sm->mio, sm->router_port, sm->router_ip, NULL, sm_mio_callback, (void *) sm); if(sm->fd == NULL) { if(errno == ECONNREFUSED) sm_lost_router = 1; log_write(sm->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR); return 1; } sm->router = sx_new(sm->sx_env, sm->fd->fd, sm_sx_callback, (void *) sm); sx_client_init(sm->router, 0, NULL, NULL, NULL, "1.0"); return 0; } JABBER_MAIN("jabberd2sm", "Jabber 2 Session Manager", "Jabber Open Source Server: Session Manager", "jabberd2router\0") { int optchar; sess_t sess; char id[1024]; #ifdef POOL_DEBUG time_t pool_time = 0; #endif const char *cli_id = 0; #ifdef HAVE_UMASK umask((mode_t) 0027); #endif srand(time(NULL)); #ifdef HAVE_WINSOCK2_H /* get winsock running */ { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* !!! tell user that we couldn't find a usable winsock dll */ return 0; } } #endif jabber_signal(SIGINT, _sm_signal); jabber_signal(SIGTERM, _sm_signal); #ifdef SIGHUP jabber_signal(SIGHUP, _sm_signal_hup); #endif #ifdef SIGPIPE jabber_signal(SIGPIPE, SIG_IGN); #endif jabber_signal(SIGUSR1, _sm_signal_usr1); jabber_signal(SIGUSR2, _sm_signal_usr2); sm = (sm_t) calloc(1, sizeof(struct sm_st)); /* load our config */ sm->config = config_new(); config_file = CONFIG_DIR "/sm.xml"; /* cmdline parsing */ while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0) { switch(optchar) { case 'c': config_file = optarg; break; case 'D': #ifdef DEBUG set_debug_flag(1); #else printf("WARN: Debugging not enabled. Ignoring -D.\n"); #endif break; case 'i': cli_id = optarg; break; case 'h': case '?': default: fputs( "sm - jabberd session manager (" VERSION ")\n" "Usage: sm <options>\n" "Options are:\n" " -c <config> config file to use [default: " CONFIG_DIR "/sm.xml]\n" " -i id Override <id> config element\n" #ifdef DEBUG " -D Show debug output\n" #endif , stdout); config_free(sm->config); free(sm); return 1; } } if(config_load_with_id(sm->config, config_file, cli_id) != 0) { fputs("sm: couldn't load config, aborting\n", stderr); config_free(sm->config); free(sm); return 2; } _sm_config_expand(sm); sm->log = log_new(sm->log_type, sm->log_ident, sm->log_facility); log_write(sm->log, LOG_NOTICE, "starting up"); /* stringprep id (domain name) so that it's in canonical form */ strncpy(id, sm->id, 1024); id[sizeof(id)-1] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", sm->id); exit(1); } sm->id = id; _sm_pidfile(sm); sm_signature(sm, PACKAGE " sm " VERSION); /* start storage */ sm->st = storage_new(sm->config, sm->log); if (sm->st == NULL) { log_write(sm->log, LOG_ERR, "failed to initialise one or more storage drivers, aborting"); exit(1); } /* pre-index known namespaces */ sm->xmlns = xhash_new(101); xhash_put(sm->xmlns, uri_AUTH, (void *) ns_AUTH); xhash_put(sm->xmlns, uri_REGISTER, (void *) ns_REGISTER); xhash_put(sm->xmlns, uri_ROSTER, (void *) ns_ROSTER); xhash_put(sm->xmlns, uri_AGENTS, (void *) ns_AGENTS); xhash_put(sm->xmlns, uri_DELAY, (void *) ns_DELAY); xhash_put(sm->xmlns, uri_BROWSE, (void *) ns_BROWSE); xhash_put(sm->xmlns, uri_EVENT, (void *) ns_EVENT); xhash_put(sm->xmlns, uri_GATEWAY, (void *) ns_GATEWAY); xhash_put(sm->xmlns, uri_EXPIRE, (void *) ns_EXPIRE); xhash_put(sm->xmlns, uri_SEARCH, (void *) ns_SEARCH); xhash_put(sm->xmlns, uri_DISCO, (void *) ns_DISCO); xhash_put(sm->xmlns, uri_DISCO_ITEMS, (void *) ns_DISCO_ITEMS); xhash_put(sm->xmlns, uri_DISCO_INFO, (void *) ns_DISCO_INFO); sm->xmlns_refcount = xhash_new(101); /* supported features */ sm->features = xhash_new(101); /* load acls */ sm->acls = aci_load(sm); /* the core supports iq, everything else is handled by the modules */ feature_register(sm, "iq"); /* startup the modules */ sm->mm = mm_new(sm); log_write(sm->log, LOG_NOTICE, "version: %s", sm->signature); sm->sessions = xhash_new(401); sm->users = xhash_new(401); sm->query_rates = xhash_new(101); sm->sx_env = sx_env_new(); #ifdef HAVE_SSL if(sm->router_pemfile != NULL) { sm->sx_ssl = sx_env_plugin(sm->sx_env, sx_ssl_init, NULL, sm->router_pemfile, NULL, NULL, sm->router_private_key_password, sm->router_ciphers); if(sm->sx_ssl == NULL) { log_write(sm->log, LOG_ERR, "failed to load SSL pemfile, SSL disabled"); sm->router_pemfile = NULL; } } #endif /* get sasl online */ sm->sx_sasl = sx_env_plugin(sm->sx_env, sx_sasl_init, "xmpp", NULL, NULL); if(sm->sx_sasl == NULL) { log_write(sm->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); } sm->mio = mio_new(MIO_MAXFD); /* vHosts map */ sm->hosts = xhash_new(1021); _sm_hosts_expand(sm); sm->retry_left = sm->retry_init; _sm_router_connect(sm); while(!sm_shutdown) { mio_run(sm->mio, 5); if(sm_logrotate) { set_debug_log_from_config(sm->config); log_write(sm->log, LOG_NOTICE, "reopening log ..."); log_free(sm->log); sm->log = log_new(sm->log_type, sm->log_ident, sm->log_facility); log_write(sm->log, LOG_NOTICE, "log started"); sm_logrotate = 0; } if(sm_lost_router) { if(sm->retry_left < 0) { log_write(sm->log, LOG_NOTICE, "attempting reconnect"); sleep(sm->retry_sleep); sm_lost_router = 0; if (sm->router) sx_free(sm->router); _sm_router_connect(sm); } else if(sm->retry_left == 0) { sm_shutdown = 1; } else { log_write(sm->log, LOG_NOTICE, "attempting reconnect (%d left)", sm->retry_left); sm->retry_left--; sleep(sm->retry_sleep); sm_lost_router = 0; if (sm->router) sx_free(sm->router); _sm_router_connect(sm); } } #ifdef POOL_DEBUG if(time(NULL) > pool_time + 60) { pool_stat(1); pool_time = time(NULL); } #endif } log_write(sm->log, LOG_NOTICE, "shutting down"); /* shut down sessions */ if(xhash_iter_first(sm->sessions)) do { xhash_iter_get(sm->sessions, NULL, NULL, (void *) &sess); sm_c2s_action(sess, "ended", NULL); sess_end(sess); } while (xhash_iter_next(sm->sessions)); xhash_free(sm->sessions); if (sm->fd) mio_close(sm->mio, sm->fd); mio_free(sm->mio); mm_free(sm->mm); storage_free(sm->st); aci_unload(sm->acls); xhash_free(sm->acls); xhash_free(sm->features); xhash_free(sm->xmlns); xhash_free(sm->xmlns_refcount); xhash_free(sm->users); xhash_free(sm->hosts); xhash_free(sm->query_rates); sx_free(sm->router); sx_env_free(sm->sx_env); log_free(sm->log); config_free(sm->config); free(sm); #ifdef POOL_DEBUG pool_stat(1); #endif #ifdef HAVE_WINSOCK2_H WSACleanup(); #endif return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mm.c����������������������������������������������������������������������0000664�0000000�0000000�00000055711�12614627753�0016004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" #ifdef _WIN32 # define LIBRARY_DIR "." # include <windows.h> #else # include <dlfcn.h> #endif /* _WIN32 */ /** @file sm/mm.c * @brief module manager * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.40 $ */ /* these functions implement a multiplexor to get calls to the correct module * for the given type */ /* Notes on dynamic modules (cedricv@) : Modules are searched by name mod_[modulename].so or mod_[modulename].dll depending platform. You have to set <path>[full_path]</path> within <modules> in sm.xml config, else it will only search in LD_LIBRARY_PATH or c:\windows\system32 */ mm_t mm_new(sm_t sm) { mm_t mm; int celem, melem, attr, *nlist = NULL; char id[13], name[32], mod_fullpath[PATH_MAX], arg[1024]; const char *modules_path; mod_chain_t chain = (mod_chain_t) NULL; mod_instance_t **list = NULL, mi; module_t mod; mm = (mm_t) calloc(1, sizeof(struct mm_st)); mm->sm = sm; mm->modules = xhash_new(101); if((celem = nad_find_elem(sm->config->nad, 0, -1, "modules", 1)) < 0) return mm; modules_path = config_get_one(sm->config, "modules.path", 0); if (modules_path != NULL) log_write(sm->log, LOG_NOTICE, "modules search path: %s", modules_path); else log_write(sm->log, LOG_NOTICE, "modules search path undefined, using default: "LIBRARY_DIR); celem = nad_find_elem(sm->config->nad, celem, -1, "chain", 1); while(celem >= 0) { if((attr = nad_find_attr(sm->config->nad, celem, -1, "id", NULL)) < 0) { celem = nad_find_elem(sm->config->nad, celem, -1, "chain", 0); continue; } snprintf(id, 13, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr)); id[12] = '\0'; log_debug(ZONE, "processing config for chain '%s'", id); list = NULL; if(strcmp(id, "sess-start") == 0) { chain = chain_SESS_START; list = &mm->sess_start; nlist = &mm->nsess_start; } else if(strcmp(id, "sess-end") == 0) { chain = chain_SESS_END; list = &mm->sess_end; nlist = &mm->nsess_end; } else if(strcmp(id, "in-sess") == 0) { chain = chain_IN_SESS; list = &mm->in_sess; nlist = &mm->nin_sess; } else if(strcmp(id, "in-router") == 0) { chain = chain_IN_ROUTER; list = &mm->in_router; nlist = &mm->nin_router; } else if(strcmp(id, "out-sess") == 0) { chain = chain_OUT_SESS; list = &mm->out_sess; nlist = &mm->nout_sess; } else if(strcmp(id, "out-router") == 0) { chain = chain_OUT_ROUTER; list = &mm->out_router; nlist = &mm->nout_router; } else if(strcmp(id, "pkt-sm") == 0) { chain = chain_PKT_SM; list = &mm->pkt_sm; nlist = &mm->npkt_sm; } else if(strcmp(id, "pkt-user") == 0) { chain = chain_PKT_USER; list = &mm->pkt_user; nlist = &mm->npkt_user; } else if(strcmp(id, "pkt-router") == 0) { chain = chain_PKT_ROUTER; list = &mm->pkt_router; nlist = &mm->npkt_router; } else if(strcmp(id, "user-load") == 0) { chain = chain_USER_LOAD; list = &mm->user_load; nlist = &mm->nuser_load; } else if(strcmp(id, "user-unload") == 0) { chain = chain_USER_UNLOAD; list = &mm->user_unload; nlist = &mm->nuser_unload; } else if(strcmp(id, "user-create") == 0) { chain = chain_USER_CREATE; list = &mm->user_create; nlist = &mm->nuser_create; } else if(strcmp(id, "user-delete") == 0) { chain = chain_USER_DELETE; list = &mm->user_delete; nlist = &mm->nuser_delete; } else if(strcmp(id, "disco-extend") == 0) { chain = chain_DISCO_EXTEND; list = &mm->disco_extend; nlist = &mm->ndisco_extend; } if(list == NULL) { log_write(sm->log, LOG_ERR, "unknown chain type '%s'", id); celem = nad_find_elem(sm->config->nad, celem, -1, "chain", 0); continue; } melem = nad_find_elem(sm->config->nad, celem, -1, "module", 1); while(melem >= 0) { if(NAD_CDATA_L(sm->config->nad, melem) <= 0) { melem = nad_find_elem(sm->config->nad, melem, -1, "module", 0); continue; } arg[0] = '\0'; attr = nad_find_attr(sm->config->nad, melem, -1, "arg", NULL); if(attr >= 0) { snprintf(arg, 1024, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr)); log_debug(ZONE, "module arg: %s", arg); } snprintf(name, 32, "%.*s", NAD_CDATA_L(sm->config->nad, melem), NAD_CDATA(sm->config->nad, melem)); mod = xhash_get(mm->modules, name); if(mod == NULL) { mod = (module_t) calloc(1, sizeof(struct module_st)); mod->mm = mm; mod->index = mm->nindex; mod->name = strdup(name); #ifndef _WIN32 if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s/mod_%s.so", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "%s/mod_%s.so", LIBRARY_DIR, name); mod->handle = dlopen(mod_fullpath, RTLD_LAZY); if (mod->handle != NULL) mod->module_init_fn = dlsym(mod->handle, "module_init"); #else if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s\\mod_%s.dll", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "mod_%s.dll", name); mod->handle = (void*) LoadLibrary(mod_fullpath); if (mod->handle != NULL) mod->module_init_fn = (int (*)(mod_instance_t))GetProcAddress((HMODULE) mod->handle, "module_init"); #endif if (mod->handle != NULL && mod->module_init_fn != NULL) { log_debug(ZONE, "preloaded module '%s' to chain '%s' (not added yet)", name, id); xhash_put(mm->modules, mod->name, (void *) mod); mm->nindex++; } else { #ifndef _WIN32 log_write(sm->log, LOG_ERR, "failed loading module '%s' to chain '%s' (%s)", name, id, dlerror()); if (mod->handle != NULL) dlclose(mod->handle); #else log_write(sm->log, LOG_ERR, "failed loading module '%s' to chain '%s' (errcode: %x)", name, id, GetLastError()); if (mod->handle != NULL) FreeLibrary((HMODULE) mod->handle); #endif melem = nad_find_elem(sm->config->nad, melem, -1, "module", 0); continue; } } mi = (mod_instance_t) calloc(1, sizeof(struct mod_instance_st)); mi->sm = sm; mi->mod = mod; mi->chain = chain; mi->arg = (arg[0] == '\0') ? NULL : strdup(arg); mi->seq = mod->init; if(mod->module_init_fn(mi) != 0) { log_write(sm->log, LOG_ERR, "init for module '%s' (seq %d) failed", name, mi->seq); free(mi); if(mod->init == 0) { xhash_zap(mm->modules, mod->name); #ifndef _WIN32 if (mod->handle != NULL) dlclose(mod->handle); #else if (mod->handle != NULL) FreeLibrary((HMODULE) mod->handle); #endif free((void*)mod->name); free(mod); mm->nindex--; melem = nad_find_elem(sm->config->nad, melem, -1, "module", 0); continue; } } mod->init++; *list = (mod_instance_t *) realloc(*list, sizeof(mod_instance_t) * (*nlist + 1)); (*list)[*nlist] = mi; log_write(sm->log, LOG_NOTICE, "module '%s' added to chain '%s' (order %d index %d seq %d)", mod->name, id, *nlist, mod->index, mi->seq); (*nlist)++; melem = nad_find_elem(sm->config->nad, melem, -1, "module", 0); } celem = nad_find_elem(sm->config->nad, celem, -1, "chain", 0); } return mm; } static void _mm_reaper(const char *module, int modulelen, void *val, void *arg) { module_t mod = (module_t) val; if(mod->free != NULL) (mod->free)(mod); #ifndef _WIN32 if (mod->handle != NULL) dlclose(mod->handle); #else if (mod->handle != NULL) FreeLibrary((HMODULE) mod->handle); #endif free((void*)mod->name); free(mod); } void mm_free(mm_t mm) { int i, j, *nlist = NULL; mod_instance_t **list = NULL, mi; /* close down modules */ xhash_walk(mm->modules, _mm_reaper, NULL); /* free instances */ for(i = 0; i < 13; i++) { switch(i) { case 0: list = &mm->sess_start; nlist = &mm->nsess_start; break; case 1: list = &mm->sess_end; nlist = &mm->nsess_end; break; case 2: list = &mm->in_sess; nlist = &mm->nin_sess; break; case 3: list = &mm->in_router; nlist = &mm->nin_router; break; case 4: list = &mm->out_sess; nlist = &mm->nout_sess; break; case 5: list = &mm->out_router; nlist = &mm->nout_router; break; case 6: list = &mm->pkt_sm; nlist = &mm->npkt_sm; break; case 7: list = &mm->pkt_user; nlist = &mm->npkt_user; break; case 8: list = &mm->pkt_router; nlist = &mm->npkt_router; break; case 9: list = &mm->user_load; nlist = &mm->nuser_load; break; case 10: list = &mm->user_create; nlist = &mm->nuser_create; break; case 11: list = &mm->user_delete; nlist = &mm->nuser_delete; break; case 12: list = &mm->disco_extend; nlist = &mm->ndisco_extend; break; } for(j = 0; j < *nlist; j++) { mi = (*list)[j]; if(mi->arg != NULL) free((void*)mi->arg); free(mi); } } /* free lists */ free(mm->sess_start); free(mm->sess_end); free(mm->in_sess); free(mm->in_router); free(mm->out_sess); free(mm->out_router); free(mm->pkt_sm); free(mm->pkt_user); free(mm->pkt_router); free(mm->user_load); free(mm->user_create); free(mm->user_delete); free(mm->disco_extend); xhash_free(mm->modules); free(mm); } /** session starting */ int mm_sess_start(mm_t mm, sess_t sess) { int n, ret = 0; mod_instance_t mi; log_debug(ZONE, "dispatching sess-start chain"); ret = 0; for(n = 0; n < mm->nsess_start; n++) { mi = mm->sess_start[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->sess_start == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->sess_start)(mi, sess); if(ret != 0) break; } log_debug(ZONE, "sess-start chain returning %d", ret); return ret; } /** session ending */ void mm_sess_end(mm_t mm, sess_t sess) { int n; mod_instance_t mi; log_debug(ZONE, "dispatching sess-end chain"); for(n = 0; n < mm->nsess_end; n++) { mi = mm->sess_end[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->sess_end == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); (mi->mod->sess_end)(mi, sess); } log_debug(ZONE, "sess-end chain returning"); } /** packets from active session */ mod_ret_t mm_in_sess(mm_t mm, sess_t sess, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching in-sess chain"); ret = mod_PASS; for(n = 0; n < mm->nin_sess; n++) { mi = mm->in_sess[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->in_sess == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->in_sess)(mi, sess, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "in-sess chain returning %d", ret); return ret; } /** packets from router */ mod_ret_t mm_in_router(mm_t mm, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching in-router chain"); if (mm != NULL && pkt != NULL ) for(n = 0; n < mm->nin_router; n++) { mi = mm->in_router[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod == NULL || mi->mod->in_router == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->in_router)(mi, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "in-router chain returning %d", ret); return ret; } /** packets to active session */ mod_ret_t mm_out_sess(mm_t mm, sess_t sess, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching out-sess chain"); for(n = 0; n < mm->nout_sess; n++) { mi = mm->out_sess[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->out_sess == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->out_sess)(mi, sess, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "out-sess chain returning %d", ret); return ret; } /** packets to router */ mod_ret_t mm_out_router(mm_t mm, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching out-router chain"); for(n = 0; n < mm->nout_router; n++) { mi = mm->out_router[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->out_router == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->out_router)(mi, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "out-router chain returning %d", ret); return ret; } /** packets for sm */ mod_ret_t mm_pkt_sm(mm_t mm, pkt_t pkt) { int n, ret = 0; mod_instance_t mi; log_debug(ZONE, "dispatching pkt-sm chain"); for(n = 0; n < mm->npkt_sm; n++) { mi = mm->pkt_sm[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->pkt_sm == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->pkt_sm)(mi, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "pkt-sm chain returning %d", ret); return ret; } /** packets for user */ mod_ret_t mm_pkt_user(mm_t mm, user_t user, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching pkt-user chain"); for(n = 0; n < mm->npkt_user; n++) { mi = mm->pkt_user[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->pkt_user == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->pkt_user)(mi, user, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "pkt-user chain returning %d", ret); return ret; } /** packets from the router */ mod_ret_t mm_pkt_router(mm_t mm, pkt_t pkt) { int n; mod_instance_t mi; mod_ret_t ret = mod_PASS; log_debug(ZONE, "dispatching pkt-router chain"); for(n = 0; n < mm->npkt_router; n++) { mi = mm->pkt_router[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->pkt_router == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->pkt_router)(mi, pkt); if(ret != mod_PASS) break; } log_debug(ZONE, "pkt-router chain returning %d", ret); return ret; } /** load user data */ int mm_user_load(mm_t mm, user_t user) { int n; mod_instance_t mi; int ret = 0; log_debug(ZONE, "dispatching user-load chain"); for(n = 0; n < mm->nuser_load; n++) { mi = mm->user_load[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->user_load == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->user_load)(mi, user); if(ret != 0) break; } log_debug(ZONE, "user-load chain returning %d", ret); return ret; } /** user data is about to be unloaded */ int mm_user_unload(mm_t mm, user_t user) { int n; mod_instance_t mi; int ret = 0; log_debug(ZONE, "dispatching user-unload chain"); for(n = 0; n < mm->nuser_unload; n++) { mi = mm->user_unload[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->user_unload == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->user_unload)(mi, user); if(ret != 0) break; } log_debug(ZONE, "user-unload chain returning %d", ret); return ret; } /** create user */ int mm_user_create(mm_t mm, jid_t jid) { int n; mod_instance_t mi; int ret = 0; log_debug(ZONE, "dispatching user-create chain"); for(n = 0; n < mm->nuser_create; n++) { mi = mm->user_create[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->user_create == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); ret = (mi->mod->user_create)(mi, jid); if(ret != 0) break; } log_debug(ZONE, "user-create chain returning %d", ret); return ret; } /** delete user */ void mm_user_delete(mm_t mm, jid_t jid) { int n; mod_instance_t mi; log_debug(ZONE, "dispatching user-delete chain"); for(n = 0; n < mm->nuser_delete; n++) { mi = mm->user_delete[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->user_delete == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); (mi->mod->user_delete)(mi, jid); } log_debug(ZONE, "user-delete chain returning"); } /** disco extend */ void mm_disco_extend(mm_t mm, pkt_t pkt) { int n; mod_instance_t mi; log_debug(ZONE, "dispatching disco-extend chain"); for(n = 0; n < mm->ndisco_extend; n++) { mi = mm->disco_extend[n]; if(mi == NULL) { log_debug(ZONE, "module at index %d is not loaded yet", n); continue; } if(mi->mod->disco_extend == NULL) { log_debug(ZONE, "module %s has no handler for this chain", mi->mod->name); continue; } log_debug(ZONE, "calling module %s", mi->mod->name); (mi->mod->disco_extend)(mi, pkt); } log_debug(ZONE, "disco-extend chain returning"); } �������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_active.c��������������������������������������������������������������0000664�0000000�0000000�00000004410�12614627753�0017473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file sm/mod_active.c * @brief active user management * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.8 $ */ #include "sm.h" static int _active_user_load(mod_instance_t mi, user_t user) { os_t os; os_object_t o; /* get their active status */ if(storage_get(user->sm->st, "active", jid_user(user->jid), NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "time", &user->active); os_free(os); } else /* can't load them if they're inactive */ return 1; return 0; } static int _active_user_create(mod_instance_t mi, jid_t jid) { time_t t; os_t os; os_object_t o; log_debug(ZONE, "activating user %s", jid_user(jid)); t = time(NULL); os = os_new(); o = os_object_new(os); os_object_put_time(o, "time", &t); storage_put(mi->sm->st, "active", jid_user(jid), os); os_free(os); return 0; } static void _active_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deactivating user %s", jid_user(jid)); storage_delete(mi->sm->st, "active", jid_user(jid), NULL); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->user_load = _active_user_load; mod->user_create = _active_user_create; mod->user_delete = _active_user_delete; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_amp.c�����������������������������������������������������������������0000664�0000000�0000000�00000036357�12614627753�0017014�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #define _GNU_SOURCE #include <string.h> #include "sm.h" #include "util/util.h" #include <stringprep.h> /** @file sm/mod_amp.c * @brief Advanced Message Processing (JEP-0079) module * @author Cedric Vivier * $Date: 2004/10/28 14:38:35 $ */ typedef struct _mod_amp_config_st { sm_t sm; int disableActionDrop; int disableActionError; int disableActionAlert; int disableActionNotify; int disableConditionDeliver; int disableConditionExpireAt; int disableConditionMatchResource; int offlinestorageDisabled; } *mod_amp_config_t; #define AMP_TRIGGERED 1 #define AMP_INVALID_RULE 2 #define AMP_INVALID_CONDITION 3 #define AMP_INVALID_ACTION 4 #define AMP_INVALID_VALUE 5 #define AMP_NOT_ACCEPTABLE 6 typedef struct amp_rule_st { int result; char *condition; char *value; char *action; struct amp_rule_st *next; } *amp_rule_t; void amp_rule_free(amp_rule_t rule) { amp_rule_t rule_c = rule; amp_rule_t rule_tmp; while (rule_c != NULL) { if (rule_c->condition) free(rule_c->condition); if (rule_c->value) free(rule_c->value); if (rule_c->action) free(rule_c->action); rule_tmp = rule_c->next; free(rule_c); rule_c = rule_tmp; } } pkt_t amp_build_response_pkt(pkt_t pkt, amp_rule_t rule) { if (!pkt || !rule) return NULL; if (rule->result == AMP_TRIGGERED) { int ns; pkt_t res = pkt_create(pkt->sm, "message", NULL, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, res); ns = nad_add_namespace(res->nad, uri_AMP, NULL); nad_append_elem(res->nad, ns, "amp", 2); nad_append_attr(res->nad, -1, "status", rule->action); nad_append_attr(res->nad, -1, "from", jid_full(pkt->from)); nad_append_attr(res->nad, -1, "to", jid_full(pkt->to)); nad_append_elem(res->nad, ns, "rule", 3); nad_append_attr(res->nad, -1, "condition", rule->condition); nad_append_attr(res->nad, -1, "value", rule->value); nad_append_attr(res->nad, -1, "action", rule->action); return res; } return NULL; } void amp_error_pkt(pkt_t pkt, amp_rule_t rule) { /* TODO: implementation */ } static mod_ret_t _amp_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* only handle messages */ if (!(pkt->type & pkt_MESSAGE)) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if (pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; /* TODO: implementation */ return mod_PASS; } static mod_ret_t _amp_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { mod_amp_config_t config = (mod_amp_config_t) mi->mod->private; int ns, elem, attr; amp_rule_t rule, rule_c; int errormode = 0; /* only handle messages */ if (!(pkt->type & pkt_MESSAGE)) return mod_PASS; /* does message have at least one rule for us? */ ns = nad_find_scoped_namespace(pkt->nad, uri_AMP, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "amp", 1); if (elem < 0 || nad_find_attr(pkt->nad, elem, -1, "status", NULL) >= 0 || (elem = nad_find_elem(pkt->nad, elem, ns, "rule", 1)) < 0) return mod_PASS; /* loop for rules */ rule = calloc(1, sizeof(struct amp_rule_st)); rule_c = rule; while (elem >= 0) { /* actions */ if (nad_find_attr(pkt->nad, elem, -1, "action", "drop") >= 0 && !config->disableActionDrop) rule_c->action = strdup("drop"); else if (nad_find_attr(pkt->nad, elem, -1, "action", "alert") >= 0 && !config->disableActionAlert) rule_c->action = strdup("alert"); else if (nad_find_attr(pkt->nad, elem, -1, "action", "error") >= 0 && !config->disableActionError) rule_c->action = strdup("error"); else if (nad_find_attr(pkt->nad, elem, -1, "action", "notify") >= 0 && !config->disableActionNotify) rule_c->action = strdup("notify"); if (!rule_c->action) { if ((attr = nad_find_attr(pkt->nad, elem, -1, "action", NULL)) >= 0) rule_c->action = strndup(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); rule_c->result = AMP_INVALID_ACTION; } /* deliver condition */ if (nad_find_attr(pkt->nad, elem, -1, "condition", "deliver") >= 0 && !config->disableConditionDeliver) { rule_c->condition = strdup("deliver"); /* direct */ if (nad_find_attr(pkt->nad, elem, -1, "value", "direct") >= 0) { rule_c->value = strdup("direct"); if (user->top != NULL) /* active session so it will be direct */ rule_c->result = AMP_TRIGGERED; } /* stored */ else if (nad_find_attr(pkt->nad, elem, -1, "value", "stored") >= 0) { rule_c->value = strdup("none"); if (!config->offlinestorageDisabled && user->top == NULL) /* no active session so it will be stored */ rule_c->result = AMP_TRIGGERED; } /* none */ else if (nad_find_attr(pkt->nad, elem, -1, "value", "none") >= 0) { rule_c->value = strdup("none"); if (config->offlinestorageDisabled && user->top == NULL) /* no active session and no offline storage */ rule_c->result = AMP_TRIGGERED; } if (!rule_c->value) { if ((attr = nad_find_attr(pkt->nad, elem, -1, "value", NULL)) >= 0) rule_c->value = strndup(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); rule_c->result = AMP_INVALID_VALUE; } } /* match-resource condition */ else if (nad_find_attr(pkt->nad, elem, -1, "condition", "match-resource") >= 0 && !config->disableConditionMatchResource) { rule_c->condition = strdup("match-resource"); /* exact */ if (nad_find_attr(pkt->nad, elem, -1, "value", "exact") >= 0) { rule_c->value = strdup("exact"); if (sess_match(user, pkt->to->resource)) /* resource found */ rule_c->result = AMP_TRIGGERED; } /* any */ else if (nad_find_attr(pkt->nad, elem, -1, "value", "any") >= 0) { rule_c->value = strdup("any"); if (user->top == NULL) /* no active resource */ rule_c->result = AMP_TRIGGERED; } /* other */ else if (nad_find_attr(pkt->nad, elem, -1, "value", "other") >= 0) { rule_c->value = strdup("other"); if (!sess_match(user, pkt->to->resource)) /* resource not found */ rule_c->result = AMP_TRIGGERED; } if (!rule_c->value) { if ((attr = nad_find_attr(pkt->nad, elem, -1, "value", NULL)) >= 0) rule_c->value = strndup(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); rule_c->result = AMP_INVALID_VALUE; } } /* expire-at condition */ else if (nad_find_attr(pkt->nad, elem, -1, "condition", "expire-at") >= 0 && !config->disableConditionExpireAt) { rule_c->condition = strdup("expire-at"); if ((attr = nad_find_attr(pkt->nad, elem, -1, "value", NULL)) < 0) rule_c->result = AMP_INVALID_VALUE; else { time_t stamp; rule_c->value = strndup(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); stamp = datetime_in(rule_c->value); if (stamp < 0) rule_c->result = AMP_INVALID_VALUE; else if (stamp < time(NULL)) /* expired! */ rule_c->result = AMP_TRIGGERED; } } if (!rule_c->condition) { if ((attr = nad_find_attr(pkt->nad, elem, -1, "condition", NULL)) >= 0) rule_c->condition = strndup(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); rule_c->result = AMP_INVALID_CONDITION; } /* if an error is triggered, pass in error mode */ if (rule_c->result > AMP_TRIGGERED) errormode = 1; /* processing stops at first rule triggerred */ if (rule_c->result == AMP_TRIGGERED && !errormode) break; /* jump to next rule (if any) */ if ((elem = nad_find_elem(pkt->nad, elem, ns, "rule", 0)) >= 0) { rule_c->next = calloc(1, sizeof(struct amp_rule_st)); rule_c = rule_c->next; } } /* build result packet (if any) */ if (rule_c->result != AMP_TRIGGERED || errormode) rule_c = rule; while (rule_c != NULL) { if (rule_c->result > 0) { /* drop action */ if (!strcmp(rule_c->action, "drop") && !errormode) goto handled; /* alert action */ else if (!strcmp(rule_c->action, "alert") && !errormode) { pkt_t res = amp_build_response_pkt(pkt, rule_c); pkt_router(res); goto handled; } /* error action */ else if (!strcmp(rule_c->action, "error") && !errormode) { pkt_t res = amp_build_response_pkt(pkt, rule_c); pkt_router(res); goto handled; } /* notify action */ else if (!strcmp(rule_c->action, "notify") && !errormode) { pkt_t res = amp_build_response_pkt(pkt, rule_c); pkt_router(res); goto pass; /* ...resume the pkt-user chain happily :) */ } } rule_c = rule_c->next; } pass: amp_rule_free(rule); return mod_PASS; handled: amp_rule_free(rule); pkt_free(pkt); return mod_HANDLED; } static mod_ret_t _amp_pkt_sm(mod_instance_t mi, pkt_t pkt) { mod_amp_config_t config = (mod_amp_config_t) mi->mod->private; pkt_t res; int ns, attr; /* we only want to play with iq disco#info gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_DISCO_INFO) return mod_PASS; /* is disco#info for us ? */ if ((attr = nad_find_attr(pkt->nad, 2, -1, "node", NULL)) < 0 || strncmp(NAD_AVAL(pkt->nad, attr), uri_AMP, NAD_AVAL_L(pkt->nad, attr)) != 0) return mod_PASS; res = pkt_create(config->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, res); pkt_free(pkt); ns = nad_add_namespace(res->nad, uri_DISCO_INFO, NULL); nad_append_elem(res->nad, ns, "query", 2); nad_append_attr(res->nad, -1, "node", uri_AMP); nad_append_elem(res->nad, ns, "identity", 3); nad_append_attr(res->nad, -1, "name", "Advanced Message Processing support"); nad_append_attr(res->nad, -1, "category", "im"); nad_append_attr(res->nad, -1, "type", "server"); nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP); if (!config->disableActionDrop) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_ACTION_DROP); } if (!config->disableActionError) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_ACTION_ERROR); } if (!config->disableActionNotify) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_ACTION_NOTIFY); } if (!config->disableConditionDeliver) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_CONDITION_DELIVER); } if (!config->disableConditionExpireAt) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_CONDITION_EXPIREAT); } if (!config->disableConditionMatchResource) { nad_append_elem(res->nad, ns, "feature", 3); nad_append_attr(res->nad, -1, "var", uri_AMP_CONDITION_MATCHRESOURCE); } /* tell them */ pkt_router(res); return mod_HANDLED; } static void _amp_free(module_t mod) { free(mod->private); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; mod_amp_config_t config; const char* option; if (mod->init) return 0; config = (mod_amp_config_t) calloc(1, sizeof(struct _mod_amp_config_st)); config->sm = mod->mm->sm; option = config_get_one(mod->mm->sm->config, "amp.disableactions.drop", 0); if (option != NULL) { log_debug(ZONE, "action Drop disabled in config."); config->disableActionDrop = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableactions.error", 0); if (option != NULL) { log_debug(ZONE, "action Error disabled in config."); config->disableActionError = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableactions.alert", 0); if (option != NULL) { log_debug(ZONE, "action Alert disabled in config."); config->disableActionAlert = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableactions.notify", 0); if (option != NULL) { log_debug(ZONE, "action Notify disabled in config."); config->disableActionNotify = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableconditions.deliver", 0); if (option != NULL) { log_debug(ZONE, "condition Deliver disabled in config."); config->disableConditionDeliver = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableconditions.expireat", 0); if (option != NULL) { log_debug(ZONE, "condition Expire-At disabled in config."); config->disableConditionExpireAt = 1; } option = config_get_one(mod->mm->sm->config, "amp.disableconditions.matchresource", 0); if (option != NULL) { log_debug(ZONE, "condition Match-Resource disabled in config."); config->disableConditionMatchResource = 1; } option = config_get_one(mod->mm->sm->config, "amp.offlinestoragedisabled", 0); if (option != NULL) { log_debug(ZONE, "offline storage disabled in config."); config->offlinestorageDisabled = 1; } option = config_get_one(mod->mm->sm->config, "offline.dropmessages", 0); if (option != NULL) { log_debug(ZONE, "offline storage disabled in config."); config->offlinestorageDisabled = 1; } mod->private = config; mod->in_sess = _amp_in_sess; mod->pkt_user = _amp_pkt_user; mod->pkt_sm = _amp_pkt_sm; mod->free = _amp_free; feature_register(mod->mm->sm, uri_AMP); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_announce.c������������������������������������������������������������0000664�0000000�0000000�00000025542�12614627753�0020037�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" #include <time.h> /** @file sm/mod_announce.c * @brief announce (broadcast) messages * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.23 $ */ /* * message to host/announce goes to all online sessions and to offline users next time they connect * message to host/announce/online goes to all online sessions */ typedef struct moddata_st { nad_t nad; int loaded; time_t t; os_t tos; int index; char *announce_resource; char *online_resource; } *moddata_t; static void _announce_load(module_t mod, moddata_t data, const char *domain) { st_ret_t ret; os_t os; os_object_t o; nad_t nad; int ns, elem, attr; char timestamp[18], telem[5]; struct tm tm; /* struct tm can vary in size depending on platform */ memset(&tm, 0, sizeof(struct tm)); data->loaded = 1; /* load the current message */ if((ret = storage_get(mod->mm->sm->st, "motd-message", domain, NULL, &os)) == st_SUCCESS) { os_iter_first(os); o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { /* Copy the nad, as the original is freed when the os is freed below */ data->nad = nad_copy(nad); if((ns = nad_find_scoped_namespace(data->nad, uri_DELAY, NULL)) >= 0 && (elem = nad_find_elem(data->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(data->nad, elem, -1, "stamp", NULL)) >= 0) { snprintf(timestamp, 18, "%.*s", NAD_AVAL_L(data->nad, attr), NAD_AVAL(data->nad, attr)); /* year */ telem[0] = timestamp[0]; telem[1] = timestamp[1]; telem[2] = timestamp[2]; telem[3] = timestamp[3]; telem[4] = '\0'; tm.tm_year = atoi(telem) - 1900; /* month */ telem[0] = timestamp[4]; telem[1] = timestamp[5]; telem[2] = '\0'; tm.tm_mon = atoi(telem) - 1; /* day */ telem[0] = timestamp[6]; telem[1] = timestamp[7]; tm.tm_mday = atoi(telem); /* hour */ telem[0] = timestamp[9]; telem[1] = timestamp[10]; tm.tm_hour = atoi(telem); /* minute */ telem[0] = timestamp[12]; telem[1] = timestamp[13]; tm.tm_min = atoi(telem); /* second */ telem[0] = timestamp[15]; telem[1] = timestamp[16]; tm.tm_sec = atoi(telem); data->t = timegm(&tm); } } os_free(os); } if(data->tos != NULL) os_free(data->tos); data->tos = os_new(); os_object_put(os_object_new(data->tos), "time", &data->t, os_type_INTEGER); } static mod_ret_t _announce_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; moddata_t data = (moddata_t) mod->private; time_t t; nad_t nad; pkt_t motd; os_t os; os_object_t o; /* try to load data if we haven't yet */ if(data->nad == NULL) { if(data->loaded) return mod_PASS; /* nothing to give them */ _announce_load(mod, data, sess->user->jid->domain); if(data->nad == NULL) return mod_PASS; } /* if they're becoming available for the first time */ if(pkt->type == pkt_PRESENCE && pkt->to == NULL && sess->user->top == NULL) { /* load the time of the last motd they got */ if((time_t) sess->user->module_data[mod->index] == 0 && storage_get(sess->user->sm->st, "motd-times", jid_user(sess->jid), NULL, &os) == st_SUCCESS) { os_iter_first(os); o = os_iter_object(os); os_object_get_time(os, o, "time", &t); sess->user->module_data[mod->index] = (void *) t; os_free(os); } /* they've seen this one */ if((time_t) sess->user->module_data[mod->index] >= data->t) return mod_PASS; /* a-delivering we go */ log_debug(ZONE, "delivering stored motd to %s", jid_full(sess->jid)); nad = nad_copy(data->nad); nad_set_attr(nad, 1, -1, "to", jid_full(sess->jid), strlen(jid_full(sess->jid))); nad_set_attr(nad, 1, -1, "from", sess->user->jid->domain, strlen(sess->user->jid->domain)); motd = pkt_new(mod->mm->sm, nad); if(motd == NULL) { log_debug(ZONE, "invalid stored motd, not delivering"); nad_free(nad); } else pkt_router(motd); sess->user->module_data[mod->index] = (void *) data->t; storage_replace(sess->user->sm->st, "motd-times", jid_user(sess->jid), NULL, data->tos); } return mod_PASS; } static void _announce_broadcast_user(const char *key, int keylen, void *val, void *arg) { user_t user = (user_t) val; moddata_t data = (moddata_t) arg; sess_t sess; nad_t nad; for(sess = user->sessions; sess != NULL; sess = sess->next) { if(!sess->available || sess->pri < 0) continue; log_debug(ZONE, "resending to '%s'", jid_full(sess->jid)); nad = nad_copy(data->nad); nad_set_attr(nad, 1, -1, "to", jid_full(sess->jid), strlen(jid_full(sess->jid))); nad_set_attr(nad, 1, -1, "from", sess->jid->domain, strlen(sess->jid->domain)); pkt_router(pkt_new(user->sm, nad)); sess->user->module_data[data->index] = (void *) data->t; storage_replace(sess->user->sm->st, "motd-times", jid_user(sess->jid), NULL, data->tos); } } static mod_ret_t _announce_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; moddata_t data = (moddata_t) mod->private; pkt_t store; nad_t nad; jid_t jid; time_t t; os_t os; os_object_t o; st_ret_t ret; int elem; /* time of this packet */ t = time(NULL); /* answer to probes and subscription requests if admin */ if((pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N) && aci_check(mod->mm->sm->acls, "broadcast", pkt->from)) { log_debug(ZONE, "answering presence probe/sub from %s with /announce resources", jid_full(pkt->from)); /* send presences */ jid = jid_new(pkt->from->domain, -1); jid_reset_components(jid, jid->node, jid->domain, data->announce_resource); pkt_router(pkt_create(mod->mm->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid))); jid_free(jid); jid = jid_new(pkt->from->domain, -1); jid_reset_components(jid, jid->node, jid->domain, data->online_resource); pkt_router(pkt_create(mod->mm->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid))); jid_free(jid); } /* we want messages addressed to /announce */ if(!(pkt->type & pkt_MESSAGE) || strlen(pkt->to->resource) < 8 || strncmp(pkt->to->resource, data->announce_resource, 8) != 0) return mod_PASS; /* make sure they're allowed */ if(!aci_check(mod->mm->sm->acls, "broadcast", pkt->from)) { log_debug(ZONE, "not allowing broadcast from %s", jid_full(pkt->from)); return -stanza_err_FORBIDDEN; } /* "fix" packet a bit */ /* force type normal */ nad_set_attr(pkt->nad, 1, -1, "type", NULL, 0); /* remove sender nick */ elem = nad_find_elem(pkt->nad, 1, -1, "nick", 1); if(elem >= 0) nad_drop_elem(pkt->nad, elem); if(pkt->to->resource[8] == '\0') { log_debug(ZONE, "storing message for announce later"); store = pkt_dup(pkt, NULL, NULL); pkt_delay(store, t, pkt->to->domain); /* prepare for storage */ os = os_new(); o = os_object_new(os); os_object_put(o, "xml", store->nad, os_type_NAD); /* store it */ ret = storage_replace(mod->mm->sm->st, "motd-message", pkt->to->domain, NULL, os); os_free(os); switch(ret) { case st_FAILED: pkt_free(store); return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: pkt_free(store); return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: break; } /* replace our local copy */ if(data->nad != NULL) nad_free(data->nad); data->nad = store->nad; store->nad = NULL; pkt_free(store); /* update timestamp */ data->t = t; if(data->tos != NULL) os_free(data->tos); data->tos = os_new(); os_object_put(os_object_new(data->tos), "time", &t, os_type_INTEGER); } else if(strcmp(&(pkt->to->resource[8]), "/online") != 0) { log_debug(ZONE, "unknown announce resource '%s'", pkt->to->resource); pkt_free(pkt); return mod_HANDLED; } log_debug(ZONE, "broadcasting message to all sessions"); /* hack */ nad = data->nad; data->nad = pkt->nad; xhash_walk(mod->mm->sm->users, _announce_broadcast_user, (void *) data); data->nad = nad; /* done */ pkt_free(pkt); return mod_HANDLED; } static void _announce_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting motd time for %s", jid_user(jid)); storage_delete(mi->sm->st, "motd-times", jid_user(jid), NULL); } static void _announce_free(module_t mod) { moddata_t data = (moddata_t) mod->private; if(data->nad != NULL) nad_free(data->nad); if(data->tos != NULL) os_free(data->tos); free(data); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; moddata_t data; if(mod->init) return 0; data = (moddata_t) calloc(1, sizeof(struct moddata_st)); mod->private = (void *) data; data->index = mod->index; data->announce_resource = "announce"; data->online_resource = "announce/online"; mod->in_sess = _announce_in_sess; mod->pkt_sm = _announce_pkt_sm; mod->user_delete = _announce_user_delete; mod->free = _announce_free; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_deliver.c�������������������������������������������������������������0000664�0000000�0000000�00000006216�12614627753�0017660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_deliver.c * @brief packet delivery * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.18 $ */ static mod_ret_t _deliver_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* ensure from is set correctly if not already by client */ if(pkt->from == NULL || jid_compare_user(pkt->from, sess->jid) != 0) { if(pkt->from != NULL) jid_free(pkt->from); pkt->from = jid_dup(sess->jid); nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); } /* no to address means its to us */ if(pkt->to == NULL) { /* drop iq-result packets */ /* user client is confirming all iq-set, but we usually do not track these * confirmations and we need to drop it here, not loop back to client */ if(pkt->type == pkt_IQ_RESULT) { pkt_free(pkt); return mod_HANDLED; } /* iq packets without to should have been already handled by modules */ if(pkt->type & pkt_IQ) { return -stanza_err_FEATURE_NOT_IMPLEMENTED; } /* supplant user jid as 'to' */ pkt->to = jid_dup(sess->jid); nad_set_attr(pkt->nad, 1, -1, "to", jid_full(pkt->to), 0); } /* let it go on the wire */ pkt_router(pkt); return mod_HANDLED; } static mod_ret_t _deliver_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { sess_t sess; /* if there's a resource, send it direct */ if(*pkt->to->resource != '\0') { /* find the session */ sess = sess_match(user, pkt->to->resource); /* and send it straight there */ if(sess != NULL) { pkt_sess(pkt, sess); return mod_HANDLED; } /* no session */ if(pkt->type & pkt_PRESENCE) { pkt_free(pkt); return mod_HANDLED; } else if(pkt->type & pkt_IQ) return -stanza_err_SERVICE_UNAVAILABLE; /* unmatched messages will fall through (XMPP-IM r20 s11 rule 2) */ } return mod_PASS; } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _deliver_in_sess; mod->pkt_user = _deliver_pkt_user; feature_register(mod->mm->sm, "message"); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_disco.c���������������������������������������������������������������0000664�0000000�0000000�00000055167�12614627753�0017340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_disco.c * @brief service discovery * @author Robert Norris * $Date: 2005/09/09 05:34:13 $ * $Revision: 1.35 $ */ #define ACTIVE_SESSIONS_NAME "Active sessions" /** holder for a single service */ typedef struct service_st *service_t; struct service_st { jid_t jid; char name[257]; char category[257]; char type[257]; xht features; }; /** all the current disco data */ typedef struct disco_st *disco_t; struct disco_st { /** identity */ const char *category; const char *type; const char *name; /** compatibility */ int agents; /** the lists */ xht dyn; xht stat; /** unified list */ xht un; /** cached result packets */ pkt_t disco_info_result; pkt_t disco_items_result; pkt_t agents_result; }; /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; service_t *svc_val; sess_t *sess_val; const char **char_val; }; /** put val into arg */ static void _disco_unify_walker(const char *key, int keylen, void *val, void *arg) { service_t svc = (service_t) val; xht dest = (xht) arg; /* if its already there, skip this one */ if(xhash_get(dest, jid_full(svc->jid)) != NULL) return; log_debug(ZONE, "unify: %s", jid_full(svc->jid)); xhash_put(dest, jid_full(svc->jid), (void *) svc); } /** unify the contents of dyn and stat */ static void _disco_unify_lists(disco_t d) { log_debug(ZONE, "unifying lists"); if(d->un != NULL) xhash_free(d->un); d->un = xhash_new(101); /* dynamic overrieds static */ xhash_walk(d->dyn, _disco_unify_walker, (void *) d->un); xhash_walk(d->stat, _disco_unify_walker, (void *) d->un); } /** build a disco items result, known services */ static pkt_t _disco_items_result(module_t mod, disco_t d) { pkt_t pkt; int ns; service_t svc; union xhashv xhv; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); if(xhash_iter_first(d->un)) do { xhv.svc_val = &svc; xhash_iter_get(d->un, NULL, NULL, xhv.val); nad_append_elem(pkt->nad, ns, "item", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); if(svc->name[0] != '\0') nad_append_attr(pkt->nad, -1, "name", svc->name); } while(xhash_iter_next(d->un)); return pkt; } /** build a disco info result */ static pkt_t _disco_info_result(module_t mod, disco_t d) { pkt_t pkt; int el, ns; const char *key; int keylen; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_DISCO_INFO, NULL); nad_append_elem(pkt->nad, ns, "query", 2); /* identity */ nad_append_elem(pkt->nad, ns, "identity", 3); nad_append_attr(pkt->nad, -1, "category", d->category); nad_append_attr(pkt->nad, -1, "type", d->type); nad_append_attr(pkt->nad, -1, "name", d->name); /* fill in our features */ if(xhash_iter_first(mod->mm->sm->features)) do { xhash_iter_get(mod->mm->sm->features, &key, &keylen, NULL); el = nad_append_elem(pkt->nad, ns, "feature", 3); nad_set_attr(pkt->nad, el, -1, "var", (char *) key, keylen); } while(xhash_iter_next(mod->mm->sm->features)); /* put it throuhg disco_extend chain to add * XEP-0128 Service Discovery Extensions */ mm_disco_extend(mod->mm, pkt); return pkt; } /** build an agents result */ static pkt_t _disco_agents_result(module_t mod, disco_t d) { pkt_t pkt; int ns; const char *key; int keylen; service_t svc; union xhashv xhv; pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); ns = nad_add_namespace(pkt->nad, uri_AGENTS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); /* fill in the items */ if(xhash_iter_first(d->un)) do { xhv.svc_val = &svc; xhash_iter_get(d->un, &key, &keylen, xhv.val); nad_append_elem(pkt->nad, ns, "agent", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); if(svc->name[0] != '\0') { nad_append_elem(pkt->nad, ns, "name", 4); nad_append_cdata(pkt->nad, svc->name, strlen(svc->name), 5); } nad_append_elem(pkt->nad, ns, "service", 4); nad_append_cdata(pkt->nad, svc->type, strlen(svc->type), 5); /* map features to the old agent flags */ if(xhash_get(svc->features, uri_REGISTER) != NULL) nad_append_elem(pkt->nad, ns, "register", 4); if(xhash_get(svc->features, uri_SEARCH) != NULL) nad_append_elem(pkt->nad, ns, "search", 4); if(xhash_get(svc->features, uri_GATEWAY) != NULL) nad_append_elem(pkt->nad, ns, "transport", 4); /* conference gets special treatment */ if(strcmp(svc->category, "conference") == 0) nad_append_elem(pkt->nad, ns, "groupchat", 4); } while(xhash_iter_next(d->un)); return pkt; } /** generate cached result packets */ static void _disco_generate_packets(module_t mod, disco_t d) { log_debug(ZONE, "regenerating packets"); if(d->disco_items_result != NULL) pkt_free(d->disco_items_result); d->disco_items_result = _disco_items_result(mod, d); if(d->disco_info_result != NULL) pkt_free(d->disco_info_result); d->disco_info_result = _disco_info_result(mod, d); if(d->agents) { if(d->agents_result != NULL) pkt_free(d->agents_result); d->agents_result = _disco_agents_result(mod, d); } } /** catch responses and populate the table */ static mod_ret_t _disco_pkt_sm_populate(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; int ns, qelem, elem, attr; service_t svc; /* it has to come from the service itself - don't want any old user messing with the table */ if(pkt->from->node[0] != '\0' || pkt->from->resource[0] != '\0') { log_debug(ZONE, "disco response from %s, not allowed", jid_full(pkt->from)); return -stanza_err_NOT_ALLOWED; } ns = nad_find_scoped_namespace(pkt->nad, uri_DISCO_INFO, NULL); qelem = nad_find_elem(pkt->nad, 1, ns, "query", 1); elem = nad_find_elem(pkt->nad, qelem, ns, "identity", 1); if(elem < 0) return -stanza_err_BAD_REQUEST; /* we don't want to list other im servers on the router */ if(nad_find_attr(pkt->nad, elem, -1, "category", "server") >= 0 && nad_find_attr(pkt->nad, elem, -1, "type", "im") >= 0) { pkt_free(pkt); return mod_HANDLED; } /* see if we already have this service */ svc = xhash_get(d->dyn, jid_full(pkt->from)); if(svc == NULL) { /* make a new one */ svc = (service_t) calloc(1, sizeof(struct service_st)); svc->jid = jid_dup(pkt->from); svc->features = xhash_new(11); /* link it in */ xhash_put(d->dyn, jid_full(svc->jid), (void *) svc); /* unify */ _disco_unify_lists(d); } /* fill in the name */ attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL); if(attr < 0) svc->name[0] = '\0'; else snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); /* category and type */ attr = nad_find_attr(pkt->nad, elem, -1, "category", NULL); if(attr >= 0) snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); else strcpy(svc->category, "unknown"); attr = nad_find_attr(pkt->nad, elem, -1, "type", NULL); if(attr >= 0) snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); else strcpy(svc->type, "unknown"); /* features */ elem = nad_find_elem(pkt->nad, qelem, -1, "feature", 1); while(elem >= 0) { attr = nad_find_attr(pkt->nad, elem, -1, "var", NULL); if(attr < 0) { elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); continue; } xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)), (void *) 1); elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); } /* regenerate packets */ _disco_generate_packets(mod, d); pkt_free(pkt); return mod_HANDLED; } /** build a disco items result, active sessions */ static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt) { int ns; sess_t sess; union xhashv xhv; ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); nad_append_attr(pkt->nad, -1, "node", "sessions"); if(xhash_iter_first(mod->mm->sm->sessions)) do { xhv.sess_val = &sess; xhash_iter_get(mod->mm->sm->sessions, NULL, NULL, xhv.val); nad_append_elem(pkt->nad, ns, "item", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(sess->jid)); nad_append_attr(pkt->nad, -1, "name", "Active session"); } while(xhash_iter_next(mod->mm->sm->sessions)); } /** catch responses and populate the table; respond to requests */ static mod_ret_t _disco_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; pkt_t result; int node, ns; /* disco info results go to a seperate function */ if(pkt->type == pkt_IQ_RESULT && pkt->ns == ns_DISCO_INFO) return _disco_pkt_sm_populate(mi, pkt); /* check whether the requested domain is serviced here */ if(xhash_get(mod->mm->sm->hosts, pkt->to->domain) == NULL) return -stanza_err_ITEM_NOT_FOUND; /* we want disco or agents gets */ if(pkt->type != pkt_IQ || !(pkt->ns == ns_DISCO_INFO || pkt->ns == ns_DISCO_ITEMS || pkt->ns == ns_AGENTS)) return mod_PASS; /* generate the caches if we haven't yet */ if(d->disco_info_result == NULL) _disco_generate_packets(mod, d); node = nad_find_attr(pkt->nad, 2, -1, "node", NULL); /* they want to know about us */ if(pkt->ns == ns_DISCO_INFO) { /* respond with cached disco info packet if no node given */ if(node < 0) { result = pkt_dup(d->disco_info_result, jid_full(pkt->from), jid_full(pkt->to)); node = nad_find_attr(pkt->nad, 2, -1, "node", NULL); if(node >= 0) { nad_set_attr(result->nad, 2, -1, "node", NAD_AVAL(pkt->nad, node), NAD_AVAL_L(pkt->nad, node)); } pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_router(result); return mod_HANDLED; } else if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) { /* priviliged op, make sure they're allowed */ if(!aci_check(mod->mm->sm->acls, "disco", pkt->from)) return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */ result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); ns = nad_add_namespace(result->nad, uri_DISCO_INFO, NULL); nad_append_elem(result->nad, ns, "query", 2); nad_append_elem(result->nad, ns, "identity", 3); nad_append_attr(result->nad, -1, "category", "hierarchy"); nad_append_attr(result->nad, -1, "type", "branch"); nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME); nad_append_elem(result->nad, -1, "feature", 3); nad_append_attr(result->nad, -1, "var", uri_DISCO_INFO); nad_append_elem(result->nad, -1, "feature", 3); nad_append_attr(result->nad, -1, "var", uri_DISCO_ITEMS); /* off it goes */ pkt_router(result); return mod_HANDLED; } else return -stanza_err_ITEM_NOT_FOUND; } /* handle agents */ if(pkt->ns == ns_AGENTS) { /* make sure we're supporting compat */ if(!d->agents) return -stanza_err_NOT_ALLOWED; result = pkt_dup(d->agents_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* they want to know who we know about */ if(node < 0) { /* no node, so toplevel services */ result = pkt_dup(d->disco_items_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* if they have privs, then show them any administrative things they can disco to */ if(aci_check(mod->mm->sm->acls, "disco", result->to)) { nad_append_elem(result->nad, NAD_ENS(result->nad, 2), "item", 3); nad_append_attr(result->nad, -1, "jid", jid_full(result->from)); nad_append_attr(result->nad, -1, "node", "sessions"); nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME); } pkt_router(result); return mod_HANDLED; } /* active sessions */ if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) { /* priviliged op, make sure they're allowed */ if(!aci_check(mod->mm->sm->acls, "disco", pkt->from)) return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */ result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); _disco_sessions_result(mod, d, result); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* I dunno what they're asking for */ return -stanza_err_ITEM_NOT_FOUND; } /** response to quering user JID */ static void _disco_user_result(pkt_t pkt, user_t user) { /* identity */ nad_append_elem(pkt->nad, -1, "identity", 3); nad_append_attr(pkt->nad, -1, "category", "account"); /* if user is logged in (has session) yet never logged in (no active time) it is certainly an anonymous user */ log_debug(ZONE, "%s: top %p active %d", jid_full(user->jid), user->sessions, user->active); nad_append_attr(pkt->nad, -1, "type", (user->sessions && !user->active) ? "anonymous" : "registered"); /* tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); } /** legacy support for agents requests from sessions */ static mod_ret_t _disco_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; pkt_t result; /* disco info requests */ if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO) { /* it has to have no to address or self bare jid */ if(pkt->to != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->to))) { return mod_PASS; } _disco_user_result(pkt, sess->user); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; } /* we want agents gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_AGENTS || pkt->to != NULL) return mod_PASS; /* fail if its not enabled */ if(!d->agents) return -stanza_err_NOT_ALLOWED; /* generate the caches if we haven't yet */ if(d->disco_info_result == NULL) _disco_generate_packets(mod, d); /* pre-canned response */ result = pkt_dup(d->agents_result, NULL, NULL); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_sess(result, sess); return mod_HANDLED; } static mod_ret_t _disco_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { /* disco info requests */ if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO) { _disco_user_result(pkt, user); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } /* pass everything else */ return mod_PASS; } /** update the table for component changes */ static mod_ret_t _disco_pkt_router(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; service_t svc; pkt_t request; int ns; /* we want advertisements with a from address */ if(pkt->from == NULL || !(pkt->rtype & route_ADV)) return mod_PASS; /* component online */ if(pkt->rtype == route_ADV) { log_debug(ZONE, "presence from component %s, issuing discovery request", jid_full(pkt->from)); /* new disco get packet */ request = pkt_create(mod->mm->sm, "iq", "get", jid_full(pkt->from), mod->mm->sm->id); pkt_id_new(request); ns = nad_add_namespace(request->nad, uri_DISCO_INFO, NULL); nad_append_elem(request->nad, ns, "query", 2); pkt_router(request); /* done with this */ pkt_free(pkt); return mod_HANDLED; } /* it went away. find it and remove it */ svc = xhash_get(d->dyn, jid_full(pkt->from)); if(svc != NULL) { log_debug(ZONE, "dropping entry for %s", jid_full(pkt->from)); xhash_zap(d->dyn, jid_full(pkt->from)); jid_free(svc->jid); xhash_free(svc->features); free(svc); /* unify */ _disco_unify_lists(d); _disco_generate_packets(mod, d); } /* done */ pkt_free(pkt); return mod_HANDLED; } static void _disco_free_walker(const char *key, int keylen, void *val, void *arg) { service_t svc = (service_t) val; jid_free(svc->jid); xhash_free(svc->features); free(svc); } static void _disco_free(module_t mod) { disco_t d = (disco_t) mod->private; xhash_walk(d->stat, _disco_free_walker, NULL); xhash_walk(d->dyn, _disco_free_walker, NULL); xhash_free(d->stat); xhash_free(d->dyn); xhash_free(d->un); if(d->disco_info_result != NULL) pkt_free(d->disco_info_result); if(d->disco_items_result != NULL) pkt_free(d->disco_items_result); if(d->agents_result != NULL) pkt_free(d->agents_result); free(d); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; disco_t d; nad_t nad; int items, item, jid, name, category, type, ns; service_t svc; if(mod->init) return 0; log_debug(ZONE, "disco module init"); d = (disco_t) calloc(1, sizeof(struct disco_st)); /* new hashes to store the lists in */ d->dyn = xhash_new(51); d->stat = xhash_new(51); /* identity */ d->category = config_get_one(mod->mm->sm->config, "discovery.identity.category", 0); if(d->category == NULL) d->category = "server"; d->type = config_get_one(mod->mm->sm->config, "discovery.identity.type", 0); if(d->type == NULL) d->type = "im"; d->name = config_get_one(mod->mm->sm->config, "discovery.identity.name", 0); if(d->name == NULL) d->name = "Jabber IM server"; /* agents compatibility */ d->agents = config_get(mod->mm->sm->config, "discovery.agents") != NULL; if(d->agents) log_debug(ZONE, "agents compat enabled"); /* our data */ mod->private = (void *) d; /* our handlers */ mod->pkt_sm = _disco_pkt_sm; mod->in_sess = _disco_in_sess; mod->pkt_user = _disco_pkt_user; mod->pkt_router = _disco_pkt_router; mod->free = _disco_free; nad = mod->mm->sm->config->nad; /* we support a number of things */ feature_register(mod->mm->sm, uri_DISCO_INFO); feature_register(mod->mm->sm, uri_DISCO_ITEMS); if(d->agents) feature_register(mod->mm->sm, uri_AGENTS); /* populate the static list from the config file */ if((items = nad_find_elem(nad, 0, -1, "discovery", 1)) < 0 || (items = nad_find_elem(nad, items, -1, "items", 1)) < 0) return 0; item = nad_find_elem(nad, items, -1, "item", 1); while(item >= 0) { /* jid is required */ jid = nad_find_attr(nad, item, -1, "jid", NULL); if(jid < 0) { item = nad_find_elem(nad, item, -1, "item", 0); continue; } /* new service */ svc = (service_t) calloc(1, sizeof(struct service_st)); svc->features = xhash_new(13); svc->jid = jid_new(NAD_AVAL(nad, jid), NAD_AVAL_L(nad, jid)); /* link it in */ xhash_put(d->stat, jid_full(svc->jid), (void *) svc); /* copy the name */ name = nad_find_attr(nad, item, -1, "name", NULL); if(name >= 0) snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(nad, name), NAD_AVAL(nad, name)); /* category and type */ category = nad_find_attr(nad, item, -1, "category", NULL); if(category >= 0) snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(nad, category), NAD_AVAL(nad, category)); else strcpy(svc->category, "unknown"); type = nad_find_attr(nad, item, -1, "type", NULL); if(type >= 0) snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(nad, type), NAD_AVAL(nad, type)); else strcpy(svc->type, "unknown"); /* namespaces */ ns = nad_find_elem(nad, item, -1, "ns", 1); while(ns >= 0) { if(NAD_CDATA_L(nad, ns) > 0) xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_CDATA(nad, ns), NAD_CDATA_L(nad, ns)), (void *) 1); ns = nad_find_elem(nad, ns, -1, "ns", 0); } item = nad_find_elem(nad, item, -1, "item", 0); log_debug(ZONE, "added %s to static list", jid_full(svc->jid)); } /* generate the initial union list */ _disco_unify_lists(d); /* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */ return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_echo.c����������������������������������������������������������������0000664�0000000�0000000�00000004372�12614627753�0017145�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_echo.c * @brief message echo * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.9 $ */ static mod_ret_t _echo_pkt_sm(mod_instance_t mi, pkt_t pkt) { jid_t jid; char *resource = (char *) mi->mod->private; /* answer to probes and subscription requests */ if(pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N) { log_debug(ZONE, "answering presence probe/sub from %s with /echo resource", jid_full(pkt->from)); /* send presence */ jid = jid_new(jid_user(pkt->to), -1); jid_reset_components(jid, jid->node, jid->domain, resource); pkt_router(pkt_create(mi->mod->mm->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid))); jid_free(jid); } /* we want messages addressed to /echo */ if(!(pkt->type & pkt_MESSAGE) || strcmp(pkt->to->resource, "echo") != 0) return mod_PASS; log_debug(ZONE, "echo request from %s", jid_full(pkt->from)); /* swap to and from and return it */ pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; /* store /echo resource for use when answering probes */ mod->private = "echo"; mod->pkt_sm = _echo_pkt_sm; /* data is static so nothing to free */ /* mod->free = _echo_free; */ return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_help.c����������������������������������������������������������������0000664�0000000�0000000�00000014342�12614627753�0017155�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* for strndup */ #define _GNU_SOURCE #include <string.h> #include "sm.h" /** @file sm/mod_help.c * @brief forward messages to administrators * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.9 $ */ /* XEP-0157 serverinfo fields */ static const char *_serverinfo_fields[] = { "abuse-addresses", "admin-addresses", "feedback-addresses", "sales-addresses", "security-addresses", "support-addresses", NULL }; static mod_ret_t _help_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; jid_t all, msg, jid, smjid; int subj, subjectl; char *org_subject; char *subject; char *resource = (char *) mod->private; smjid = jid_new(jid_user(pkt->to), -1); jid_reset_components(smjid, smjid->node, smjid->domain, resource); /* answer to probes and subscription requests */ if(pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N) { log_debug(ZONE, "answering presence probe/sub from %s with /help resource", jid_full(pkt->from)); /* send presence */ pkt_router(pkt_create(mod->mm->sm, "presence", NULL, jid_user(pkt->from), jid_full(smjid))); } jid_free(smjid); /* we want messages addressed to the sm itself or /help resource */ if(!(pkt->type & pkt_MESSAGE) || (pkt->to->resource[0] != '\0' && strcmp(pkt->to->resource, "help"))) return mod_PASS; log_debug(ZONE, "help message from %s", jid_full(pkt->from)); all = xhash_get(mod->mm->sm->acls, "all"); msg = xhash_get(mod->mm->sm->acls, "messages"); nad_set_attr(pkt->nad, 1, -1, "type", NULL, 0); subj = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "subject", 1); if(subj >= 0 && NAD_CDATA_L(pkt->nad, subj) > 0) { org_subject = strndup(NAD_CDATA(pkt->nad, subj), NAD_CDATA_L(pkt->nad, subj)); } else { org_subject = "(none)"; } subjectl = strlen(org_subject) + strlen(jid_full(pkt->from)) + 8; subject = (char *) malloc(sizeof(char) * subjectl); snprintf(subject, subjectl, "Fwd[%s]: %s", jid_full(pkt->from), org_subject); if(subj >= 0 && NAD_CDATA_L(pkt->nad, subj) > 0) { free(org_subject); nad_drop_elem(pkt->nad, subj); } nad_insert_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "subject", subject); for(jid = all; jid != NULL; jid = jid->next) { if (jid_compare_full(pkt->from, jid) == 0) { /* make a copy of the nad so it can be dumped to a string */ nad_t copy = nad_copy(pkt->nad); const char * xml; int len; if (!copy) { log_write(mod->mm->sm->log, LOG_ERR, "%s:%d help admin %s is messaging sm for help! packet dropped. (unable to print packet - out of memory?)", ZONE, jid_full(jid)); continue; } nad_print(copy, 0, &xml, &len); log_write(mod->mm->sm->log, LOG_ERR, "%s:%d help admin %s is messaging sm for help! packet dropped: \"%.*s\"\n", ZONE, jid_full(jid), len, xml); nad_free(copy); continue; } log_debug(ZONE, "resending to %s", jid_full(jid)); pkt_router(pkt_dup(pkt, jid_full(jid), jid_user(pkt->to))); } for(jid = msg; jid != NULL; jid = jid->next) if(!jid_search(all, jid)) { log_debug(ZONE, "resending to %s", jid_full(jid)); pkt_router(pkt_dup(pkt, jid_full(jid), jid_user(pkt->to))); } /* !!! autoreply */ free(subject); pkt_free(pkt); return mod_HANDLED; } static void _help_disco_extend(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; int ns, i, n; config_elem_t elem; char confelem[64]; log_debug(ZONE, "in mod_help disco-extend"); if(config_get(mod->mm->sm->config, "discovery.serverinfo") == NULL) return; ns = nad_add_namespace(pkt->nad, uri_XDATA, NULL); /* there may be several XDATA siblings, so need to enforce the NS */ pkt->nad->scope = ns; nad_append_elem(pkt->nad, ns, "x", 3); nad_append_attr(pkt->nad, -1, "type", "result"); /* hidden form type field*/ nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "FORM_TYPE"); nad_append_attr(pkt->nad, -1, "type", "hidden"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, uri_SERVERINFO, strlen(uri_SERVERINFO), 6); /* loop over serverinfo fields */ for(i = 0; _serverinfo_fields[i]; i++) { snprintf(confelem, 64, "discovery.serverinfo.%s.value", _serverinfo_fields[i]); elem = config_get(mod->mm->sm->config, confelem); if(elem != NULL) { nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", _serverinfo_fields[i]); for(n = 0; n < elem->nvalues; n++) { log_debug(ZONE, "adding %s: %s", confelem, elem->values[n]); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, elem->values[n], strlen(elem->values[n]), 6); } } } } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; /* store /help resource for use when answering probes */ mod->private = "help"; mod->pkt_sm = _help_pkt_sm; mod->disco_extend = _help_disco_extend; /* module data is static so nothing to free */ /* mod->free = _help_free; */ return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_iq_last.c�������������������������������������������������������������0000664�0000000�0000000�00000010774�12614627753�0017666�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_last.c * @brief last activity * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.18 $ */ #define uri_LAST "jabber:iq:last" static int ns_LAST = 0; static mod_ret_t _iq_last_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; char uptime[10]; /* we only want to play with iq:last gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_LAST) return mod_PASS; snprintf(uptime, 10, "%d", (int) (time(NULL) - (time_t) mod->private)); nad_set_attr(pkt->nad, 2, -1, "seconds", uptime, 0); /* tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } static mod_ret_t _iq_last_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { char lasttime[10]; time_t t; os_t os; os_object_t o; st_ret_t ret; /* we only want to play with iq:last gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_LAST) return mod_PASS; /* make sure they're allowed */ if(!pres_trust(user, pkt->from)) return -stanza_err_FORBIDDEN; /* If the IQ was sent to a JID with a resource, then XMPP-IM 11.1.1 * requires we deliver it if that resource is available */ if (*pkt->to->resource != '\0') return mod_PASS; /* If they have an available resource, we should return a query element with a * seconds value of 0 */ if(user->top != NULL) { nad_set_attr(pkt->nad, 2, -1, "seconds", "0", 0); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } ret = storage_get(user->sm->st, "logout", jid_user(user->jid), NULL, &os); switch(ret) { case st_SUCCESS: t = 0; if(os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "time", &t); } os_free(os); snprintf(lasttime, 10, "%d", (int) (time(NULL) - t)); nad_set_attr(pkt->nad, 2, -1, "seconds", lasttime, 0); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTFOUND: return -stanza_err_SERVICE_UNAVAILABLE; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } /* we never get here */ return -stanza_err_INTERNAL_SERVER_ERROR; } static void _iq_last_sess_end(mod_instance_t mi, sess_t sess) { time_t t; os_t os; os_object_t o; /* store their logout time */ t = time(NULL); os = os_new(); o = os_object_new(os); os_object_put_time(o, "time", &t); storage_replace(sess->user->sm->st, "logout", jid_user(sess->jid), NULL, os); os_free(os); } static void _iq_last_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting logout time for %s", jid_user(jid)); storage_delete(mi->sm->st, "logout", jid_user(jid), NULL); } static void _iq_last_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_LAST); feature_unregister(mod->mm->sm, uri_LAST); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->sess_end = _iq_last_sess_end; mod->pkt_user = _iq_last_pkt_user; mod->pkt_sm = _iq_last_pkt_sm; mod->user_delete = _iq_last_user_delete; mod->free = _iq_last_free; /* startup time */ mod->private = (void *) time(NULL); ns_LAST = sm_register_ns(mod->mm->sm, uri_LAST); feature_register(mod->mm->sm, uri_LAST); return 0; } ����jabberd2-jabberd-2.3.4/sm/mod_iq_ping.c�������������������������������������������������������������0000664�0000000�0000000�00000004364�12614627753�0017656�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_ping.c * @brief xmpp ping * @author Tomasz Sieprawski * $Date: 2007/04/06 xx:xx:xx $ * $Revision: 1.0 $ */ static int ns_PING = 0; void _iq_ping_reply(pkt_t pkt) { int ns, elem; ns = nad_find_scoped_namespace(pkt->nad, urn_PING, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "ping", 1); if (elem>=0) nad_drop_elem(pkt->nad, elem); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); return; } static mod_ret_t _iq_ping_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { if(pkt->to != NULL || pkt->type != pkt_IQ || pkt->ns != ns_PING) return mod_PASS; _iq_ping_reply(pkt); pkt_sess(pkt, sess); return mod_HANDLED; } static mod_ret_t _iq_ping_pkt_sm(mod_instance_t mi, pkt_t pkt) { if(pkt->type != pkt_IQ || pkt->ns != ns_PING) return mod_PASS; _iq_ping_reply(pkt); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } static void _iq_ping_free(module_t mod) { sm_unregister_ns(mod->mm->sm, urn_PING); feature_unregister(mod->mm->sm, urn_PING); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _iq_ping_in_sess; mod->pkt_sm = _iq_ping_pkt_sm; mod->free = _iq_ping_free; ns_PING = sm_register_ns(mod->mm->sm, urn_PING); feature_register(mod->mm->sm, urn_PING); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_iq_private.c����������������������������������������������������������0000664�0000000�0000000�00000016731�12614627753�0020374�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_private.c * @brief private xml storage * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.24 $ */ #define uri_PRIVATE "jabber:iq:private" static int ns_PRIVATE = 0; static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, elem, target, targetns; st_ret_t ret; char filter[4096]; os_t os; os_object_t o; nad_t nad; pkt_t result; sess_t sscan; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "query", 1); /* find the first child */ target = elem + 1; while(target < pkt->nad->ecur) { if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth) break; target++; } /* not found, so we're done */ if(target == pkt->nad->ecur) return -stanza_err_BAD_REQUEST; /* find the target namespace */ targetns = NAD_ENS(pkt->nad, target); /* gotta have a namespace */ if(targetns < 0) { log_debug(ZONE, "no namespace specified"); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); /* get */ if(pkt->type == pkt_IQ) { /* remember that this resource requested the namespace */ if(sess->module_data[mod->index] == NULL) { /* create new hash if necesary */ sess->module_data[mod->index] = xhash_new(101); pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]); } xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os); switch(ret) { case st_SUCCESS: if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { result = pkt_new(sess->user->sm, nad_copy(nad)); if(result != NULL) { nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); os_free(os); return mod_HANDLED; } } } os_free(os); /* drop through */ log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND"); case st_NOTFOUND: log_debug(ZONE, "namespace not found, returning"); /* * !!! really, we should just return a 404. 1.4 just slaps a * result on the packet and sends it back. hurrah for * legacy namespaces. */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } } os = os_new(); o = os_object_new(os); snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); os_object_put(o, "ns", filter, os_type_STRING); os_object_put(o, "xml", pkt->nad, os_type_NAD); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: /* create result packet */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* and flush it to the session */ pkt_sess(result, sess); /* push it to all resources that read this xmlns item */ snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* skip our resource and those that didn't read any private-storage */ if(sscan == sess || sscan->module_data[mod->index] == NULL) continue; /* check whether namespace was read */ if(xhash_get(sscan->module_data[mod->index], filter)) { result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } /* finally free the packet */ pkt_free(pkt); return mod_HANDLED; } /* we never get here */ return 0; } static void _iq_private_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting private xml storage for %s", jid_user(jid)); storage_delete(mi->sm->st, "private", jid_user(jid), NULL); } static void _iq_private_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_PRIVATE); feature_unregister(mod->mm->sm, uri_PRIVATE); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if (mod->init) return 0; mod->in_sess = _iq_private_in_sess; mod->user_delete = _iq_private_user_delete; mod->free = _iq_private_free; ns_PRIVATE = sm_register_ns(mod->mm->sm, uri_PRIVATE); feature_register(mod->mm->sm, uri_PRIVATE); return 0; } ���������������������������������������jabberd2-jabberd-2.3.4/sm/mod_iq_time.c�������������������������������������������������������������0000664�0000000�0000000�00000006502�12614627753�0017653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_time.c * @brief entity time * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.14 $ */ #ifdef ENABLE_SUPERSEDED static int ns_TIME = 0; #endif static int ns_URN_TIME = 0; #ifdef HAVE_TZNAME extern char *tzname[]; #endif static mod_ret_t _iq_time_pkt_sm(mod_instance_t mi, pkt_t pkt) { time_t t; struct tm *tm; char buf[64]; char *c; /* we only want to play with iq:time gets */ #ifdef ENABLE_SUPERSEDED if(pkt->type != pkt_IQ || (pkt->ns != ns_TIME && pkt->ns != ns_URN_TIME)) #else if(pkt->type != pkt_IQ || pkt->ns != ns_URN_TIME) #endif return mod_PASS; t = time(NULL); tm = localtime(&t); #ifdef HAVE_TZSET tzset(); #endif #ifdef ENABLE_SUPERSEDED if(pkt->ns == ns_TIME) { datetime_out(t, dt_LEGACY, buf, 64); nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "utc", buf); strcpy(buf, asctime(tm)); c = strchr(buf, '\n'); if(c != NULL) *c = '\0'; nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "display", buf); #if defined(HAVE_STRUCT_TM_TM_ZONE) nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "tz", (char *) tm->tm_zone); #elif defined(HAVE_TZNAME) nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "tz", tzname[0]); #endif } else { #endif /* ENABLE_SUPERSEDED */ datetime_out(t, dt_DATETIME, buf, 64); nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "utc", buf); #ifdef HAVE_TZSET snprintf(buf, 64, "%+03d:%02d", -((int)timezone)/(60*60), -((int)timezone)%(60*60)); #else snprintf(buf, 64, "%+03d:%02d", (int) tm->tm_gmtoff/(60*60), (int) tm->tm_gmtoff%(60*60)); #endif nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "tzo", buf); #ifdef ENABLE_SUPERSEDED } #endif /* tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } static void _iq_time_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_TIME); feature_unregister(mod->mm->sm, uri_TIME); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->pkt_sm = _iq_time_pkt_sm; mod->free = _iq_time_free; #ifdef ENABLE_SUPERSEDED ns_TIME = sm_register_ns(mod->mm->sm, uri_TIME); feature_register(mod->mm->sm, uri_TIME); #endif ns_URN_TIME = sm_register_ns(mod->mm->sm, urn_TIME); feature_register(mod->mm->sm, urn_TIME); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_iq_vcard.c������������������������������������������������������������0000664�0000000�0000000�00000030700�12614627753�0020011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_vcard.c * @brief user profiles (vcard) * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.25 $ */ #define uri_VCARD "vcard-temp" static int ns_VCARD = 0; #define VCARD_MAX_FIELD_SIZE (16384) typedef struct _mod_iq_vcard_st { size_t vcard_max_field_size_default; size_t vcard_max_field_size_avatar; } *mod_iq_vcard_t; /** * these are the vcard attributes that gabber supports. they're also * all strings, and thus easy to automate. there might be more in * regular use, we need to check that out. one day, when we're all * using real foaf profiles, we'll have bigger things to worry about :) * * darco(2005-09-15): Added quite a few more fields, including those * necessary for vCard avatar support. */ static const char *_iq_vcard_map[] = { "FN", "fn", "N/FAMILY", "n-family", "N/GIVEN", "n-given", "N/MIDDLE", "n-middle", "N/PREFIX", "n-prefix", "N/SUFFIX", "n-suffix", "NICKNAME", "nickname", "PHOTO/TYPE", "photo-type", "PHOTO/BINVAL", "photo-binval", "PHOTO/EXTVAL", "photo-extval", "BDAY", "bday", "ADR/POBOX", "adr-pobox", "ADR/EXTADD", "adr-extadd", "ADR/STREET", "adr-street", "ADR/LOCALITY", "adr-locality", "ADR/REGION", "adr-region", "ADR/PCODE", "adr-pcode", "ADR/CTRY", "adr-country", "TEL/NUMBER", "tel", "EMAIL/USERID", "email", "JABBERID", "jabberid", "MAILER", "mailer", "TZ", "tz", "GEO/LAT", "geo-lat", "GEO/LON", "geo-lon", "TITLE", "title", "ROLE", "role", "LOGO/TYPE", "logo-type", "LOGO/BINVAL", "logo-binval", "LOGO/EXTVAL", "logo-extval", "AGENT/EXTVAL", "agent-extval", "ORG/ORGNAME", "org-orgname", "ORG/ORGUNIT", "org-orgunit", "NOTE", "note", "REV", "rev", "SORT-STRING", "sort-string", "SOUND/PHONETIC","sound-phonetic", "SOUND/BINVAL", "sound-binval", "SOUND/EXTVAL", "sound-extval", "UID", "uid", "URL", "url", "DESC", "desc", "KEY/TYPE", "key-type", "KEY/CRED", "key-cred", NULL, NULL }; static os_t _iq_vcard_to_object(mod_instance_t mi, pkt_t pkt) { os_t os; os_object_t o; int i = 0, elem; char ekey[10], *cdata; const char *vkey, *dkey, *vskey; size_t fieldsize; mod_iq_vcard_t iq_vcard = (mod_iq_vcard_t) mi->mod->private; log_debug(ZONE, "building object from packet"); os = os_new(); o = os_object_new(os); while(_iq_vcard_map[i] != NULL) { vkey = _iq_vcard_map[i]; dkey = _iq_vcard_map[i + 1]; i += 2; if( !strcmp(vkey, "PHOTO/BINVAL") ) { fieldsize = iq_vcard->vcard_max_field_size_avatar; } else { fieldsize = iq_vcard->vcard_max_field_size_default; } vskey = strchr(vkey, '/'); if(vskey == NULL) { vskey = vkey; elem = 2; } else { sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey); elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1); if(elem < 0) continue; vskey++; } elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, 2), vskey, 1); if(elem < 0 || NAD_CDATA_L(pkt->nad, elem) == 0) continue; log_debug(ZONE, "extracted vcard key %s val '%.*s' for db key %s", vkey, NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem), dkey); cdata = malloc(fieldsize); if(cdata) { snprintf(cdata, fieldsize, "%.*s", NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem)); cdata[fieldsize-1] = '\0'; os_object_put(o, dkey, cdata, os_type_STRING); free(cdata); } } return os; } static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os) { pkt_t pkt; os_object_t o; int i = 0, elem; char ekey[10], *dval; const char *vkey, *dkey, *vskey; log_debug(ZONE, "building packet from object"); pkt = pkt_create(sm, "iq", "result", NULL, NULL); nad_append_elem(pkt->nad, nad_add_namespace(pkt->nad, uri_VCARD, NULL), "vCard", 2); if(!os_iter_first(os)) return pkt; o = os_iter_object(os); while(_iq_vcard_map[i] != NULL) { vkey = _iq_vcard_map[i]; dkey = _iq_vcard_map[i + 1]; i += 2; if(!os_object_get_str(os, o, dkey, &dval)) continue; vskey = strchr(vkey, '/'); if(vskey == NULL) { vskey = vkey; elem = 2; } else { sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey); elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1); if(elem < 0) elem = nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), ekey, 3); vskey++; } log_debug(ZONE, "extracted dbkey %s val '%s' for vcard key %s", dkey, dval, vkey); if (!strcmp(dkey, "tel")) { nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), "VOICE", pkt->nad->elems[elem].depth + 1); } nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), vskey, pkt->nad->elems[elem].depth + 1); nad_append_cdata(pkt->nad, dval, strlen(dval), pkt->nad->elems[elem].depth + 2); } return pkt; } static mod_ret_t _iq_vcard_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { os_t os; st_ret_t ret; pkt_t result; /* only handle vcard sets and gets that aren't to anyone */ if(pkt->to != NULL || (pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD) return mod_PASS; /* get */ if(pkt->type == pkt_IQ) { if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid))) return -stanza_err_RESOURCE_CONSTRAINT; ret = storage_get(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, &os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; case st_NOTFOUND: nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); nad_set_attr(pkt->nad, 1, -1, "to", NULL, 0); nad_set_attr(pkt->nad, 1, -1, "from", NULL, 0); pkt_sess(pkt, sess); return mod_HANDLED; case st_SUCCESS: result = _iq_vcard_to_pkt(sess->user->sm, os); os_free(os); nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); return mod_HANDLED; } /* we never get here */ pkt_free(pkt); return mod_HANDLED; } os = _iq_vcard_to_object(mi, pkt); if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid))) return -stanza_err_RESOURCE_CONSTRAINT; ret = storage_replace(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); return mod_HANDLED; } /* we never get here */ pkt_free(pkt); return mod_HANDLED; } /* for the special JID of your jabber server bare domain. * You can have one for every virtual host * you can populate it using your DBMS frontend */ static mod_ret_t _iq_vcard_pkt_sm(mod_instance_t mi, pkt_t pkt) { os_t os; st_ret_t ret; pkt_t result; /* only handle vcard sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD) return mod_PASS; /* error them if they're trying to do a set */ if(pkt->type == pkt_IQ_SET) return -stanza_err_FORBIDDEN; /* a vcard for the server */ ret = storage_get(mi->sm->st, "vcard", pkt->to->domain, NULL, &os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; case st_NOTFOUND: return -stanza_err_ITEM_NOT_FOUND; case st_SUCCESS: result = _iq_vcard_to_pkt(mi->sm, os); os_free(os); result->to = jid_dup(pkt->from); result->from = jid_dup(pkt->to); nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0); nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0); pkt_id(pkt, result); pkt_router(result); pkt_free(pkt); return mod_HANDLED; } /* we never get here */ pkt_free(pkt); return mod_HANDLED; } static mod_ret_t _iq_vcard_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { os_t os; st_ret_t ret; pkt_t result; /* only handle vcard sets and gets, without resource */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD || pkt->to->resource[0] !='\0') return mod_PASS; /* error them if they're trying to do a set */ if(pkt->type == pkt_IQ_SET) return -stanza_err_FORBIDDEN; if (sm_storage_rate_limit(user->sm, jid_user(pkt->from))) return -stanza_err_RESOURCE_CONSTRAINT; ret = storage_get(user->sm->st, "vcard", jid_user(user->jid), NULL, &os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; case st_NOTFOUND: return -stanza_err_SERVICE_UNAVAILABLE; case st_SUCCESS: result = _iq_vcard_to_pkt(user->sm, os); os_free(os); result->to = jid_dup(pkt->from); result->from = jid_dup(pkt->to); nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0); nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0); pkt_id(pkt, result); pkt_router(result); pkt_free(pkt); return mod_HANDLED; } /* we never get here */ pkt_free(pkt); return mod_HANDLED; } static void _iq_vcard_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting vcard for %s", jid_user(jid)); storage_delete(mi->sm->st, "vcard", jid_user(jid), NULL); } static void _iq_vcard_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_VCARD); feature_unregister(mod->mm->sm, uri_VCARD); free(mod->private); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; mod_iq_vcard_t iq_vcard; if(mod->init) return 0; mod->pkt_sm = _iq_vcard_pkt_sm; mod->in_sess = _iq_vcard_in_sess; mod->pkt_user = _iq_vcard_pkt_user; mod->user_delete = _iq_vcard_user_delete; mod->free = _iq_vcard_free; ns_VCARD = sm_register_ns(mod->mm->sm, uri_VCARD); feature_register(mod->mm->sm, uri_VCARD); iq_vcard = (mod_iq_vcard_t) calloc(1, sizeof(struct _mod_iq_vcard_st)); iq_vcard->vcard_max_field_size_default = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.default", 0), VCARD_MAX_FIELD_SIZE); iq_vcard->vcard_max_field_size_avatar = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.avatar", 0), VCARD_MAX_FIELD_SIZE); mod->private = iq_vcard; return 0; } ����������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_iq_version.c����������������������������������������������������������0000664�0000000�0000000�00000022604�12614627753�0020403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_iq_version.c * @brief software version * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.16 $ */ #ifdef HAVE_SYS_UTSNAME_H # include <sys/utsname.h> #endif typedef struct _mod_iq_version_config_st { char *app_name; char *app_version; char *app_signature; char *os_name; char *os_release; } *mod_iq_version_config_t; static int ns_VERSION = 0; void _iq_version_get_os_version(mod_iq_version_config_t config) { #if defined(HAVE_UNAME) struct utsname un; #elif defined(_WIN32) char sysname[64]; char release[64]; OSVERSIONINFOEX osvi; BOOL bOsVersionInfoEx; BOOL bSomeError = FALSE; sysname[0] = '\0'; release[0] = '\0'; #endif /* figure out the os type */ #if defined(HAVE_UNAME) if(uname(&un) == 0) { config->os_name = strdup(un.sysname); config->os_release = strdup(un.machine); return; } #elif defined(_WIN32) ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) ) { /* If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. */ osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) { snprintf(sysname, 64, "unknown"); bSomeError = TRUE; } } if (!bSomeError) { switch (osvi.dwPlatformId) { case VER_PLATFORM_WIN32_NT: /* Test for the product. */ if ( osvi.dwMajorVersion <= 4 ) snprintf(sysname, 64, "Microsoft Windows NT"); if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) snprintf(sysname, 64, "Microsoft Windows 2000"); if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) snprintf(sysname, 64, "Microsoft Windows XP"); /* Test for product type. */ if( bOsVersionInfoEx ) { if ( osvi.wProductType == VER_NT_WORKSTATION ) { if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) snprintf(release, 64, "Personal" ); else snprintf(release, 64, "Professional" ); } else if ( osvi.wProductType == VER_NT_SERVER ) { if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) snprintf(release, 64, "DataCenter Server" ); else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) snprintf(release, 64, "Advanced Server" ); else snprintf(release, 64, "Server" ); } } else { HKEY hKey; char szProductType[80]; DWORD dwBufLen; RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey ); RegQueryValueEx( hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen); RegCloseKey( hKey ); if ( lstrcmpi( "WINNT", szProductType) == 0 ) snprintf(release, 64, "Professional" ); if ( lstrcmpi( "LANMANNT", szProductType) == 0 ) snprintf(release, 64, "Server" ); if ( lstrcmpi( "SERVERNT", szProductType) == 0 ) snprintf(release, 64, "Advanced Server" ); } break; case VER_PLATFORM_WIN32_WINDOWS: if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { snprintf(sysname, 64, "Microsoft Windows 95"); if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' ) snprintf(release, 64, "OSR2" ); } if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { snprintf(sysname, 64, "Microsoft Windows 98"); if ( osvi.szCSDVersion[1] == 'A' ) snprintf(release, 64, "SE" ); } if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { snprintf(sysname, 64, "Microsoft Windows Me"); } break; case VER_PLATFORM_WIN32s: snprintf(sysname, 64, "Microsoft Win32s"); break; } } config->os_name = strdup(sysname); config->os_release = strdup(release); return; #endif } static mod_ret_t _iq_version_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; mod_iq_version_config_t config = (mod_iq_version_config_t) mod->private; char buf[256]; /* we only want to play with iq:version gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_VERSION) return mod_PASS; nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "name", config->app_name); nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "version", config->app_version); /* figure out the os type */ if(config->os_name != NULL) { if(config->os_release) snprintf(buf, 256, "%s %s", config->os_name, config->os_release); else snprintf(buf, 256, "%s", config->os_name); nad_insert_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 1), "os", buf); } /* tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } static void _iq_version_disco_extend(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; mod_iq_version_config_t config = (mod_iq_version_config_t) mod->private; int ns; log_debug(ZONE, "in mod_iq_version disco-extend"); ns = nad_add_namespace(pkt->nad, uri_XDATA, NULL); /* there may be several XDATA siblings, so need to enforce the NS */ pkt->nad->scope = ns; nad_append_elem(pkt->nad, ns, "x", 3); nad_append_attr(pkt->nad, -1, "type", "result"); /* hidden form type field*/ nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "FORM_TYPE"); nad_append_attr(pkt->nad, -1, "type", "hidden"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, urn_SOFTWAREINFO, strlen(urn_SOFTWAREINFO), 6); nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "software"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, config->app_name, strlen(config->app_name), 6); nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "software_version"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, config->app_version, strlen(config->app_version), 6); if(config->os_name != NULL) { nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "os"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, config->os_name, strlen(config->os_name), 6); } if(config->os_name != NULL) { nad_append_elem(pkt->nad, -1, "field", 4); nad_append_attr(pkt->nad, -1, "var", "os_version"); nad_append_elem(pkt->nad, -1, "value", 5); nad_append_cdata(pkt->nad, config->os_release, strlen(config->os_release), 6); } } static void _iq_version_free(module_t mod) { mod_iq_version_config_t config = (mod_iq_version_config_t) mod->private; sm_unregister_ns(mod->mm->sm, uri_VERSION); feature_unregister(mod->mm->sm, uri_VERSION); if(config->os_name != NULL) free(config->os_name); if(config->os_release != NULL) free(config->os_release); free(config); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { mod_iq_version_config_t config; module_t mod = mi->mod; if(mod->init) return 0; config = (mod_iq_version_config_t) calloc(1, sizeof(struct _mod_iq_version_config_st)); config->app_name = PACKAGE; config->app_version = VERSION; config->app_signature = mi->sm->signature; _iq_version_get_os_version(config); mod->private = config; mod->pkt_sm = _iq_version_pkt_sm; mod->disco_extend = _iq_version_disco_extend; mod->free = _iq_version_free; ns_VERSION = sm_register_ns(mod->mm->sm, uri_VERSION); feature_register(mod->mm->sm, uri_VERSION); return 0; } ����������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_offline.c�������������������������������������������������������������0000664�0000000�0000000�00000027533�12614627753�0017655�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_offline.c * @brief offline storage * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.26 $ */ typedef struct _mod_offline_st { int dropmessages; int storeheadlines; int dropsubscriptions; int userquota; } *mod_offline_t; static mod_ret_t _offline_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { st_ret_t ret; os_t os; os_object_t o; nad_t nad; pkt_t queued; int ns, elem, attr; char cttl[15], cstamp[18]; time_t ttl, stamp; /* if they're becoming available for the first time */ if(pkt->type == pkt_PRESENCE && sess->pri >= 0 && pkt->to == NULL && sess->user->top == NULL) { ret = storage_get(pkt->sm->st, "queue", jid_user(sess->jid), NULL, &os); if(ret != st_SUCCESS) { log_debug(ZONE, "storage_get returned %d", ret); return mod_PASS; } if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { queued = pkt_new(pkt->sm, nad_copy(nad)); if(queued == NULL) { log_debug(ZONE, "invalid queued packet, not delivering"); } else { /* check expiry as necessary */ if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) { snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); ttl = atoi(cttl); /* it should have a x:delay stamp, because we stamp everything we store */ if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) { snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); stamp = datetime_in(cstamp); if(stamp + ttl <= time(NULL)) { log_debug(ZONE, "queued packet has expired, dropping"); pkt_free(queued); continue; } } } log_debug(ZONE, "delivering queued packet to %s", jid_full(sess->jid)); pkt_sess(queued, sess); } } } while(os_iter_next(os)); os_free(os); /* drop the spool */ storage_delete(pkt->sm->st, "queue", jid_user(sess->jid), NULL); } /* pass it so that other modules and mod_presence can get it */ return mod_PASS; } static mod_ret_t _offline_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { mod_offline_t offline = (mod_offline_t) mi->mod->private; int ns, elem, attr; os_t os; os_object_t o; pkt_t event; st_ret_t ret; int queuesize; /* send messages to the top sessions */ if(user->top != NULL && (pkt->type & pkt_MESSAGE || pkt->type & pkt_S10N)) { sess_t scan; /* loop over each session */ for(scan = user->sessions; scan != NULL; scan = scan->next) { /* don't deliver to unavailable sessions */ if(!scan->available) continue; /* skip negative priorities */ if(scan->pri < 0) continue; /* headlines go to all, other to top priority */ if(pkt->type != pkt_MESSAGE_HEADLINE && scan->pri < user->top->pri) continue; /* deliver to session */ log_debug(ZONE, "delivering message to %s", jid_full(scan->jid)); pkt_sess(pkt_dup(pkt, jid_full(scan->jid), jid_full(pkt->from)), scan); } pkt_free(pkt); return mod_HANDLED; } /* if user quotas are enabled, count the number of offline messages this user has in the queue */ if(offline->userquota > 0) { ret = storage_count(user->sm->st, "queue", jid_user(user->jid), NULL, &queuesize); log_debug(ZONE, "storage_count ret is %i queue size is %i", ret, queuesize); /* if the user's quota is exceeded, return an error */ if (ret == st_SUCCESS && (pkt->type & pkt_MESSAGE) && queuesize >= offline->userquota) return -stanza_err_SERVICE_UNAVAILABLE; } /* save messages and s10ns for later */ if((pkt->type & pkt_MESSAGE && !offline->dropmessages) || (pkt->type & pkt_S10N && !offline->dropsubscriptions)) { /* check type of the message and drop headlines and groupchat */ if((((pkt->type & pkt_MESSAGE_HEADLINE) == pkt_MESSAGE_HEADLINE) && !offline->storeheadlines) || (pkt->type & pkt_MESSAGE_GROUPCHAT) == pkt_MESSAGE_GROUPCHAT) { log_debug(ZONE, "not saving message (type 0x%X) for later", pkt->type); pkt_free(pkt); return mod_HANDLED; } log_debug(ZONE, "saving packet for later"); pkt_delay(pkt, time(NULL), user->jid->domain); /* new object */ os = os_new(); o = os_object_new(os); os_object_put(o, "xml", pkt->nad, os_type_NAD); /* store it */ switch(storage_put(user->sm->st, "queue", jid_user(user->jid), os)) { case st_FAILED: os_free(os); return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: os_free(os); return -stanza_err_SERVICE_UNAVAILABLE; /* xmpp-im 9.5#4 */ default: os_free(os); /* XEP-0022 - send offline events if they asked for it */ /* if there's an id element, then this is a notification, not a request, so ignore it */ if((ns = nad_find_scoped_namespace(pkt->nad, uri_EVENT, NULL)) >= 0 && (elem = nad_find_elem(pkt->nad, 1, ns, "x", 1)) >= 0 && nad_find_elem(pkt->nad, elem, ns, "offline", 1) >= 0 && nad_find_elem(pkt->nad, elem, ns, "id", 1) < 0) { event = pkt_create(user->sm, "message", NULL, jid_full(pkt->from), jid_full(pkt->to)); attr = nad_find_attr(pkt->nad, 1, -1, "type", NULL); if(attr >= 0) nad_set_attr(event->nad, 1, -1, "type", NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); ns = nad_add_namespace(event->nad, uri_EVENT, NULL); nad_append_elem(event->nad, ns, "x", 2); nad_append_elem(event->nad, ns, "offline", 3); nad_append_elem(event->nad, ns, "id", 3); attr = nad_find_attr(pkt->nad, 1, -1, "id", NULL); if(attr >= 0) nad_append_cdata(event->nad, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr), 4); pkt_router(event); } pkt_free(pkt); return mod_HANDLED; } } return mod_PASS; } static void _offline_user_delete(mod_instance_t mi, jid_t jid) { os_t os; os_object_t o; nad_t nad; pkt_t queued; int ns, elem, attr; char cttl[15], cstamp[18]; time_t ttl, stamp; log_debug(ZONE, "deleting queue for %s", jid_user(jid)); /* bounce the queue */ if(storage_get(mi->mod->mm->sm->st, "queue", jid_user(jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { queued = pkt_new(mi->mod->mm->sm, nad_copy(nad)); if(queued == NULL) { log_debug(ZONE, "invalid queued packet, not delivering"); } else { /* check expiry as necessary */ if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) { snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); ttl = atoi(cttl); /* it should have a x:delay stamp, because we stamp everything we store */ if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) { snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); stamp = datetime_in(cstamp); if(stamp + ttl <= time(NULL)) { log_debug(ZONE, "queued packet has expired, dropping"); pkt_free(queued); continue; } } } log_debug(ZONE, "bouncing queued packet from %s", jid_full(queued->from)); pkt_router(pkt_error(queued, stanza_err_ITEM_NOT_FOUND)); } } } while(os_iter_next(os)); os_free(os); } storage_delete(mi->sm->st, "queue", jid_user(jid), NULL); } static void _offline_free(module_t mod) { mod_offline_t offline = (mod_offline_t) mod->private; free(offline); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; const char *configval; mod_offline_t offline; if(mod->init) return 0; offline = (mod_offline_t) calloc(1, sizeof(struct _mod_offline_st)); configval = config_get_one(mod->mm->sm->config, "offline.dropmessages", 0); if (configval != NULL) offline->dropmessages = 1; configval = config_get_one(mod->mm->sm->config, "offline.storeheadlines", 0); if (configval != NULL) offline->storeheadlines = 1; configval = config_get_one(mod->mm->sm->config, "offline.dropsubscriptions", 0); if (configval != NULL) offline->dropsubscriptions = 1; offline->userquota = j_atoi(config_get_one(mod->mm->sm->config, "offline.userquota", 0), 0); mod->private = offline; mod->in_sess = _offline_in_sess; mod->pkt_user = _offline_pkt_user; mod->user_delete = _offline_user_delete; mod->free = _offline_free; feature_register(mod->mm->sm, "msgoffline"); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_pep.c�����������������������������������������������������������������0000664�0000000�0000000�00000006075�12614627753�0017015�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2009 Tomasz Sterna * * 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, MA02111-1307USA */ #include "sm.h" /* * XEP-0163 is some lunatic nightmare... * * If you want it - YOU implement it! */ /** @file sm/mod_pep.c * @brief XEP-0163: Personal Eventing Protocol * @author Tomasz Sterna */ #define uri_PUBSUB "http://jabber.org/protocol/pubsub" static int ns_PUBSUB = 0; static mod_ret_t _pep_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { int ns, elem; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PUBSUB) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PUBSUB, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "pubsub", 1); log_debug(ZONE, "_pep_in_sess() %d %d", ns, elem); return mod_PASS; } static mod_ret_t _pep_out_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* add pep identity to disco results from bare JID */ if(!(pkt->type & pkt_IQ) || pkt->ns != ns_DISCO_INFO || (pkt->from != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->from)))) return mod_PASS; /* add PEP identity */ nad_append_elem(pkt->nad, -1, "identity", 3); nad_append_attr(pkt->nad, -1, "category", "pubsub"); nad_append_attr(pkt->nad, -1, "type", "pep"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#access-presence"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#auto-create"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#auto-subscribe"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#filtered-notifications"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#publish"); return mod_PASS; } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _pep_in_sess; mod->out_sess = _pep_out_sess; ns_PUBSUB = sm_register_ns(mod->mm->sm, uri_PUBSUB); feature_register(mod->mm->sm, uri_PUBSUB); return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_presence.c������������������������������������������������������������0000664�0000000�0000000�00000013371�12614627753�0020032�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_presence.c * @brief presence tracker driver * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.17 $ */ /** presence from the session */ static mod_ret_t _presence_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* only handle presence */ if(!(pkt->type & pkt_PRESENCE)) return mod_PASS; /* reset from if necessary */ if(pkt->from == NULL || jid_compare_user(pkt->from, sess->jid) != 0) { if(pkt->from != NULL) jid_free(pkt->from); pkt->from = jid_dup(sess->jid); nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); } /* presence broadcast (T1, T2, T3) */ if(pkt->to == NULL) pres_update(sess, pkt); /* directed presence (T7, T8) */ else pres_deliver(sess, pkt); return mod_HANDLED; } /* drop incoming presence if the user isn't around, * so we don't have to load them during broadcasts */ mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt) { user_t user; sess_t sess; /* only check presence to users, pass presence to sm and probes */ if(!(pkt->type & pkt_PRESENCE) || pkt->to->node[0] == '\0' || pkt->type == pkt_PRESENCE_PROBE) return mod_PASS; /* get the user _without_ doing a load */ user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to)); /* no user, or no sessions, bail */ if(user == NULL || user->sessions == NULL) { pkt_free(pkt); return mod_HANDLED; } /* only pass if there's at least one available session */ for(sess = user->sessions; sess != NULL; sess = sess->next) if(sess->available) return mod_PASS; /* no available sessions, drop */ pkt_free(pkt); return mod_HANDLED; } /** presence to a user */ static mod_ret_t _presence_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { sess_t sess; /* only handle presence */ if(!(pkt->type & pkt_PRESENCE)) return mod_PASS; /* errors get tracked, but still delivered (T6) */ if(pkt->type & pkt_ERROR) { /* find the session */ sess = sess_match(user, pkt->to->resource); if(sess == NULL) { log_debug(ZONE, "bounced presence, but no corresponding session anymore, dropping"); pkt_free(pkt); return mod_HANDLED; } log_debug(ZONE, "bounced presence, tracking"); pres_error(sess, pkt->from); /* bounced probes get dropped */ if((pkt->type & pkt_PRESENCE_PROBE) == pkt_PRESENCE_PROBE) { pkt_free(pkt); return mod_HANDLED; } } /* if there's a resource, send it direct */ if(pkt->to->resource[0] != '\0') { sess = sess_match(user, pkt->to->resource); if(sess == NULL) { /* resource isn't online - XMPP-IM 11.3 requires we ignore it*/ pkt_free(pkt); return mod_HANDLED; } pkt_sess(pkt, sess); return mod_HANDLED; } /* remote presence updates (T4, T5) */ pres_in(user, pkt); return mod_HANDLED; } /* presence packets to the sm */ static mod_ret_t _presence_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; jid_t smjid; /* only check presence/subs to server JID */ if(!(pkt->type & pkt_PRESENCE || pkt->type & pkt_S10N)) return mod_PASS; smjid = jid_new(jid_user(pkt->to), -1); /* handle subscription requests */ if(pkt->type == pkt_S10N) { log_debug(ZONE, "accepting subscription request from %s", jid_full(pkt->from)); /* accept request */ pkt_router(pkt_create(mod->mm->sm, "presence", "subscribed", jid_user(pkt->from), jid_user(smjid))); /* and subscribe back to theirs */ pkt_router(pkt_create(mod->mm->sm, "presence", "subscribe", jid_user(pkt->from), jid_user(smjid))); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; } /* handle unsubscribe requests */ if(pkt->type == pkt_S10N_UN) { log_debug(ZONE, "accepting unsubscribe request from %s", jid_full(pkt->from)); /* ack the request */ pkt_router(pkt_create(mod->mm->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(smjid))); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; } /* drop the rest */ log_debug(ZONE, "dropping presence from %s", jid_full(pkt->from)); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; } static void _presence_free(module_t mod) { feature_unregister(mod->mm->sm, "presence"); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _presence_in_sess; mod->in_router = _presence_in_router; mod->pkt_user = _presence_pkt_user; mod->pkt_sm = _presence_pkt_sm; mod->free = _presence_free; feature_register(mod->mm->sm, "presence"); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_privacy.c�������������������������������������������������������������0000664�0000000�0000000�00000142056�12614627753�0017706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_privacy.c * @brief XEP-0016 Privacy Lists and XEP-0191 Simple Comunications Blocking * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.32 $ */ static int ns_PRIVACY = 0; static int ns_BLOCKING = 0; typedef struct zebra_st *zebra_t; typedef struct zebra_list_st *zebra_list_t; typedef struct zebra_item_st *zebra_item_t; typedef enum { zebra_NONE, zebra_JID, zebra_GROUP, zebra_S10N } zebra_item_type_t; typedef enum { block_NONE = 0x00, block_MESSAGE = 0x01, block_PRES_IN = 0x02, block_PRES_OUT = 0x04, block_IQ = 0x08 } zebra_block_type_t; /** zebra data for a single user */ struct zebra_st { xht lists; zebra_list_t def; }; struct zebra_list_st { pool_t p; char *name; zebra_item_t items, last; }; struct zebra_item_st { zebra_item_type_t type; jid_t jid; char *group; int to; int from; int deny; /* 0 = allow, 1 = deny */ int order; zebra_block_type_t block; zebra_item_t next, prev; }; typedef struct privacy_st { /* currently active list */ zebra_list_t active; /* was blocklist requested */ int blocklist; } *privacy_t; /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; zebra_list_t *z_val; }; static void _privacy_free_z(zebra_t z) { zebra_list_t zlist; union xhashv xhv; log_debug(ZONE, "freeing zebra ctx"); if(xhash_iter_first(z->lists)) do { xhv.z_val = &zlist; xhash_iter_get(z->lists, NULL, NULL, xhv.val); pool_free(zlist->p); } while(xhash_iter_next(z->lists)); xhash_free(z->lists); free(z); } static void _privacy_user_free(zebra_t *z) { if(*z != NULL) _privacy_free_z(*z); } static int _privacy_user_load(mod_instance_t mi, user_t user) { module_t mod = mi->mod; zebra_t z; os_t os; os_object_t o; zebra_list_t zlist; pool_t p; zebra_item_t zitem, scan; char *str; log_debug(ZONE, "loading privacy lists for %s", jid_user(user->jid)); /* free if necessary */ z = user->module_data[mod->index]; if(z != NULL) _privacy_free_z(z); z = (zebra_t) calloc(1, sizeof(struct zebra_st)); z->lists = xhash_new(101); user->module_data[mod->index] = z; pool_cleanup(user->p, (void (*))(void *) _privacy_user_free, &(user->module_data[mod->index])); /* pull the whole lot */ if(storage_get(user->sm->st, "privacy-items", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) do { o = os_iter_object(os); /* list name */ if(!os_object_get_str(os, o, "list", &str)) { log_debug(ZONE, "item with no list field, skipping"); continue; } log_debug(ZONE, "got item for list %s", str); zlist = xhash_get(z->lists, str); /* new list */ if(zlist == NULL) { log_debug(ZONE, "creating list %s", str); p = pool_new(); zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st)); zlist->p = p; zlist->name = pstrdup(p, str); xhash_put(z->lists, zlist->name, (void *) zlist); } /* new item */ zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st)); /* item type */ if(os_object_get_str(os, o, "type", &str)) switch(str[0]) { case 'j': zitem->type = zebra_JID; break; case 'g': zitem->type = zebra_GROUP; break; case 's': zitem->type = zebra_S10N; break; } /* item value, according to type */ if(zitem->type != zebra_NONE) { if(!os_object_get_str(os, o, "value", &str)) { log_debug(ZONE, "no value on non-fall-through item, dropping this item"); continue; } switch(zitem->type) { case zebra_JID: zitem->jid = jid_new(str, strlen(str)); if(zitem->jid == NULL) { log_debug(ZONE, "invalid jid '%s' on item, dropping this item", str); continue; } pool_cleanup(zlist->p, (void *) jid_free, zitem->jid); log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid)); break; case zebra_GROUP: zitem->group = pstrdup(zlist->p, str); log_debug(ZONE, "group item with value '%s'", zitem->group); break; case zebra_S10N: if(strcmp(str, "to") == 0) zitem->to = 1; else if(strcmp(str, "from") == 0) zitem->from = 1; else if(strcmp(str, "both") == 0) zitem->to = zitem->from = 1; else if(strcmp(str, "none") != 0) { log_debug(ZONE, "invalid value '%s' on s10n item, dropping this item", str); continue; } log_debug(ZONE, "s10n item with value '%s' (to %d from %d)", str, zitem->to, zitem->from); break; case zebra_NONE: /* can't get here */ break; } } /* action */ os_object_get_bool(os, o, "deny", &zitem->deny); if(zitem->deny) { log_debug(ZONE, "deny rule"); } else { log_debug(ZONE, "accept rule"); } os_object_get_int(os, o, "order", &(zitem->order)); log_debug(ZONE, "order %d", zitem->order); os_object_get_int(os, o, "block", (int*) &(zitem->block)); log_debug(ZONE, "block 0x%x", zitem->block); /* insert it */ for(scan = zlist->items; scan != NULL; scan = scan->next) if(zitem->order < scan->order) break; /* we're >= everyone, add us to the end */ if(scan == NULL) { if(zlist->last == NULL) zlist->items = zlist->last = zitem; else { zlist->last->next = zitem; zitem->prev = zlist->last; zlist->last = zitem; } } /* insert just before scan */ else { if(zlist->items == scan) { zitem->next = zlist->items; zlist->items = zitem; scan->prev = zitem; } else { zitem->next = scan; zitem->prev = scan->prev; scan->prev->next = zitem; scan->prev = zitem; } } } while(os_iter_next(os)); os_free(os); } /* default list */ if(storage_get(user->sm->st, "privacy-default", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_str(os, o, "default", &str)) { z->def = (zebra_list_t) xhash_get(z->lists, str); if(z->def == NULL) { log_debug(ZONE, "storage says the default list for %s is %s, but it doesn't exist!", jid_user(user->jid), str); } else { log_debug(ZONE, "user %s has default list %s", jid_user(user->jid), str); } } } while(os_iter_next(os)); os_free(os); } return 0; } /** returns 0 if the packet should be allowed, otherwise 1 */ static int _privacy_action(user_t user, zebra_list_t zlist, jid_t jid, pkt_type_t ptype, int in) { zebra_item_t scan; int match, i; item_t ritem; char domres[2048]; log_debug(ZONE, "running match on list %s for %s (packet type 0x%x) (%s)", zlist->name, jid_full(jid), ptype, in ? "incoming" : "outgoing"); /* loop over the list, trying to find a match */ for(scan = zlist->items; scan != NULL; scan = scan->next) { match = 0; switch(scan->type) { case zebra_NONE: /* fall through, all packets match this */ match = 1; break; case zebra_JID: snprintf(domres, sizeof(domres) / sizeof(domres[0]), "%s/%s", jid->domain, jid->resource); /* jid check - match node@dom/res, then node@dom, then dom/resource, then dom */ if(jid_compare_full(scan->jid, jid) == 0 || strcmp(jid_full(scan->jid), jid_user(jid)) == 0 || strcmp(jid_full(scan->jid), domres) == 0 || strcmp(jid_full(scan->jid), jid->domain) == 0) match = 1; break; case zebra_GROUP: /* roster group check - get the roster item, node@dom/res, then node@dom, then dom */ ritem = xhash_get(user->roster, jid_full(jid)); if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid)); if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain); /* got it, do the check */ if(ritem != NULL) for(i = 0; i < ritem->ngroups; i++) if(strcmp(scan->group, ritem->groups[i]) == 0) match = 1; break; case zebra_S10N: /* roster item check - get the roster item, node@dom/res, then node@dom, then dom */ ritem = xhash_get(user->roster, jid_full(jid)); if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid)); if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain); /* got it, do the check */ if(ritem != NULL) if(scan->to == ritem->to && scan->from == ritem->from) match = 1; break; } /* if we matched a rule, we have to do packet block matching */ if(match) { /* no packet blocking, matching done */ if(scan->block == block_NONE) return scan->deny; /* incoming checks block_MESSAGE, block_PRES_IN and block_IQ */ if(in) { if(ptype & pkt_MESSAGE && scan->block & block_MESSAGE) return scan->deny; if(ptype & pkt_PRESENCE && scan->block & block_PRES_IN) return scan->deny; if(ptype & pkt_IQ && scan->block & block_IQ) return scan->deny; } else if((ptype & pkt_PRESENCE && scan->block & block_PRES_OUT && ptype != pkt_PRESENCE_PROBE) || (ptype & pkt_MESSAGE && scan->block & block_MESSAGE)) { /* outgoing check, block_PRES_OUT */ /* XXX and block_MESSAGE for XEP-0191 while it violates XEP-0016 */ return scan->deny; } } } /* didn't match the list, so allow */ return 0; } /** check incoming packets */ static mod_ret_t _privacy_in_router(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; user_t user; zebra_t z; sess_t sess = NULL; zebra_list_t zlist = NULL; /* if its coming to the sm, let it in */ if(pkt->to == NULL || pkt->to->node[0] == '\0') return mod_PASS; /* get the user */ user = user_load(mod->mm->sm, pkt->to); if(user == NULL) { log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to)); return mod_PASS; } /* get our lists */ z = (zebra_t) user->module_data[mod->index]; /* find a session */ if(*pkt->to->resource != '\0') sess = sess_match(user, pkt->to->resource); /* didn't match a session, so use the top session */ if(sess == NULL) sess = user->top; /* get the active list for the session */ if(sess != NULL && sess->module_data[mod->index] != NULL) zlist = ((privacy_t) sess->module_data[mod->index])->active; /* no active list, so use the default list */ if(zlist == NULL) zlist = z->def; /* no list, so allow everything */ if(zlist == NULL) return mod_PASS; /* figure out the action */ if(_privacy_action(user, zlist, pkt->from, pkt->type, 1) == 0) return mod_PASS; /* deny */ log_debug(ZONE, "denying incoming packet based on privacy policy"); /* iqs get special treatment */ if(pkt->type == pkt_IQ || pkt->type == pkt_IQ_SET) return -stanza_err_FEATURE_NOT_IMPLEMENTED; /* drop it */ pkt_free(pkt); return mod_HANDLED; } /** check outgoing packets */ static mod_ret_t _privacy_out_router(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; user_t user; zebra_t z; sess_t sess = NULL; zebra_list_t zlist = NULL; int err, ns; /* if its coming from the sm, let it go */ if(pkt->from == NULL || pkt->from->node[0] == '\0') return mod_PASS; /* get the user */ user = user_load(mod->mm->sm, pkt->from); if(user == NULL) { log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to)); return mod_PASS; } /* get our lists */ z = (zebra_t) user->module_data[mod->index]; /* find a session */ if(*pkt->from->resource != '\0') sess = sess_match(user, pkt->from->resource); /* get the active list for the session */ if(sess != NULL && sess->module_data[mod->index] != NULL) zlist = ((privacy_t) sess->module_data[mod->index])->active; /* no active list, so use the default list */ if(zlist == NULL) zlist = z->def; /* no list, so allow everything */ if(zlist == NULL) return mod_PASS; /* figure out the action */ if(_privacy_action(user, zlist, pkt->to, pkt->type, 0) == 0) return mod_PASS; /* deny */ log_debug(ZONE, "denying outgoing packet based on privacy policy"); /* messages get special treatment */ if(pkt->type & pkt_MESSAGE) { /* hack the XEP-0191 error in */ pkt_error(pkt, stanza_err_NOT_ACCEPTABLE); err = nad_find_elem(pkt->nad, 1, -1, "error", 1); ns = nad_add_namespace(pkt->nad, urn_BLOCKING_ERR, NULL); nad_insert_elem(pkt->nad, err, ns, "blocked", NULL); pkt_sess(pkt, sess); return mod_HANDLED; } /* drop it */ pkt_free(pkt); return mod_HANDLED; } /** add a list to the return packet */ static void _privacy_result_builder(xht zhash, const char *name, void *val, void *arg) { zebra_list_t zlist = (zebra_list_t) val; pkt_t pkt = (pkt_t) arg; int ns, query, list, item; zebra_item_t zitem; char order[14]; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL); query = nad_find_elem(pkt->nad, 1, ns, "query", 1); list = nad_insert_elem(pkt->nad, query, ns, "list", NULL); nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0); /* run through the items and build the nad */ for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) { item = nad_insert_elem(pkt->nad, list, ns, "item", NULL); switch(zitem->type) { case zebra_JID: nad_set_attr(pkt->nad, item, -1, "type", "jid", 0); nad_set_attr(pkt->nad, item, -1, "value", jid_full(zitem->jid), 0); break; case zebra_GROUP: nad_set_attr(pkt->nad, item, -1, "type", "group", 0); nad_set_attr(pkt->nad, item, -1, "value", zitem->group, 0); break; case zebra_S10N: nad_set_attr(pkt->nad, item, -1, "type", "subscription", 0); if(zitem->to == 1 && zitem->from == 1) nad_set_attr(pkt->nad, item, -1, "value", "both", 4); else if(zitem->to == 1) nad_set_attr(pkt->nad, item, -1, "value", "to", 2); else if(zitem->from == 1) nad_set_attr(pkt->nad, item, -1, "value", "from", 4); else nad_set_attr(pkt->nad, item, -1, "value", "none", 4); break; case zebra_NONE: break; } if(zitem->deny) nad_set_attr(pkt->nad, item, -1, "action", "deny", 4); else nad_set_attr(pkt->nad, item, -1, "action", "allow", 5); snprintf(order, 14, "%d", zitem->order); order[13] = '\0'; nad_set_attr(pkt->nad, item, -1, "order", order, 0); if(zitem->block & block_MESSAGE) nad_insert_elem(pkt->nad, item, ns, "message", NULL); if(zitem->block & block_PRES_IN) nad_insert_elem(pkt->nad, item, ns, "presence-in", NULL); if(zitem->block & block_PRES_OUT) nad_insert_elem(pkt->nad, item, ns, "presence-out", NULL); if(zitem->block & block_IQ) nad_insert_elem(pkt->nad, item, ns, "iq", NULL); } } /** add a list to the return packet */ static void _privacy_lists_result_builder(const char *name, int namelen, void *val, void *arg) { zebra_list_t zlist = (zebra_list_t) val; pkt_t pkt = (pkt_t) arg; int ns, query, list; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL); query = nad_find_elem(pkt->nad, 1, ns, "query", 1); list = nad_insert_elem(pkt->nad, query, ns, "list", NULL); nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0); } /** remove jid deny ocurrences from the privacy list, unblock all if no jid given to match, then update unblocked contact with presence information */ static void _unblock_jid(user_t user, storage_t st, zebra_list_t zlist, jid_t jid) { char filter[1024]; zebra_item_t scan; sess_t sscan; jid_t notify_jid = NULL; for(scan = zlist->items; scan != NULL; scan = scan->next) { if(scan->type == zebra_JID && scan->deny && (jid == NULL || jid_compare_full(scan->jid, jid) == 0)) { if(zlist->items == scan) { zlist->items = scan->next; if(zlist->items != NULL) zlist->items->prev = NULL; } else { assert(scan->prev != NULL); scan->prev->next = scan->next; if(scan->next != NULL) scan->next->prev = scan->prev; } if (zlist->last == scan) zlist->last = scan->prev; /* and from the storage */ sprintf(filter, "(&(list=%zu:%s)(type=3:jid)(value=%zu:%s))", strlen(urn_BLOCKING), urn_BLOCKING, strlen(jid_full(scan->jid)), jid_full(scan->jid)); storage_delete(st, "privacy-items", jid_user(user->jid), filter); /* set jid for notify */ notify_jid = scan->jid; } /* update unblocked contact with presence information of all sessions */ /* XXX NOTE !!! There is a possibility that we notify more than once * if user edited the privacy list manually, not with XEP-0191. * Well... We're going to live with it. ;-) */ if(notify_jid != NULL && pres_trust(user, notify_jid)) for(sscan = user->sessions; sscan != NULL; sscan = sscan->next) { /* do not update if session is not available, * we sent presence direct or got error bounce */ if(!sscan->available || jid_search(sscan->A, notify_jid) || jid_search(sscan->E, notify_jid)) continue; log_debug(ZONE, "updating unblocked %s with presence from %s", jid_full(notify_jid), jid_full(sscan->jid)); pkt_router(pkt_dup(sscan->pres, jid_full(notify_jid), jid_full(sscan->jid))); } } } /** list management requests */ static mod_ret_t _privacy_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, query, list, name, active, def, item, type, value, action, order, blocking, jid, push = 0; char corder[14], str[256], filter[1024]; zebra_t z; zebra_list_t zlist, old; pool_t p; zebra_item_t zitem, scan; sess_t sscan; jid_t jidt; pkt_t result; os_t os; os_object_t o; st_ret_t ret; /* we only want to play with iq:privacy and urn:xmpp:blocking packets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || (pkt->ns != ns_PRIVACY && pkt->ns != ns_BLOCKING)) return mod_PASS; /* if it has a to, throw it out */ if(pkt->to != NULL) return -stanza_err_BAD_REQUEST; /* get our lists */ z = (zebra_t) sess->user->module_data[mod->index]; /* create session privacy description */ if(sess->module_data[mod->index] == NULL) sess->module_data[mod->index] = (void *) pmalloco(sess->p, sizeof(struct privacy_st)); /* handle XEP-0191: Simple Communications Blocking * as simplified frontend to default privacy list */ if(pkt->ns == ns_BLOCKING) { if(pkt->type == pkt_IQ_SET) { /* find out what to do */ int block; ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL); blocking = nad_find_elem(pkt->nad, 1, ns, "block", 1); if(blocking >= 0) block = 1; else { blocking = nad_find_elem(pkt->nad, 1, ns, "unblock", 1); if(blocking >= 0) block = 0; else return -stanza_err_BAD_REQUEST; } /* if there is no default list, create one */ if(!z->def) { /* remove any previous one */ if((zlist = xhash_get(z->lists, urn_BLOCKING))) { pool_free(zlist->p); sprintf(filter, "(list=%zu:%s)", strlen(urn_BLOCKING), urn_BLOCKING); storage_delete(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter); } /* create new zebra list with name 'urn:xmpp:blocking' */ p = pool_new(); zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st)); zlist->p = p; zlist->name = pstrdup(p, urn_BLOCKING); xhash_put(z->lists, zlist->name, (void *) zlist); /* make it default */ z->def = zlist; /* and in the storage */ os = os_new(); o = os_object_new(os); os_object_put(o, "default", zlist->name, os_type_STRING); ret = storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os); os_free(os); if(ret != st_SUCCESS) return -stanza_err_INTERNAL_SERVER_ERROR; log_debug(ZONE, "blocking created '%s' privacy list and set it default", zlist->name); } else { /* use the default one */ zlist = z->def; } /* activate this list */ ((privacy_t) sess->module_data[mod->index])->active = zlist; log_debug(ZONE, "session '%s' has now active list '%s'", jid_full(sess->jid), zlist->name); item = nad_find_elem(pkt->nad, blocking, ns, "item", 1); if(item < 0) { if(block) { /* cannot block unknown */ return -stanza_err_BAD_REQUEST; } else { /* unblock all */ _unblock_jid(sess->user, mod->mm->sm->st, zlist, NULL); /* mark to send blocklist push */ push = 1; } } /* loop over the items */ while(item >= 0) { /* extract jid */ jid = nad_find_attr(pkt->nad, item, -1, "jid", 0); if(jid < 0) return -stanza_err_BAD_REQUEST; jidt = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid)); if(jidt == NULL) return -stanza_err_BAD_REQUEST; /* find blockitem in the list */ for(scan = zlist->items; scan != NULL; scan = scan->next) if(scan->type == zebra_JID && jid_compare_full(scan->jid, jidt) == 0) break; /* take action */ if(block) { if(scan != NULL && scan->deny && scan->block == block_NONE) { push = 0; } else { /* first make us unavailable if user is on roster */ if(pres_trust(sess->user, jidt)) for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* do not update if session is not available, * we sent presence direct or got error bounce */ if(!sscan->available || jid_search(sscan->A, jidt) || jid_search(sscan->E, jidt)) continue; log_debug(ZONE, "forcing unavailable to %s from %s after block", jid_full(jidt), jid_full(sscan->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unavailable", jid_full(jidt), jid_full(sscan->jid))); } /* new item */ zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st)); zitem->type = zebra_JID; zitem->jid = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid)); pool_cleanup(zlist->p, (void *) jid_free, zitem->jid); zitem->deny = 1; zitem->block = block_NONE; /* insert it in front of list */ zitem->order = 0; if(zlist->last == NULL) { zlist->items = zlist->last = zitem; } else { zitem->next = zlist->items; zlist->items->prev = zitem; zlist->items = zitem; } /* and into the storage backend */ os = os_new(); o = os_object_new(os); os_object_put(o, "list", zlist->name, os_type_STRING); os_object_put(o, "type", "jid", os_type_STRING); os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING); os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN); os_object_put(o, "order", &zitem->order, os_type_INTEGER); os_object_put(o, "block", &zitem->block, os_type_INTEGER); ret = storage_put(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), os); os_free(os); if(ret != st_SUCCESS) { jid_free(jidt); return -stanza_err_INTERNAL_SERVER_ERROR; } /* mark to send blocklist push */ push = 1; } } else { /* unblock action */ if(scan != NULL && scan->deny) { /* remove all jid deny ocurrences from the privacy list */ _unblock_jid(sess->user, mod->mm->sm->st, zlist, jidt); /* mark to send blocklist push */ push = 1; } else { jid_free(jidt); return -stanza_err_ITEM_NOT_FOUND; } } jid_free(jidt); /* next item */ item = nad_find_elem(pkt->nad, item, ns, "item", 0); } /* return empty result */ result = pkt_create(pkt->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); pkt_sess(result, sess); /* blocklist push */ if(push) { for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* don't push to us or to anyone who hasn't requested blocklist */ if(sscan == sess || sscan->module_data[mod->index] == NULL || ((privacy_t) sscan->module_data[mod->index])->blocklist == 0) continue; result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } /* and done with request */ pkt_free(pkt); return mod_HANDLED; } /* it's a get */ ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL); blocking = nad_find_elem(pkt->nad, 1, ns, "blocklist", 1); if(blocking < 0) return -stanza_err_BAD_REQUEST; result = pkt_create(pkt->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); ns = nad_add_namespace(result->nad, urn_BLOCKING, NULL); blocking = nad_insert_elem(result->nad, 1, ns, "blocklist", NULL); /* insert items only from the default list */ if(z->def != NULL) { log_debug(ZONE, "blocking list is '%s'", z->def->name); zlist = xhash_get(z->lists, z->def->name); /* run through the items and build the nad */ for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) { /* we're interested in items type 'jid' with action 'deny' only */ if(zitem->type == zebra_JID && zitem->deny) { item = nad_insert_elem(result->nad, blocking, -1, "item", NULL); nad_set_attr(result->nad, item, -1, "jid", jid_full(zitem->jid), 0); } } /* mark that the blocklist was requested */ ((privacy_t) sess->module_data[mod->index])->blocklist = 1; } /* give it to the session */ pkt_sess(result, sess); pkt_free(pkt); return mod_HANDLED; } /* else handle XEP-0016: Privacy Lists */ /* find the query */ ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL); query = nad_find_elem(pkt->nad, 1, ns, "query", 1); if(query < 0) return -stanza_err_BAD_REQUEST; /* update lists or set the active list */ if(pkt->type == pkt_IQ_SET) { /* find out what we're doing */ list = nad_find_elem(pkt->nad, query, ns, "list", 1); active = nad_find_elem(pkt->nad, query, ns, "active", 1); def = nad_find_elem(pkt->nad, query, ns, "default", 1); /* we need something to do, but we can't do it all at once */ if((list < 0 && active < 0 && def < 0) || (list >= 0 && (active >=0 || def >= 0))) return -stanza_err_BAD_REQUEST; /* loop over any/all lists and store them */ if(list >= 0) { /* only allowed to change one list at a time */ if(nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0) return -stanza_err_BAD_REQUEST; /* get the list name */ name = nad_find_attr(pkt->nad, list, -1, "name", NULL); if(name < 0) { log_debug(ZONE, "no list name specified, failing request"); return -stanza_err_BAD_REQUEST; } snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name)); str[255] = '\0'; log_debug(ZONE, "updating list %s", str); /* make a new one */ p = pool_new(); zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st)); zlist->p = p; zlist->name = pstrdup(p, str); os = os_new(); /* loop over the items */ item = nad_find_elem(pkt->nad, list, ns, "item", 1); while(item >= 0) { /* extract things */ type = nad_find_attr(pkt->nad, item, -1, "type", 0); value = nad_find_attr(pkt->nad, item, -1, "value", 0); action = nad_find_attr(pkt->nad, item, -1, "action", 0); order = nad_find_attr(pkt->nad, item, -1, "order", 0); /* sanity */ if(action < 0 || order < 0 || (type >= 0 && value < 0)) { pool_free(p); os_free(os); return -stanza_err_BAD_REQUEST; } /* new item */ zitem = (zebra_item_t) pmalloco(p, sizeof(struct zebra_item_st)); /* have to store it too */ o = os_object_new(os); os_object_put(o, "list", zlist->name, os_type_STRING); /* type & value */ if(type >= 0) { if(NAD_AVAL_L(pkt->nad, type) == 3 && strncmp("jid", NAD_AVAL(pkt->nad, type), 3) == 0) { zitem->type = zebra_JID; zitem->jid = jid_new(NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value)); if(zitem->jid == NULL) { log_debug(ZONE, "invalid jid '%.*s', failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value)); pool_free(p); os_free(os); return -stanza_err_BAD_REQUEST; } pool_cleanup(p, (void *) jid_free, zitem->jid); log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid)); os_object_put(o, "type", "jid", os_type_STRING); os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING); } else if(NAD_AVAL_L(pkt->nad, type) == 5 && strncmp("group", NAD_AVAL(pkt->nad, type), 5) == 0) { zitem->type = zebra_GROUP; zitem->group = pstrdupx(zlist->p, NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value)); /* !!! check if the group exists */ log_debug(ZONE, "group item with value '%s'", zitem->group); os_object_put(o, "type", "group", os_type_STRING); os_object_put(o, "value", zitem->group, os_type_STRING); } else if(NAD_AVAL_L(pkt->nad, type) == 12 && strncmp("subscription", NAD_AVAL(pkt->nad, type), 12) == 0) { zitem->type = zebra_S10N; os_object_put(o, "type", "subscription", os_type_STRING); if(NAD_AVAL_L(pkt->nad, value) == 2 && strncmp("to", NAD_AVAL(pkt->nad, value), 2) == 0) { zitem->to = 1; os_object_put(o, "value", "to", os_type_STRING); } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("from", NAD_AVAL(pkt->nad, value), 4) == 0) { zitem->from = 1; os_object_put(o, "value", "from", os_type_STRING); } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("both", NAD_AVAL(pkt->nad, value), 4) == 0) { zitem->to = zitem->from = 1; os_object_put(o, "value", "both", os_type_STRING); } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("none", NAD_AVAL(pkt->nad, value), 4) == 0) os_object_put(o, "value", "none", os_type_STRING); else { log_debug(ZONE, "invalid value '%.*s' on s10n item, failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value)); pool_free(p); os_free(os); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "s10n item with value '%.*s' (to %d from %d)", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value), zitem->to, zitem->from); } } /* action */ if(NAD_AVAL_L(pkt->nad, action) == 4 && strncmp("deny", NAD_AVAL(pkt->nad, action), 4) == 0) { zitem->deny = 1; log_debug(ZONE, "deny rule"); } else if(NAD_AVAL_L(pkt->nad, action) == 5 && strncmp("allow", NAD_AVAL(pkt->nad, action), 5) == 0) { zitem->deny = 0; log_debug(ZONE, "allow rule"); } else { log_debug(ZONE, "unknown action '%.*s', failing request", NAD_AVAL_L(pkt->nad, action), NAD_AVAL(pkt->nad, action)); pool_free(p); os_free(os); return -stanza_err_BAD_REQUEST; } os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN); /* order */ snprintf(corder, 14, "%.*s", NAD_AVAL_L(pkt->nad, order), NAD_AVAL(pkt->nad, order)); corder[13] = '\0'; zitem->order = atoi(corder); os_object_put(o, "order", &zitem->order, os_type_INTEGER); /* block types */ if(nad_find_elem(pkt->nad, item, ns, "message", 1) >= 0) zitem->block |= block_MESSAGE; if(nad_find_elem(pkt->nad, item, ns, "presence-in", 1) >= 0) zitem->block |= block_PRES_IN; if(nad_find_elem(pkt->nad, item, ns, "presence-out", 1) >= 0) zitem->block |= block_PRES_OUT; if(nad_find_elem(pkt->nad, item, ns, "iq", 1) >= 0) zitem->block |= block_IQ; /* merge block all */ if(zitem->block & block_MESSAGE && zitem->block & block_PRES_IN && zitem->block & block_PRES_OUT && zitem->block & block_IQ) zitem->block = block_NONE; os_object_put(o, "block", &zitem->block, os_type_INTEGER); /* insert it */ for(scan = zlist->items; scan != NULL; scan = scan->next) if(zitem->order < scan->order) break; /* we're >= everyone, add us to the end */ if(scan == NULL) { if(zlist->last == NULL) zlist->items = zlist->last = zitem; else { zlist->last->next = zitem; zitem->prev = zlist->last; zlist->last = zitem; } } /* insert just before scan */ else { if(zlist->items == scan) { zitem->next = zlist->items; zlist->items = zitem; scan->prev = zitem; } else { zitem->next = scan; zitem->prev = scan->prev; scan->prev->next = zitem; scan->prev = zitem; } } /* next item */ item = nad_find_elem(pkt->nad, item, ns, "item", 0); } /* write the whole list out */ sprintf(filter, "(list=%zu:%s)", strlen(zlist->name), zlist->name); ret = storage_replace(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter, os); os_free(os); /* failed! */ if(ret != st_SUCCESS) { pool_free(zlist->p); return -stanza_err_INTERNAL_SERVER_ERROR; } /* old list pointer */ old = xhash_get(z->lists, zlist->name); /* removed list */ if(zlist->items == NULL) { log_debug(ZONE, "removed list %s", zlist->name); xhash_zap(z->lists, zlist->name); pool_free(zlist->p); if(old != NULL) pool_free(old->p); zlist = NULL; } else { log_debug(ZONE, "updated list %s", zlist->name); xhash_put(z->lists, zlist->name, (void *) zlist); if(old != NULL) pool_free(old->p); } /* if this was a new list, then noone has it active yet */ if(old != NULL) { /* relink */ log_debug(ZONE, "relinking sessions"); /* loop through sessions, relink */ for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) if(sscan->module_data[mod->index] != NULL && ((privacy_t) sscan->module_data[mod->index])->active == old) { ((privacy_t) sscan->module_data[mod->index])->active = zlist; log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sscan->jid), (zlist != NULL) ? zlist->name : "(NONE)"); } /* default list */ if(z->def == old) { z->def = zlist; if(zlist == NULL) { storage_delete(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL); log_debug(ZONE, "removed default list"); } else { os = os_new(); o = os_object_new(os); os_object_put(o, "default", zlist->name, os_type_STRING); storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os); os_free(os); log_debug(ZONE, "default list is now '%s'", (zlist != NULL) ? zlist->name : "(NONE)"); } } } } /* set the active list */ if(active >= 0) { name = nad_find_attr(pkt->nad, active, -1, "name", NULL); if(name < 0) { /* no name, no active list */ log_debug(ZONE, "clearing active list for session '%s'", jid_full(sess->jid)); ((privacy_t) sess->module_data[mod->index])->active = NULL; } else { snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name)); str[255] = '\0'; zlist = xhash_get(z->lists, str); if(zlist == NULL) { log_debug(ZONE, "request to make list '%s' active, but there's no such list", str); return -stanza_err_ITEM_NOT_FOUND; } ((privacy_t) sess->module_data[mod->index])->active = zlist; log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sess->jid), str); } } /* set the default list */ if(def >= 0) { name = nad_find_attr(pkt->nad, def, -1, "name", NULL); if(name < 0) { /* no name, no default list */ log_debug(ZONE, "clearing default list for '%s'", jid_user(sess->user->jid)); z->def = NULL; } else { snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name)); str[255] = '\0'; zlist = xhash_get(z->lists, str); if(zlist == NULL) { log_debug(ZONE, "request to make list '%s' default, but there's no such list"); return -stanza_err_ITEM_NOT_FOUND; } z->def = zlist; os = os_new(); o = os_object_new(os); os_object_put(o, "default", zlist->name, os_type_STRING); storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os); os_free(os); log_debug(ZONE, "'%s' now has default list '%s'", jid_user(sess->user->jid), str); } } /* done, let them know */ result = pkt_create(pkt->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* done with this */ pkt_free(pkt); /* give it to the session */ pkt_sess(result, sess); /* all done */ return mod_HANDLED; } /* its a get */ /* only allowed to request one list, if any */ list = nad_find_elem(pkt->nad, query, ns, "list", 1); if(list >= 0 && nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0) return -stanza_err_BAD_REQUEST; result = pkt_create(pkt->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); ns = nad_add_namespace(result->nad, uri_PRIVACY, NULL); query = nad_insert_elem(result->nad, 1, ns, "query", NULL); /* just do one */ if(list >= 0) { name = nad_find_attr(pkt->nad, list, -1, "name", NULL); zlist = xhash_getx(z->lists, NAD_AVAL(pkt->nad, name), NAD_AVAL_L(pkt->nad, name)); if(zlist == NULL) return -stanza_err_ITEM_NOT_FOUND; _privacy_result_builder(z->lists, zlist->name, (void *) zlist, (void *) result); } else { /* walk the list hash and add the lists in */ xhash_walk(z->lists, _privacy_lists_result_builder, (void *) result); } /* tell them about current active and default list if they asked for everything */ if(list < 0) { /* active */ if(((privacy_t) sess->module_data[mod->index])->active != NULL) { active = nad_insert_elem(result->nad, query, ns, "active", NULL); nad_set_attr(result->nad, active, -1, "name", ((privacy_t) sess->module_data[mod->index])->active->name, 0); } /* and the default list */ if(z->def != NULL) { def = nad_insert_elem(result->nad, query, ns, "default", NULL); nad_set_attr(result->nad, def, -1, "name", z->def->name, 0); } } /* give it to the session */ pkt_sess(result, sess); /* done with this */ pkt_free(pkt); /* all done */ return mod_HANDLED; } static void _privacy_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting privacy data for %s", jid_user(jid)); storage_delete(mi->sm->st, "privacy-items", jid_user(jid), NULL); storage_delete(mi->sm->st, "privacy-default", jid_user(jid), NULL); } static void _privacy_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_PRIVACY); feature_unregister(mod->mm->sm, uri_PRIVACY); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if (mod->init) return 0; mod->user_load = _privacy_user_load; mod->in_router = _privacy_in_router; mod->out_router = _privacy_out_router; mod->in_sess = _privacy_in_sess; mod->user_delete = _privacy_user_delete; mod->free = _privacy_free; ns_PRIVACY = sm_register_ns(mod->mm->sm, uri_PRIVACY); feature_register(mod->mm->sm, uri_PRIVACY); ns_BLOCKING = sm_register_ns(mod->mm->sm, urn_BLOCKING); feature_register(mod->mm->sm, urn_BLOCKING); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_roster.c��������������������������������������������������������������0000664�0000000�0000000�00000063064�12614627753�0017550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_roster.c * @brief roster managment & subscriptions * @author Robert Norris * $Date: 2005/09/09 05:34:13 $ * $Revision: 1.61 $ */ typedef struct _mod_roster_st { int maxitems; } *mod_roster_t; typedef struct _roster_walker_st { pkt_t pkt; int req_ver; int ver; sess_t sess; } *roster_walker_t; /** free a single roster item */ static void _roster_freeuser_walker(const char *key, int keylen, void *val, void *arg) { item_t item = (item_t) val; int i; jid_free(item->jid); if(item->name != NULL) free((void*)item->name); for(i = 0; i < item->ngroups; i++) free((void*)item->groups[i]); free(item->groups); free(item); } /** free the roster */ static void _roster_freeuser(user_t user) { if(user->roster == NULL) return; log_debug(ZONE, "freeing roster for %s", jid_user(user->jid)); xhash_walk(user->roster, _roster_freeuser_walker, NULL); xhash_free(user->roster); user->roster = NULL; } static void _roster_save_item(user_t user, item_t item) { os_t os; os_object_t o; char filter[4096]; int i; log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid)); os = os_new(); o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); if(item->name != NULL) os_object_put(o, "name", item->name, os_type_STRING); os_object_put(o, "to", &item->to, os_type_BOOLEAN); os_object_put(o, "from", &item->from, os_type_BOOLEAN); os_object_put(o, "ask", &item->ask, os_type_INTEGER); snprintf(filter, 4096, "(jid=%zu:%s)", strlen(jid_full(item->jid)), jid_full(item->jid)); storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os); os_free(os); if(item->ngroups == 0) { storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter); return; } os = os_new(); for(i = 0; i < item->ngroups; i++) { o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); os_object_put(o, "group", item->groups[i], os_type_STRING); } storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os); os_free(os); } /** insert a roster item into this pkt, starting at elem */ static void _roster_insert_item(pkt_t pkt, item_t item, int elem) { int ns, i; char *sub; ns = nad_add_namespace(pkt->nad, uri_CLIENT, NULL); elem = nad_insert_elem(pkt->nad, elem, ns, "item", NULL); nad_set_attr(pkt->nad, elem, -1, "jid", jid_full(item->jid), 0); if(item->to && item->from) sub = "both"; else if(item->to) sub = "to"; else if(item->from) sub = "from"; else sub = "none"; nad_set_attr(pkt->nad, elem, -1, "subscription", sub, 0); if(item->ask == 1) nad_set_attr(pkt->nad, elem, -1, "ask", "subscribe", 9); else if(item->ask == 2) /* XXX there is no ask='unsubscribe' in RFC bis anymore */ nad_set_attr(pkt->nad, elem, -1, "ask", "unsubscribe", 11); if(item->name != NULL) nad_set_attr(pkt->nad, elem, -1, "name", item->name, 0); for(i = 0; i < item->ngroups; i++) nad_insert_elem(pkt->nad, elem, NAD_ENS(pkt->nad, elem), "group", item->groups[i]); } /** push this packet to all sessions except the given one */ static int _roster_push(user_t user, pkt_t pkt, int mod_index) { sess_t scan; pkt_t push; int pushes = 0; /* do the push */ for(scan = user->sessions; scan != NULL; scan = scan->next) { /* don't push to us or to anyone who hasn't loaded the roster */ if(scan->module_data[mod_index] == NULL) continue; push = pkt_dup(pkt, jid_full(scan->jid), NULL); pkt_sess(push, scan); pushes++; } /* return the pushed packets count */ return pushes; } static mod_ret_t _roster_in_sess_s10n(mod_instance_t mi, sess_t sess, pkt_t pkt) { mod_roster_t mroster = (mod_roster_t) mi->mod->private; module_t mod = mi->mod; item_t item; pkt_t push; int ns, elem, ret, items = -1; log_debug(ZONE, "got s10n packet"); /* s10ns have to go to someone */ if(pkt->to == NULL) return -stanza_err_BAD_REQUEST; /* add a proper from address (no resource) */ if(pkt->from != NULL) jid_free(pkt->from); pkt->from = jid_new(jid_user(sess->jid), -1); nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); /* see if they're already on the roster */ item = xhash_get(sess->user->roster, jid_full(pkt->to)); if(item == NULL) { /* if they're not on the roster, there's no subscription, * so quietly pass it on */ if(pkt->type == pkt_S10N_UN || pkt->type == pkt_S10N_UNED) return mod_PASS; /* check if user exceedes maximum roster items */ if(mroster->maxitems > 0) { ret = storage_count(sess->user->sm->st, "roster-items", jid_user(sess->user->jid), NULL, &items); log_debug(ZONE, "user has %i roster-items, maximum is %i", items, mroster->maxitems); /* if the limit is reached, return an error */ if (ret == st_SUCCESS && items >= mroster->maxitems) return -stanza_err_NOT_ACCEPTABLE; } /* make a new one */ item = (item_t) calloc(1, sizeof(struct item_st)); item->jid = jid_dup(pkt->to); /* remember it */ xhash_put(sess->user->roster, jid_full(item->jid), (void *) item); log_debug(ZONE, "made new empty roster item for %s", jid_full(item->jid)); } /* a request */ if(pkt->type == pkt_S10N && ! item->to) item->ask = 1; else if(pkt->type == pkt_S10N_UN && item->to) item->ask = 2; /* changing states */ else if(pkt->type == pkt_S10N_ED) { /* they're allowed to see us, send them presence */ item->from = 1; pres_roster(sess, item); } else if(pkt->type == pkt_S10N_UNED) { /* they're not allowed to see us anymore */ item->from = 0; pres_roster(sess, item); } if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->user->jid))) return -stanza_err_RESOURCE_CONSTRAINT; /* save changes */ _roster_save_item(sess->user, item); /* build a new packet to push out to everyone */ push = pkt_create(sess->user->sm, "iq", "set", NULL, NULL); pkt_id_new(push); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); elem = nad_append_elem(push->nad, ns, "query", 3); _roster_insert_item(push, item, elem); /* tell everyone */ _roster_push(sess->user, push, mod->index); /* everyone knows */ pkt_free(push); /* pass it on */ return mod_PASS; } /** build the iq:roster packet from the hash */ static void _roster_get_walker(const char *id, int idlen, void *val, void *arg) { item_t item = (item_t) val; roster_walker_t rw = (roster_walker_t) arg; _roster_insert_item(rw->pkt, item, 2); /* remember largest item version */ if(item->ver > rw->ver) rw->ver = item->ver; } /** push roster XEP-0237 updates to client */ static void _roster_update_walker(const char *id, int idlen, void *val, void *arg) { pkt_t push; char *buf; int elem, ns; item_t item = (item_t) val; roster_walker_t rw = (roster_walker_t) arg; /* skip unneded roster items */ if(item->ver <= rw->req_ver) return; /* build a interim roster push packet */ push = pkt_create(rw->sess->user->sm, "iq", "set", NULL, NULL); pkt_id_new(push); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); elem = nad_append_elem(push->nad, ns, "query", 3); buf = (char *) malloc(sizeof(char) * 128); sprintf(buf, "%d", item->ver); nad_set_attr(push->nad, elem, -1, "ver", buf, 0); free(buf); _roster_insert_item(push, item, elem); pkt_sess(push, rw->sess); } static void _roster_set_item(pkt_t pkt, int elem, sess_t sess, mod_instance_t mi) { mod_roster_t mroster = (mod_roster_t) mi->mod->private; module_t mod = mi->mod; int attr, ns, i, ret, items = -1; jid_t jid; item_t item; pkt_t push; char filter[4096]; /* extract the jid */ attr = nad_find_attr(pkt->nad, elem, -1, "jid", NULL); jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL) { log_debug(ZONE, "jid failed prep check, skipping"); return; } /* check for removals */ if(nad_find_attr(pkt->nad, elem, -1, "subscription", "remove") >= 0) { /* trash the item */ item = xhash_get(sess->user->roster, jid_full(jid)); if(item != NULL) { /* tell them they're unsubscribed */ if(item->from) { log_debug(ZONE, "telling %s that they're unsubscribed", jid_user(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unsubscribed", jid_user(item->jid), jid_user(sess->jid))); } item->from = 0; /* tell them to unsubscribe us */ if(item->to) { log_debug(ZONE, "unsubscribing from %s", jid_user(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unsubscribe", jid_user(item->jid), jid_user(sess->jid))); } item->to = 0; /* send unavailable */ pres_roster(sess, item); /* kill it */ xhash_zap(sess->user->roster, jid_full(jid)); _roster_freeuser_walker((const char *) jid_full(jid), strlen(jid_full(jid)), (void *) item, NULL); snprintf(filter, 4096, "(jid=%zu:%s)", strlen(jid_full(jid)), jid_full(jid)); storage_delete(sess->user->sm->st, "roster-items", jid_user(sess->jid), filter); storage_delete(sess->user->sm->st, "roster-groups", jid_user(sess->jid), filter); } log_debug(ZONE, "removed %s from roster", jid_full(jid)); /* build a new packet to push out to everyone */ push = pkt_create(sess->user->sm, "iq", "set", NULL, NULL); pkt_id_new(push); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); nad_append_elem(push->nad, ns, "query", 3); elem = nad_append_elem(push->nad, ns, "item", 4); nad_set_attr(push->nad, elem, -1, "jid", jid_full(jid), 0); nad_set_attr(push->nad, elem, -1, "subscription", "remove", 6); /* tell everyone */ _roster_push(sess->user, push, mod->index); /* we're done */ pkt_free(push); jid_free(jid); return; } /* find a pre-existing one */ item = xhash_get(sess->user->roster, jid_full(jid)); if(item == NULL) { /* check if user exceedes maximum roster items */ if(mroster->maxitems > 0) { ret = storage_count(sess->user->sm->st, "roster-items", jid_user(sess->user->jid), NULL, &items); log_debug(ZONE, "user has %i roster-items, maximum is %i", items, mroster->maxitems); /* if the limit is reached, skip it */ if (ret == st_SUCCESS && items >= mroster->maxitems) return; } /* make a new one */ item = (item_t) calloc(1, sizeof(struct item_st)); /* add the jid */ item->jid = jid; /* add it to the roster */ xhash_put(sess->user->roster, jid_full(item->jid), (void *) item); log_debug(ZONE, "created new roster item %s", jid_full(item->jid)); } else jid_free(jid); /* extract the name */ attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL); if(attr >= 0) { /* free the old name */ if(item->name != NULL) { free((void*)item->name); item->name = NULL; } if (NAD_AVAL_L(pkt->nad, attr) > 0) { item->name = (const char *) malloc(sizeof(char) * (NAD_AVAL_L(pkt->nad, attr) + 1)); sprintf((char *)item->name, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); } } /* free the old groups */ if(item->groups != NULL) { for(i = 0; i < item->ngroups; i++) free((void*)item->groups[i]); free(item->groups); item->ngroups = 0; item->groups = NULL; } /* loop over the groups, adding them to the array */ elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, elem), "group", 1); while(elem >= 0) { /* empty group tags get skipped */ if(NAD_CDATA_L(pkt->nad, elem) >= 0) { /* make room and shove it in */ item->groups = (const char **) realloc(item->groups, sizeof(char *) * (item->ngroups + 1)); item->groups[item->ngroups] = (const char *) malloc(sizeof(char) * (NAD_CDATA_L(pkt->nad, elem) + 1)); sprintf((char *)(item->groups[item->ngroups]), "%.*s", NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem)); item->ngroups++; } elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, elem), "group", 0); } log_debug(ZONE, "added %s to roster (to %d from %d ask %d name %s ngroups %d)", jid_full(item->jid), item->to, item->from, item->ask, item->name, item->ngroups); if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->user->jid))) return; /* save changes */ _roster_save_item(sess->user, item); /* build a new packet to push out to everyone */ push = pkt_create(sess->user->sm, "iq", "set", NULL, NULL); pkt_id_new(push); ns = nad_add_namespace(push->nad, uri_ROSTER, NULL); elem = nad_append_elem(push->nad, ns, "query", 3); _roster_insert_item(push, item, elem); /* tell everyone */ _roster_push(sess->user, push, mod->index); /* we're done */ pkt_free(push); } /** our main handler for packets arriving from a session */ static mod_ret_t _roster_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int elem, attr, ver = 0; pkt_t result; char *buf; roster_walker_t rw; /* handle s10ns in a different function */ if(pkt->type & pkt_S10N) return _roster_in_sess_s10n(mi, sess, pkt); /* we only want to play with iq:roster packets */ if(pkt->ns != ns_ROSTER) return mod_PASS; /* quietly drop results, its probably them responding to a push */ if(pkt->type == pkt_IQ_RESULT) { pkt_free(pkt); return mod_HANDLED; } /* need gets or sets */ if(pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) return mod_PASS; /* get */ if(pkt->type == pkt_IQ) { /* check for "XEP-0237: Roster Versioning request" */ if((elem = nad_find_elem(pkt->nad, 1, -1, "query", 1)) >= 0 &&(attr = nad_find_attr(pkt->nad, elem, -1, "ver", NULL)) >= 0) { if (NAD_AVAL_L(pkt->nad, attr) > 0) { buf = (char *) malloc(sizeof(char) * (NAD_AVAL_L(pkt->nad, attr) + 1)); sprintf(buf, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); ver = j_atoi(buf, 0); free(buf); } } /* build the packet */ rw = (roster_walker_t) calloc(1, sizeof(struct _roster_walker_st)); rw->pkt = pkt; rw->req_ver = ver; rw->sess = sess; nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); if(ver > 0) { /* send XEP-0237 empty result */ nad_drop_elem(pkt->nad, elem); pkt_sess(pkt_tofrom(pkt), sess); xhash_walk(sess->user->roster, _roster_update_walker, (void *) rw); } else { xhash_walk(sess->user->roster, _roster_get_walker, (void *) rw); if(elem >= 0 && attr >= 0) { buf = (char *) malloc(sizeof(char) * 128); sprintf(buf, "%d", rw->ver); nad_set_attr(pkt->nad, elem, -1, "ver", buf, 0); free(buf); } pkt_sess(pkt_tofrom(pkt), sess); } free(rw); /* remember that they loaded it, so we know to push updates to them */ sess->module_data[mod->index] = (void *) 1; return mod_HANDLED; } /* set, find the item */ elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), "item", 1); if(elem < 0) /* no item, abort */ return -stanza_err_BAD_REQUEST; /* loop over items and stick them in */ while(elem >= 0) { /* extract the jid */ attr = nad_find_attr(pkt->nad, elem, -1, "jid", NULL); if(attr < 0 || NAD_AVAL_L(pkt->nad, attr) == 0) { log_debug(ZONE, "no jid on this item, aborting"); /* no jid, abort */ return -stanza_err_BAD_REQUEST; } /* utility */ _roster_set_item(pkt, elem, sess, mi); /* next one */ elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, elem), "item", 0); } /* send the result */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* tell them */ pkt_sess(result, sess); /* free the request */ pkt_free(pkt); return mod_HANDLED; } /** handle incoming s10ns */ static mod_ret_t _roster_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { module_t mod = mi->mod; item_t item; int ns, elem; /* only want s10ns */ if(!(pkt->type & pkt_S10N)) return mod_PASS; /* drop route errors */ if(pkt->rtype & route_ERROR) { pkt_free(pkt); return mod_HANDLED; } /* get the roster item */ item = (item_t) xhash_get(user->roster, jid_full(pkt->from)); if(item == NULL) { /* subs are handled by the client */ if(pkt->type == pkt_S10N) { /* if the user is online broadcast it like roster push */ if(user->top != NULL && _roster_push(user, pkt, mod->index) > 0) { /* pushed, thus handled */ pkt_free(pkt); return mod_HANDLED; } else { /* not pushed to any online resource - pass it on (to mod_offline) */ return mod_PASS; } } /* other S10Ns: we didn't ask for this, so we don't care */ pkt_free(pkt); return mod_HANDLED; } /* ignore bogus answers */ if( (pkt->type == pkt_S10N_ED && (item->ask != 1 || item->to) ) || (pkt->type == pkt_S10N_UNED && ! item->to) ) { /* remove pending ask */ if( (pkt->type == pkt_S10N_ED && item->ask == 1) || (pkt->type == pkt_S10N_UNED && item->ask == 2) ) { item->ask = 0; /* save changes */ _roster_save_item(user, item); } pkt_free(pkt); return mod_HANDLED; } /* trying to subscribe */ if(pkt->type == pkt_S10N) { if(item->from) { /* already subscribed, tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "subscribed", 10); pkt_router(pkt_tofrom(pkt)); /* update their presence from the leading session */ if(user->top != NULL) pres_roster(user->top, item); return mod_HANDLED; } return mod_PASS; } /* handle unsubscribe */ if(pkt->type == pkt_S10N_UN) { if(!item->from) { /* already unsubscribed, tell them */ nad_set_attr(pkt->nad, 1, -1, "type", "unsubscribed", 12); pkt_router(pkt_tofrom(pkt)); return mod_HANDLED; } /* change state */ item->from = 0; /* confirm unsubscription */ pkt_router(pkt_create(user->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(user->jid))); /* update their presence from the leading session */ if(user->top != NULL) pres_roster(user->top, item); } /* update our s10n */ if(pkt->type == pkt_S10N_ED) { item->to = 1; if(item->ask == 1) item->ask = 0; } if(pkt->type == pkt_S10N_UNED) { item->to = 0; if(item->ask == 2) item->ask = 0; } if (sm_storage_rate_limit(user->sm, jid_user(pkt->from))) return -stanza_err_RESOURCE_CONSTRAINT; /* save changes */ _roster_save_item(user, item); /* if there's no sessions, then we're done */ if(user->sessions == NULL) return mod_PASS; /* build a new packet to push out to everyone */ pkt = pkt_create(user->sm, "iq", "set", NULL, NULL); pkt_id_new(pkt); ns = nad_add_namespace(pkt->nad, uri_ROSTER, NULL); elem = nad_append_elem(pkt->nad, ns, "query", 3); _roster_insert_item(pkt, item, elem); /* tell everyone */ _roster_push(user, pkt, mod->index); /* everyone knows */ pkt_free(pkt); return mod_PASS; } /** load the roster from the database */ static int _roster_user_load(mod_instance_t mi, user_t user) { os_t os; os_object_t o; char *str; item_t item, olditem; log_debug(ZONE, "loading roster for %s", jid_user(user->jid)); user->roster = xhash_new(101); /* pull all the items */ if(storage_get(user->sm->st, "roster-items", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_str(os, o, "jid", &str)) { /* new one */ item = (item_t) calloc(1, sizeof(struct item_st)); item->jid = jid_new(str, -1); if(item->jid == NULL) { log_debug(ZONE, "eek! invalid jid %s, skipping it", str); free(item); } else { if(os_object_get_str(os, o, "name", &str)) item->name = strdup(str); os_object_get_bool(os, o, "to", &item->to); os_object_get_bool(os, o, "from", &item->from); os_object_get_int(os, o, "ask", &item->ask); os_object_get_int(os, o, "object-sequence", &item->ver); olditem = xhash_get(user->roster, jid_full(item->jid)); if(olditem) { log_debug(ZONE, "removing old %s roster entry", jid_full(item->jid)); xhash_zap(user->roster, jid_full(item->jid)); _roster_freeuser_walker(jid_full(item->jid), strlen(jid_full(item->jid)), (void *) olditem, NULL); } /* its good */ xhash_put(user->roster, jid_full(item->jid), (void *) item); log_debug(ZONE, "added %s to roster (to %d from %d ask %d ver %d name %s)", jid_full(item->jid), item->to, item->from, item->ask, item->ver, item->name); } } } while(os_iter_next(os)); os_free(os); } /* pull the groups and match them up */ if(storage_get(user->sm->st, "roster-groups", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_str(os, o, "jid", &str)) { item = xhash_get(user->roster, str); if(item != NULL && os_object_get_str(os, o, "group", &str)) { item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1)); item->groups[item->ngroups] = strdup(str); item->ngroups++; log_debug(ZONE, "added group %s to item %s", str, jid_full(item->jid)); } } } while(os_iter_next(os)); os_free(os); } pool_cleanup(user->p, (void (*))(void *) _roster_freeuser, user); return 0; } static void _roster_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting roster data for %s", jid_user(jid)); storage_delete(mi->sm->st, "roster-items", jid_user(jid), NULL); storage_delete(mi->sm->st, "roster-groups", jid_user(jid), NULL); } static void _roster_free(module_t mod) { mod_roster_t mroster = (mod_roster_t) mod->private; free(mroster); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; mod_roster_t mroster; if(mod->init) return 0; mroster = (mod_roster_t) calloc(1, sizeof(struct _mod_roster_st)); mroster->maxitems = j_atoi(config_get_one(mod->mm->sm->config, "roster.maxitems", 0), 0); mod->private = mroster; mod->in_sess = _roster_in_sess; mod->pkt_user = _roster_pkt_user; mod->user_load = _roster_user_load; mod->user_delete = _roster_user_delete; mod->free = _roster_free; feature_register(mod->mm->sm, uri_ROSTER); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_roster_publish.c������������������������������������������������������0000664�0000000�0000000�00000066652�12614627753�0021304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_roster_publish.c * @brief roster publishing * @author Nikita Smirnov */ #ifndef NO_SM_CACHE typedef struct _roster_publish_active_cache_st *_roster_publish_active_cache_t; struct _roster_publish_active_cache_st { time_t time; // when cache was updated time_t active; char *jid_user; }; typedef struct _roster_publish_group_cache_st *_roster_publish_group_cache_t; struct _roster_publish_group_cache_st { time_t time; // when cache was updated char *groupid; char *groupname; }; #endif typedef struct _roster_publish_st { int publish, forcegroups, fixsubs, overridenames, mappedgroups, fixexist; const char *fetchdomain, *fetchuser, *fetchfixed, *dbtable; const char *groupprefix, *groupsuffix, *removedomain; int groupprefixlen, groupsuffixlen; time_t active_cache_ttl; time_t group_cache_ttl; #ifndef NO_SM_CACHE xht active_cache; // cache of values from 'active' storage, // used to check that user exists in sm database xht group_cache; // cache of values from published-roster-groups storage // used to map group id to group name #endif } *roster_publish_t; #ifndef NO_SM_CACHE /* free single item of active cache */ static void _roster_publish_free_active_cache_walker(const char *key, int keylen, void *val, void *arg) { _roster_publish_active_cache_t item = (_roster_publish_active_cache_t)val; free(item->jid_user); free(item); } /* free single item of group cache */ static void _roster_publish_free_group_cache_walker(const char *key, int keylen, void *val, void *arg) { _roster_publish_group_cache_t item = (_roster_publish_group_cache_t)val; free(item->groupid); free(item->groupname); free(item); } #endif /* * get group's descriptive name by it's text id * returned value needs to be freed by caller */ static const char *_roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid) { os_t os; os_object_t o; char *str; char *group; #ifndef NO_SM_CACHE _roster_publish_group_cache_t group_cached; #endif if(!groupid) return groupid; #ifndef NO_SM_CACHE /* check for remembered group value in cache */ if( rp->group_cache_ttl ) { if( rp->group_cache ) { group_cached = xhash_get(rp->group_cache, groupid); if( group_cached != NULL ) { if( (time(NULL) - group_cached->time) >= rp->group_cache_ttl ) { log_debug(ZONE,"group cache: expiring cached value for %s",groupid); xhash_zap(rp->group_cache, groupid); free(group_cached); } else { log_debug(ZONE,"group cache: returning cached value for %s",groupid); return strdup(group_cached->groupname); } } } else { log_debug(ZONE,"group cache: creating cache"); rp->group_cache = xhash_new(401); } } #endif if(storage_get(sm->st, "published-roster-groups", groupid, NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); os_object_get_str(os, o, "groupname", &str); if( str ) { group=strdup(str); } else { group=NULL; } os_free(os); #ifndef NO_SM_CACHE if( rp->group_cache_ttl && group ) { log_debug(ZONE,"group cache: updating cache value for %s",groupid); group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st)); group_cached->time = time(NULL); group_cached->groupid = strdup(groupid); group_cached->groupname = strdup(group); xhash_put(rp->group_cache, group_cached->groupid, group_cached); } #endif return group; } else { return NULL; } } /* free a single roster item */ static void _roster_publish_free_walker(xht roster, const char *key, void *val, void *arg) { item_t item = (item_t) val; int i; jid_free(item->jid); if(item->name != NULL) free((void*)item->name); for(i = 0; i < item->ngroups; i++) free((void*)item->groups[i]); free(item->groups); free(item); } static void _roster_publish_save_item(user_t user, item_t item) { os_t os; os_object_t o; char filter[4096]; int i; log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid)); os = os_new(); o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); if(item->name != NULL) os_object_put(o, "name", item->name, os_type_STRING); os_object_put(o, "to", &item->to, os_type_BOOLEAN); os_object_put(o, "from", &item->from, os_type_BOOLEAN); os_object_put(o, "ask", &item->ask, os_type_INTEGER); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os); os_free(os); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); if(item->ngroups == 0) { storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter); return; } os = os_new(); for(i = 0; i < item->ngroups; i++) { o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); os_object_put(o, "group", item->groups[i], os_type_STRING); } storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os); os_free(os); } /** publish the roster from the database */ static int _roster_publish_user_load(mod_instance_t mi, user_t user) { roster_publish_t roster_publish = (roster_publish_t) mi->mod->private; os_t os, os_active; os_object_t o, o_active; char *str; const char *group; char filter[4096]; const char *fetchkey; int i,j,gpos,found,delete,checksm,tmp_to,tmp_from,tmp_do_change; item_t item; jid_t jid; /* update roster to match published roster */ if( roster_publish->publish) { /* free if necessary */ if(user->roster == NULL) { log_write(user->sm->log, LOG_NOTICE, "roster_publish: no roster for %s",jid_user(user->jid)); return 0; } log_debug(ZONE, "publishing roster for %s",jid_user(user->jid)); /* get published roster */ if(roster_publish->fetchfixed) fetchkey = roster_publish->fetchfixed; else if(roster_publish->fetchuser) fetchkey = jid_user(user->jid); else if(roster_publish->fetchdomain) fetchkey = user->jid->domain; else fetchkey = ""; if( storage_get(user->sm->st, (roster_publish->dbtable ? roster_publish->dbtable : "published-roster"), fetchkey, NULL, &os) == st_SUCCESS ) { if(os_iter_first(os)) { /* iterate on published roster */ jid = NULL; do { o = os_iter_object(os); if(os_object_get_str(os, o, "jid", &str)) { int userinsm; #ifndef NO_SM_CACHE _roster_publish_active_cache_t active_cached = 0; #endif log_debug(ZONE, "got %s item for inserting in", str); if( strcmp(str,jid_user(user->jid)) == 0 ) { /* not adding self */ continue; /* do { } while( os_iter_next ) */ } /* check that published item exists in sm database */ checksm=0; if( jid ) jid_free(jid); jid = jid_new(str, -1); if( roster_publish->removedomain ) { if( strcmp("1", roster_publish->removedomain) == 0 || /* XXX HACKY!!! "1" is very config.c dependant */ strcmp(jid->domain, roster_publish->removedomain) == 0 ) { checksm = 1; } } if( checksm ) { /* is this a hack? but i want to know was the user activated in sm or no? */ #ifndef NO_SM_CACHE /* check for remembered active value in cache */ userinsm = -1; if( roster_publish->active_cache_ttl ) { if( roster_publish->active_cache ) { active_cached = xhash_get(roster_publish->active_cache, jid_user(jid)); if( active_cached != NULL ) { if( (time(NULL) - active_cached->time) >= roster_publish->active_cache_ttl ) { xhash_zap(roster_publish->active_cache, jid_user(jid)); free(active_cached); } else { if( active_cached->active ) { userinsm = 1; } else { userinsm = 0; } } } } else { roster_publish->active_cache = xhash_new(401); } } if( userinsm == -1 ) { if( roster_publish->active_cache_ttl ) { active_cached = calloc(1, sizeof(struct _roster_publish_active_cache_st)); active_cached->time = time(NULL); } #endif if(storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS && os_iter_first(os_active)) { #ifndef NO_SM_CACHE if( roster_publish->active_cache_ttl ) { o_active = os_iter_object(os_active); os_object_get_time(os_active, o_active, "time", &active_cached->active); } #endif os_free(os_active); userinsm = 1; } else { #ifndef NO_SM_CACHE if( roster_publish->active_cache_ttl ) { active_cached->active = 0; } #endif userinsm = 0; } #ifndef NO_SM_CACHE if( roster_publish->active_cache_ttl ) { active_cached->jid_user = strdup(jid_user(jid)); xhash_put(roster_publish->active_cache, active_cached->jid_user, active_cached); } } // if( userinsm == -1 ) #endif } else userinsm = 0; // if( checksm ) item = xhash_get(user->roster,jid_user(jid)); if( item == NULL ) { /* user has no this jid in his roster */ /* if we checking sm database and user is not in it, not adding */ if( checksm && !userinsm ) { log_debug(ZONE, "published user %s has no record in sm, not adding", jid_user(jid)); continue; /* do { } while( os_iter_next ) */ } log_debug(ZONE, "user has no %s in roster, adding", jid_user(jid)); item = (item_t) calloc(1, sizeof(struct item_st)); item->jid = jid_new(jid_user(jid), -1); if(item->jid == NULL) { log_debug(ZONE, "eek! invalid jid %s, skipping it", jid_user(jid)); log_write(user->sm->log, LOG_ERR, "roster_publish: eek! invalid jid %s, skipping it", jid_user(jid)); /* nvs: is it needed? */ free(item); /* nvs: is it needed? */ } else { os_object_get_str(os, o, "group", &str); if( roster_publish->mappedgroups ) { group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group } else { if(str) group = strdup(str); else group = NULL; } if( group ) { item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1)); item->groups[item->ngroups] = group; item->ngroups++; if(os_object_get_str(os, o, "name", &str)) item->name = strdup(str); os_object_get_bool(os, o, "to", &item->to); os_object_get_bool(os, o, "from", &item->from); os_object_get_int(os, o, "ask", &item->ask); log_debug(ZONE, "adding %s to roster from template (to %d from %d ask %d name %s)", jid_full(item->jid), item->to, item->from, item->ask, item->name); /* its good */ xhash_put(user->roster, jid_full(item->jid), (void *) item); _roster_publish_save_item(user,item); } else { log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str,jid_full(item->jid)); free(item); } if (roster_publish->fixexist && ( (checksm && !userinsm) || (!checksm && storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS && os_iter_first(os_active)) ) ) { /* Add thise jid to active table*/ log_debug(ZONE, "adding published user %s to sm", jid_user(jid)); time_t tfe; os_t osfe; os_object_t ofe; tfe = time(NULL); osfe = os_new(); ofe = os_object_new(osfe); os_object_put_time(ofe, "time", &tfe); storage_put(mi->sm->st, "active", jid_user(jid), osfe); os_free(osfe); } } } else /* if( item == NULL ) else ... : here item != NULL : user has this jid in his roster */ { /* if we checking sm database and user is not in it, remove it from roster */ if( checksm && !userinsm ) { log_debug(ZONE, "published user %s has no record in sm, deleting from roster", jid_user(jid)); snprintf(filter, 4096, "(jid=%s)", jid_full(jid)); storage_delete(user->sm->st, "roster-items", jid_user(user->jid), filter); snprintf(filter, 4096, "(jid=%s)", jid_full(jid)); storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter); xhash_zap(user->roster, jid_full(jid)); _roster_publish_free_walker(NULL, (const char *) jid_full(jid), (void *) item, NULL); continue; /* do { } while( os_iter_next ) */ } if( roster_publish->fixsubs ) { /* check subscriptions and correct if needed */ os_object_get_bool(os, o, "to", &tmp_to); os_object_get_bool(os, o, "from", &tmp_from); if( item->to != tmp_to || item->from != tmp_from ) { item->to = tmp_to; item->from = tmp_from; log_debug(ZONE, "fixsubs in roster %s, item %s",jid_user(user->jid),jid_user(item->jid)); xhash_put(user->roster, jid_full(item->jid), (void *) item); _roster_publish_save_item(user,item); } } if( roster_publish->overridenames ) { /* override display name if it differs */ if(os_object_get_str(os, o, "name", &str)) { if( str ) { tmp_do_change = 0; if( ! item->name ) { tmp_do_change = 1; } else { if( strcmp(item->name,str) != 0 ) { tmp_do_change = 1; } } if( tmp_do_change ) { log_debug(ZONE, "replacing name for %s in roster of %s", jid_full(item->jid),jid_user(user->jid)); item->name = strdup(str); xhash_put(user->roster, jid_full(item->jid), (void *) item); _roster_publish_save_item(user,item); } } else { log_debug(ZONE,"warning: name is null in published roster for item %s",jid_full(item->jid)); } } } if( roster_publish->forcegroups ) { /* item already in roster, check groups if needed */ os_object_get_str(os, o, "group", &str); if( roster_publish->mappedgroups ) { group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group if( !group ) { log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str, jid_full(item->jid)); continue; /* do { } while( os_iter_next ) */ } } else { group = strdup(str); } /* find published roster item's group in user's roster */ found = 0; for(i = 0; i < item->ngroups; i++) { if( strcmp(item->groups[i],group) == 0 ) { found = 1; /* do not break loop, give groups that matches * prefix and suffix to be deleted */ } else { /* check if user's roster group matches * prefix or suffix given in config * and delete such groups (and thus they will be replaced) */ delete = 0; if( roster_publish->groupprefix ) { if( strncmp(item->groups[i],roster_publish->groupprefix,roster_publish->groupprefixlen) == 0 ) { delete = 1; } } if( !delete && roster_publish->groupsuffix ) { gpos=strlen(item->groups[i])-roster_publish->groupsuffixlen; if( gpos > 0 ) { if( strcmp(item->groups[i]+gpos,roster_publish->groupsuffix) == 0 ) { delete = 1; } } } /* remove group from roster item */ if( delete ) { free((void*)item->groups[i]); for(j = i; j < item->ngroups-1; j++) { item->groups[j]=item->groups[j+1]; } item->ngroups--; item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups)); } } } /* for(i... */ if( !found ) { log_debug(ZONE, "adding group %s to item %s for user %s",group,jid_user(item->jid),jid_user(user->jid)); item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1)); item->groups[item->ngroups] = group; // will be freed item->ngroups++; /* replace item */ xhash_put(user->roster, jid_full(item->jid), (void *) item); _roster_publish_save_item(user,item); } else { free((void*)group); } } /* else if( roster_publish->forcegroups ) */ } /* end of if if( item == NULL ) */ } /* if( os_object_get(...) */ } while(os_iter_next(os)); if( jid ) jid_free(jid); } os_free(os); } } return 0; } static void _roster_publish_free(module_t mod) { roster_publish_t roster_publish = (roster_publish_t) mod->private; #ifndef NO_SM_CACHE if( roster_publish->active_cache ) { xhash_walk(roster_publish->active_cache,_roster_publish_free_active_cache_walker,NULL); xhash_free(roster_publish->active_cache); } if( roster_publish->group_cache ) { xhash_walk(roster_publish->group_cache,_roster_publish_free_group_cache_walker,NULL); xhash_free(roster_publish->group_cache); } #endif free(roster_publish); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; roster_publish_t roster_publish; if(mod->init) return 0; roster_publish = (roster_publish_t) calloc(1, sizeof(struct _roster_publish_st)); if( config_get_one(mod->mm->sm->config, "user.template.publish", 0) ) { roster_publish->publish = 1; roster_publish->fetchdomain = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.domain", 0); roster_publish->fetchuser = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.user", 0); roster_publish->fetchfixed = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.fixed", 0); roster_publish->dbtable = config_get_one(mod->mm->sm->config, "user.template.publish.db-table", 0); roster_publish->removedomain = config_get_one(mod->mm->sm->config, "user.template.publish.check-remove-domain", 0); roster_publish->fixsubs = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.fix-subscriptions", 0), 0); roster_publish->overridenames = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.override-names", 0), 0); roster_publish->mappedgroups = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.map-groups", 0), 0); roster_publish->fixexist = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.force-create-contacts", 0), 0); #ifndef NO_SM_CACHE roster_publish->active_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.active-cache-ttl", 0), 0); roster_publish->group_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.group-cache-ttl", 0), 0); #endif if( config_get_one(mod->mm->sm->config, "user.template.publish.force-groups", 0) ) { roster_publish->forcegroups = 1; roster_publish->groupprefix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.prefix", 0); if( roster_publish->groupprefix ) { roster_publish->groupprefixlen = strlen(roster_publish->groupprefix); } roster_publish->groupsuffix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.suffix", 0); if( roster_publish->groupsuffix ) { roster_publish->groupsuffixlen = strlen(roster_publish->groupsuffix); } } else { roster_publish->forcegroups = 0; } } else { roster_publish->publish = 0; } mod->private = roster_publish; mod->user_load = _roster_publish_user_load; mod->free = _roster_publish_free; return 0; } // vim: shiftwidth=4 ��������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_session.c�������������������������������������������������������������0000664�0000000�0000000�00000026145�12614627753�0017714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_session.c * @brief session control * @author Robert Norris * $Date: 2006/03/09 09:08:14 $ * $Revision: 1.12 $ */ /** session packet handling * * - if packet has session namespace on first element, its from a c2s * * - if its pkt_SESSION, then its some session action * - if its pkt_SESSION_START, start a session, reply, done * - get the sm id, find the corresponding session * - do the action, reply, done * * - otherwise, its a normal message/presence/iq for a session * - get the sm id, find the corresponding session * - hand to in_sess chain * */ /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; sess_t *sess_val; }; static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) { sm_t sm = mi->mod->mm->sm; int ns, iq, elem, attr; jid_t jid; sess_t sess = (sess_t) NULL; mod_ret_t ret; /* if we've got this namespace, its from a c2s */ if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0) return mod_PASS; /* don't bother if its a failure */ if(pkt->type & pkt_SESS_FAILED) { /* !!! check failed=1, handle */ pkt_free(pkt); return mod_HANDLED; } /* session commands */ if(pkt->type & pkt_SESS) { ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL); /* only end can get away without a target */ attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL); if(attr < 0 && pkt->type != pkt_SESS_END) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* session start */ if(pkt->type == pkt_SESS) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid != NULL) sess = sess_start(sm, jid); if(jid == NULL || sess == NULL) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); if(jid != NULL) jid_free(jid); return mod_HANDLED; } /* c2s component that is handling this session */ strcpy(sess->c2s, pkt->rfrom->domain); /* remember what c2s calls us */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); /* mark PBX session as fake */ if(!strncmp("PBX", sess->c2s_id, 3)) { sess->fake = 1; } /* add our id */ nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0); /* mark that it started OK */ nad_set_attr(pkt->nad, 1, -1, "action", "started", 7); /* set this SM name */ nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0); /* inform c2s */ sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* user create */ if(pkt->type == pkt_SESS_CREATE) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL || user_create(sm, jid) != 0) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); if(jid != NULL) jid_free(jid); return mod_HANDLED; } /* inform c2s */ nad_set_attr(pkt->nad, 1, -1, "action", "created", 7); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* user delete */ if(pkt->type == pkt_SESS_DELETE) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL) { pkt_free(pkt); return mod_HANDLED; } user_delete(sm, jid); /* inform c2s */ nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* get the session id */ attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); if(attr < 0) { log_debug(ZONE, "no session id, bouncing"); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* find the corresponding session */ sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); /* active check */ if(sess == NULL) { log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* make sure its from them */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id); pkt_free(pkt); return mod_HANDLED; } /* session end */ if(pkt->type == pkt_SESS_END) { sm_c2s_action(sess, "ended", NULL); sess_end(sess); pkt_free(pkt); return mod_HANDLED; } log_debug(ZONE, "unknown session packet, dropping"); pkt_free(pkt); return mod_HANDLED; } /* otherwise, its a normal packet for the session */ /* #ifdef ENABLE_SUPERSEDED // FIXME XXX TODO clients are not yet ready for this */ /* check for RFC3920 session request * * with RFC3920bis it is unneeded * * session is activated by bind, so we just return back result */ if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 && (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 && (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) { log_debug(ZONE, "session create request"); /* build a result packet */ nad_drop_elem(pkt->nad, elem); nad_set_attr(pkt->nad, iq, -1, "type", "result", 6); /* return the result */ sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* #endif */ /* get the session id */ attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); if(attr < 0) { log_debug(ZONE, "no session id, bouncing"); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* find the corresponding session */ sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); /* active check */ if(sess == NULL) { log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* make sure its from them */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id); pkt_free(pkt); return mod_HANDLED; } /* where it came from */ pkt->source = sess; /* hand it to the modules */ ret = mm_in_sess(pkt->sm->mm, sess, pkt); switch(ret) { case mod_HANDLED: break; case mod_PASS: /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */ if(pkt->type == pkt_IQ_RESULT) break; else ret = -stanza_err_FEATURE_NOT_IMPLEMENTED; default: pkt_sess(pkt_error(pkt, -ret), sess); break; } return mod_HANDLED; } static mod_ret_t _session_pkt_router(mod_instance_t mi, pkt_t pkt) { sess_t sess; union xhashv xhv; /* we want unadvertisments */ if(pkt->from == NULL || !(pkt->rtype & route_ADV) || pkt->rtype != route_ADV_UN) return mod_PASS; log_debug(ZONE, "component '%s' went offline, checking for sessions held there", jid_full(pkt->from)); /* this is fairly inefficient, especially if we have a lot of sessions * online, but it shouldn't be called that often (components are usually * long-running) */ xhv.sess_val = &sess; if(xhash_iter_first(mi->mod->mm->sm->sessions)) do { xhash_iter_get(mi->mod->mm->sm->sessions, NULL, NULL, xhv.val); if(sess && strcmp(sess->c2s, pkt->from->domain) == 0) sess_end(sess); } while (xhash_iter_next(mi->mod->mm->sm->sessions)); return mod_PASS; } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { if(mi->mod->init) return 0; mi->mod->in_router = _session_in_router; mi->mod->pkt_router = _session_pkt_router; return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_status.c��������������������������������������������������������������0000664�0000000�0000000�00000016250�12614627753�0017550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd mod_status - Jabber Open Source Server * Copyright (c) 2004 Lucas Nussbaum <lucas@lucas-nussbaum.net> * * 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, MA02111-1307USA */ /** @file sm/mod_status.c * @brief status info management * @author Lucas Nussbaum * $Date: 2004/09/01 $ * $Revision: 1.3 $ */ /* for strndup */ #define _GNU_SOURCE #include <string.h> #include "sm.h" typedef struct _status_st { sm_t sm; const char *resource; } *status_t; static void _status_os_replace(storage_t st, const char *jid, char *status, char *show, time_t *lastlogin, time_t *lastlogout, nad_t nad) { os_t os = os_new(); os_object_t o = os_object_new(os); os_object_put(o, "status", status, os_type_STRING); os_object_put(o, "show", show, os_type_STRING); os_object_put(o, "last-login", (void **) lastlogin, os_type_INTEGER); os_object_put(o, "last-logout", (void **) lastlogout, os_type_INTEGER); if(nad != NULL) os_object_put(o, "xml", nad, os_type_NAD); storage_replace(st, "status", jid, NULL, os); os_free(os); } static void _status_store(storage_t st, const char *jid, pkt_t pkt, time_t *lastlogin, time_t *lastlogout) { char *show; int show_free = 0; switch(pkt->type) { int elem; case pkt_PRESENCE_UN: show = "unavailable"; break; default: elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "show", 1); if (elem < 0) { show = ""; } else { if (NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19) show = ""; else { show = strndup(NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem)); show_free = 1; } } } _status_os_replace(st, jid, "online", show, lastlogin, lastlogout, pkt->nad); if(show_free) free(show); } static int _status_sess_start(mod_instance_t mi, sess_t sess) { time_t t, lastlogout; os_t os; os_object_t o; st_ret_t ret; nad_t nad; /* not interested if there is other top session */ if(sess->user->top != NULL && sess != sess->user->top) return mod_PASS; ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); if (ret == st_SUCCESS) { if (os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "last-logout", &lastlogout); os_object_get_nad(os, o, "xml", &nad); nad = nad_copy(nad); } os_free(os); } else { lastlogout = (time_t) 0; nad = NULL; } t = time(NULL); _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "online", "", &t, &lastlogout, nad); if(nad != NULL) nad_free(nad); return mod_PASS; } static void _status_sess_end(mod_instance_t mi, sess_t sess) { time_t t, lastlogin; os_t os; os_object_t o; st_ret_t ret; nad_t nad; /* not interested if there is other top session */ if(sess->user->top != NULL && sess != sess->user->top) return; ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); if (ret == st_SUCCESS) { if (os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "last-login", &lastlogin); os_object_get_nad(os, o, "xml", &nad); nad = nad_copy(nad); } os_free(os); } else { lastlogin = (time_t) 0; nad = NULL; } t = time(NULL); _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "offline", "", &lastlogin, &t, nad); if(nad != NULL) nad_free(nad); } static mod_ret_t _status_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { time_t lastlogin, lastlogout; os_t os; os_object_t o; st_ret_t ret; /* only handle presence */ if(!(pkt->type & pkt_PRESENCE)) return mod_PASS; ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); if (ret == st_SUCCESS) { if (os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "last-login", &lastlogin); os_object_get_time(os, o, "last-logout", &lastlogout); } os_free(os); } else { lastlogin = (time_t) 0; lastlogout = (time_t) 0; } /* Store only presence broadcasts. If the presence is for a specific user, ignore it. */ if (pkt->to == NULL) _status_store(sess->user->sm->st, jid_user(sess->jid), pkt, &lastlogin, &lastlogout); return mod_PASS; } /* presence packets incoming from other servers */ static mod_ret_t _status_pkt_sm(mod_instance_t mi, pkt_t pkt) { time_t t; jid_t jid; module_t mod = mi->mod; status_t st = (status_t) mod->private; /* store presence information */ if(pkt->type == pkt_PRESENCE || pkt->type == pkt_PRESENCE_UN) { log_debug(ZONE, "storing presence from %s", jid_full(pkt->from)); t = (time_t) 0; _status_store(mod->mm->sm->st, jid_user(pkt->from), pkt, &t, &t); } /* answer to probes and subscription requests*/ if(st->resource && (pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N)) { log_debug(ZONE, "answering presence probe/sub from %s with /%s resource", jid_full(pkt->from), st->resource); /* send presence */ jid = jid_new(pkt->to->domain, -1); jid = jid_reset_components(jid, jid->node, jid->domain, st->resource); pkt_router(pkt_create(st->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid))); jid_free(jid); } /* and handle over */ return mod_PASS; } static void _status_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting status information of %s", jid_user(jid)); storage_delete(mi->sm->st, "status", jid_user(jid), NULL); } static void _status_free(module_t mod) { free(mod->private); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; status_t tr; if (mod->init) return 0; tr = (status_t) calloc(1, sizeof(struct _status_st)); tr->sm = mod->mm->sm; tr->resource = config_get_one(mod->mm->sm->config, "status.resource", 0); mod->private = tr; mod->sess_start = _status_sess_start; mod->sess_end = _status_sess_end; mod->in_sess = _status_in_sess; mod->pkt_sm = _status_pkt_sm; mod->user_delete = _status_user_delete; mod->free = _status_free; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_template_roster.c�����������������������������������������������������0000664�0000000�0000000�00000017561�12614627753�0021444�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_template_roster.c * @brief user auto-population - roster * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.11 $ */ /* user template - roster */ typedef struct _template_roster_st { sm_t sm; const char *filename; time_t mtime; xht items; } *template_roster_t; /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; item_t *item_val; }; static int _template_roster_reload(template_roster_t tr) { struct stat st; FILE *f; long size; char *buf; nad_t nad; int nitems, eitem, ajid, as10n, aname, egroup; item_t item; if(stat(tr->filename, &st) < 0) { log_write(tr->sm->log, LOG_ERR, "couldn't stat roster template %s: %s", tr->filename, strerror(errno)); return 1; } if(st.st_mtime <= tr->mtime) return 0; tr->mtime = st.st_mtime; if(tr->items != NULL) xhash_free(tr->items); tr->items = xhash_new(101); f = fopen(tr->filename, "r"); if(f == NULL) { log_write(tr->sm->log, LOG_ERR, "couldn't open roster template %s: %s", tr->filename, strerror(errno)); return 1; } fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); buf = (char *) malloc(sizeof(char) * size); if (fread(buf, 1, size, f) != size || ferror(f)) { log_write(tr->sm->log, LOG_ERR, "couldn't read from roster template %s: %s", tr->filename, strerror(errno)); free(buf); fclose(f); return 1; } fclose(f); nad = nad_parse(buf, size); if(nad == NULL) { log_write(tr->sm->log, LOG_ERR, "couldn't parse roster template"); free(buf); return 1; } free(buf); if(nad->ecur < 2) { log_write(tr->sm->log, LOG_NOTICE, "roster template has no elements"); } nitems = 0; eitem = nad_find_elem(nad, 0, NAD_ENS(nad, 0), "item", 1); while(eitem >= 0) { ajid = nad_find_attr(nad, eitem, -1, "jid", NULL); if(ajid < 0) { log_write(tr->sm->log, LOG_ERR, "roster template has item with no jid, skipping"); continue; } item = (item_t) pmalloco(xhash_pool(tr->items), sizeof(struct item_st)); item->jid = jid_new(NAD_AVAL(nad, ajid), NAD_AVAL_L(nad, ajid)); if(item->jid == NULL) { log_write(tr->sm->log, LOG_ERR, "roster template has item with invalid jid, skipping"); continue; } pool_cleanup(xhash_pool(tr->items), (void (*)(void *)) jid_free, item->jid); as10n = nad_find_attr(nad, eitem, -1, "subscription", NULL); if(as10n >= 0) { if(NAD_AVAL_L(nad, as10n) == 2 && strncmp("to", NAD_AVAL(nad, as10n), 2) == 0) item->to = 1; else if(NAD_AVAL_L(nad, as10n) == 4 && strncmp("from", NAD_AVAL(nad, as10n), 4) == 0) item->from = 1; else if(NAD_AVAL_L(nad, as10n) == 4 && strncmp("both", NAD_AVAL(nad, as10n), 4) == 0) item->to = item->from = 1; } aname = nad_find_attr(nad, eitem, -1, "name", NULL); if(aname >= 0) item->name = pstrdupx(xhash_pool(tr->items), NAD_AVAL(nad, aname), NAD_AVAL_L(nad, aname)); egroup = nad_find_elem(nad, eitem, NAD_ENS(nad, 0), "group", 1); while(egroup >= 0) { if(NAD_CDATA_L(nad, egroup) <= 0) { log_write(tr->sm->log, LOG_ERR, "roster template has zero-length group, skipping"); continue; } item->groups = (const char **) realloc(item->groups, sizeof(char *) * (item->ngroups + 1)); item->groups[item->ngroups] = pstrdupx(xhash_pool(tr->items), NAD_CDATA(nad, egroup), NAD_CDATA_L(nad, egroup)); item->ngroups++; egroup = nad_find_elem(nad, egroup, NAD_ENS(nad, 0), "group", 0); } if(item->groups != NULL) pool_cleanup(xhash_pool(tr->items), free, item->groups); xhash_put(tr->items, jid_full(item->jid), item); log_debug(ZONE, "loaded roster template item %s, %d groups", jid_full(item->jid), item->ngroups); nitems++; eitem = nad_find_elem(nad, eitem, NAD_ENS(nad, 0), "item", 0); } log_write(tr->sm->log, LOG_NOTICE, "loaded %d items from roster template", nitems); return 0; } /** !!! this is a cut & paste of _roster_save_time - break it out */ static void _template_roster_save_item(sm_t sm, jid_t jid, item_t item) { os_t os; os_object_t o; char filter[4096]; int i; log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(jid)); os = os_new(); o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); if(item->name != NULL) os_object_put(o, "name", item->name, os_type_STRING); os_object_put(o, "to", &item->to, os_type_BOOLEAN); os_object_put(o, "from", &item->from, os_type_BOOLEAN); os_object_put(o, "ask", &item->ask, os_type_INTEGER); snprintf(filter, 4096, "(jid=%zu:%s)", strlen(jid_full(item->jid)), jid_full(item->jid)); storage_replace(sm->st, "roster-items", jid_user(jid), filter, os); os_free(os); snprintf(filter, 4096, "(jid=%zu:%s)", strlen(jid_full(item->jid)), jid_full(item->jid)); if(item->ngroups == 0) { storage_delete(sm->st, "roster-groups", jid_user(jid), filter); return; } os = os_new(); for(i = 0; i < item->ngroups; i++) { o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); os_object_put(o, "group", item->groups[i], os_type_STRING); } storage_replace(sm->st, "roster-groups", jid_user(jid), filter, os); os_free(os); } static int _template_roster_user_create(mod_instance_t mi, jid_t jid) { template_roster_t tr = (template_roster_t) mi->mod->private; item_t item; union xhashv xhv; if(_template_roster_reload(tr) != 0) return 0; log_debug(ZONE, "populating roster with items from template"); if(xhash_iter_first(tr->items)) do { xhv.item_val = &item; xhash_iter_get(tr->items, NULL, NULL, xhv.val); _template_roster_save_item(tr->sm, jid, item); } while(xhash_iter_next(tr->items)); return 0; } static void _template_roster_free(module_t mod) { template_roster_t tr = (template_roster_t) mod->private; if(tr->items != NULL) xhash_free(tr->items); free(tr); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; const char *filename; template_roster_t tr; if(mod->init) return 0; filename = config_get_one(mod->mm->sm->config, "user.template.roster", 0); if(filename == NULL) return 0; tr = (template_roster_t) calloc(1, sizeof(struct _template_roster_st)); tr->sm = mod->mm->sm; tr->filename = filename; mod->private = tr; mod->user_create = _template_roster_user_create; mod->free = _template_roster_free; return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/mod_vacation.c������������������������������������������������������������0000664�0000000�0000000�00000016737�12614627753�0020043�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_vacation.c * @brief vacation messages * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.13 $ */ #define uri_VACATION "http://jabber.org/protocol/vacation" static int ns_VACATION = 0; typedef struct _vacation_st { time_t start; time_t end; char *msg; } *vacation_t; static mod_ret_t _vacation_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; vacation_t v = sess->user->module_data[mod->index]; int ns, start, end, msg; char dt[30]; pkt_t res; os_t os; os_object_t o; /* we only want to play with vacation iq packets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VACATION) return mod_PASS; /* if it has a to, throw it out */ if(pkt->to != NULL) return -stanza_err_BAD_REQUEST; /* get */ if(pkt->type == pkt_IQ) { if(v->msg == NULL) { res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); if(v->start != 0) { datetime_out(v->start, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "start", dt); } else nad_insert_elem(pkt->nad, 2, ns, "start", NULL); if(v->end != 0) { datetime_out(v->end, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "end", dt); } else nad_insert_elem(pkt->nad, 2, ns, "end", NULL); nad_insert_elem(pkt->nad, 2, ns, "message", v->msg); pkt_tofrom(pkt); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt, sess); return mod_HANDLED; } /* set */ ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); start = nad_find_elem(pkt->nad, 2, ns, "start", 1); end = nad_find_elem(pkt->nad, 2, ns, "end", 1); msg = nad_find_elem(pkt->nad, 2, ns, "message", 1); if(start < 0 || end < 0 || msg < 0) { /* forget */ if(v->msg != NULL) { free(v->msg); v->msg = NULL; } v->start = 0; v->end = 0; storage_delete(mi->sm->st, "vacation-settings", jid_user(sess->jid), NULL); res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } if(NAD_CDATA_L(pkt->nad, start) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, start), (30 < NAD_CDATA_L(pkt->nad, start) ? 30 : NAD_CDATA_L(pkt->nad, start))); v->start = datetime_in(dt); } else v->start = 0; if(NAD_CDATA_L(pkt->nad, end) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, end), (30 < NAD_CDATA_L(pkt->nad, end) ? 30 : NAD_CDATA_L(pkt->nad, end))); v->end = datetime_in(dt); } else v->end = 0; v->msg = (char *) malloc(sizeof(char) * (NAD_CDATA_L(pkt->nad, msg) + 1)); strncpy(v->msg, NAD_CDATA(pkt->nad, msg), NAD_CDATA_L(pkt->nad, msg)); v->msg[NAD_CDATA_L(pkt->nad, msg)] = '\0'; os = os_new(); o = os_object_new(os); os_object_put(o, "start", &v->start, os_type_INTEGER); os_object_put(o, "end", &v->end, os_type_INTEGER); os_object_put(o, "message", v->msg, os_type_STRING); if(storage_replace(mod->mm->sm->st, "vacation-settings", jid_user(sess->user->jid), NULL, os) != st_SUCCESS) { free(v->msg); v->msg = NULL; v->start = 0; v->end = 0; return -stanza_err_INTERNAL_SERVER_ERROR; } res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } static mod_ret_t _vacation_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { module_t mod = mi->mod; vacation_t v = user->module_data[mod->index]; time_t t; pkt_t res; if(v->msg == NULL) return mod_PASS; /* only want messages, and only if they're offline */ if(!(pkt->type & pkt_MESSAGE) || user->top != NULL) return mod_PASS; /* reply only to real, human users - they always have full JIDs in 'from' */ jid_expand(pkt->from); if(pkt->from->node[0] == '\0' || pkt->from->resource[0] == '\0') { pkt_free(pkt); return mod_HANDLED; } t = time(NULL); if(v->start < t && (t < v->end || v->end == 0)) { res = pkt_create(mod->mm->sm, "message", NULL, jid_full(pkt->from), user->jid->domain); nad_insert_elem(res->nad, 1, NAD_ENS(res->nad, 1), "subject", "Automated reply"); nad_insert_elem(res->nad, 1, NAD_ENS(res->nad, 1), "body", v->msg); pkt_router(res); /* !!! remember that we sent this */ } return mod_PASS; } static void _vacation_user_free(vacation_t v) { if(v->msg != NULL) free(v->msg); free(v); } static int _vacation_user_load(mod_instance_t mi, user_t user) { module_t mod = mi->mod; vacation_t v; os_t os; os_object_t o; v = (vacation_t) calloc(1, sizeof(struct _vacation_st)); user->module_data[mod->index] = v; if(storage_get(mod->mm->sm->st, "vacation-settings", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_time(os, o, "start", &v->start) && os_object_get_time(os, o, "end", &v->end) && os_object_get_str(os, o, "message", &v->msg)) v->msg = strdup(v->msg); else { v->start = 0; v->end = 0; v->msg = NULL; } } os_free(os); } pool_cleanup(user->p, (void (*))(void *) _vacation_user_free, v); return 0; } static void _vacation_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting vacations settings for %s", jid_user(jid)); storage_delete(mi->sm->st, "vacation-settings", jid_user(jid), NULL); } static void _vacation_free(module_t mod) { sm_unregister_ns(mod->mm->sm, uri_VACATION); feature_unregister(mod->mm->sm, uri_VACATION); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _vacation_in_sess; mod->pkt_user = _vacation_pkt_user; mod->user_load = _vacation_user_load; mod->user_delete = _vacation_user_delete; mod->free = _vacation_free; /* mmm good! :) */ ns_VACATION = sm_register_ns(mod->mm->sm, uri_VACATION); feature_register(mod->mm->sm, uri_VACATION); return 0; } ���������������������������������jabberd2-jabberd-2.3.4/sm/mod_validate.c������������������������������������������������������������0000664�0000000�0000000�00000003313�12614627753�0020012�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/mod_validate.c * @brief packet validator * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.15 $ */ static mod_ret_t _validate_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* only want message, presence and iq */ if(!(pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ || pkt->type & pkt_S10N)) { log_debug(ZONE, "we only take message, presence and iq packets"); return -stanza_err_BAD_REQUEST; } return mod_PASS; } static mod_ret_t _validate_in_router(mod_instance_t mi, pkt_t pkt) { return _validate_in_sess(mi, NULL, pkt); } DLLEXPORT int module_init(mod_instance_t mi, const char *arg) { module_t mod = mi->mod; if(mod->init) return 0; mod->in_sess = _validate_in_sess; mod->in_router = _validate_in_router; return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/pkt.c���������������������������������������������������������������������0000664�0000000�0000000�00000044074�12614627753�0016171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/pkt.c * @brief packet abstraction * @author Robert Norris * $Date: 2005/09/09 05:34:13 $ * $Revision: 1.35 $ */ pkt_t pkt_error(pkt_t pkt, int err) { if(pkt == NULL) return NULL; /* if it's an error already, log, free, return */ if(pkt->type & pkt_ERROR) { log_debug(ZONE, "dropping error pkt"); pkt_free(pkt); return NULL; } stanza_error(pkt->nad, 1, err); /* update vars and attrs */ pkt_tofrom(pkt); pkt->type |= pkt_ERROR; /* supplant route destination in case there was none in original packet */ if(pkt->to == NULL && pkt->rto != NULL) pkt->to = jid_dup(pkt->rto); /* all done, error'd and addressed */ log_debug(ZONE, "processed %d error pkt", err); return pkt; } /** swap a packet's to and from attributes */ pkt_t pkt_tofrom(pkt_t pkt) { jid_t tmp; if(pkt == NULL) return NULL; /* swap vars */ tmp = pkt->from; pkt->from = pkt->to; pkt->to = tmp; tmp = pkt->rfrom; pkt->rfrom = pkt->rto; pkt->rto = tmp; /* update attrs */ if(pkt->to != NULL) nad_set_attr(pkt->nad, 1, -1, "to", jid_full(pkt->to), 0); if(pkt->from != NULL) nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); if(pkt->rto != NULL) nad_set_attr(pkt->nad, 0, -1, "to", jid_full(pkt->rto), 0); if(pkt->rfrom != NULL) nad_set_attr(pkt->nad, 0, -1, "from", jid_full(pkt->rfrom), 0); return pkt; } /** duplicate pkt, replacing addresses */ pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from) { pkt_t pnew; if(pkt == NULL) return NULL; pnew = (pkt_t) calloc(1, sizeof(struct pkt_st)); pnew->sm = pkt->sm; pnew->type = pkt->type; pnew->nad = nad_copy(pkt->nad); /* set replacement attrs */ if(to != NULL) { pnew->to = jid_new(to, -1); nad_set_attr(pnew->nad, 1, -1, "to", jid_full(pnew->to), 0); } else if(pkt->to != NULL) pnew->to = jid_dup(pkt->to); if(from != NULL) { pnew->from = jid_new(from, -1); nad_set_attr(pnew->nad, 1, -1, "from", jid_full(pnew->from), 0); } else if(pkt->from != NULL) pnew->from = jid_dup(pkt->from); log_debug(ZONE, "duplicated packet"); return pnew; } pkt_t pkt_new(sm_t sm, nad_t nad) { pkt_t pkt; int ns, attr, elem; char pri[20]; log_debug(ZONE, "creating new packet"); /* find the route */ ns = nad_find_namespace(nad, 0, uri_COMPONENT, NULL); if(ns < 0) { log_debug(ZONE, "packet not in component namespace"); nad_free(nad); return NULL; } /* create the pkt holder */ pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); pkt->sm = sm; pkt->nad = nad; /* routes */ if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) { /* route element */ if((attr = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) pkt->rto = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) pkt->rfrom = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* route type */ attr = nad_find_attr(nad, 0, -1, "type", NULL); if(attr < 0) pkt->rtype = route_UNICAST; else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("broadcast", NAD_AVAL(nad, attr), 9) == 0) pkt->rtype = route_BROADCAST; /* route errors */ if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) pkt->rtype |= route_ERROR; /* client packets */ ns = nad_find_namespace(nad, 1, uri_CLIENT, NULL); if(ns >= 0) { /* get initial addresses */ if((attr = nad_find_attr(pkt->nad, 1, -1, "to", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) pkt->to = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if((attr = nad_find_attr(pkt->nad, 1, -1, "from", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) pkt->from = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); /* find type, if any */ attr = nad_find_attr(pkt->nad, 1, -1, "type", NULL); /* messages are simple, only subtypes */ if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("message", NAD_ENAME(pkt->nad, 1), 7) == 0) { pkt->type = pkt_MESSAGE; if(attr >= 0) { if(NAD_AVAL_L(pkt->nad, attr) == 4 && strncmp("chat", NAD_AVAL(pkt->nad, attr), 4) == 0) pkt->type = pkt_MESSAGE_CHAT; else if(NAD_AVAL_L(pkt->nad, attr) == 8 && strncmp("headline", NAD_AVAL(pkt->nad, attr), 8) == 0) pkt->type = pkt_MESSAGE_HEADLINE; else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("groupchat", NAD_AVAL(pkt->nad, attr), 9) == 0) pkt->type = pkt_MESSAGE_GROUPCHAT; else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_MESSAGE | pkt_ERROR; } return pkt; } /* presence is a mixed bag, s10ns in here too */ if(NAD_ENAME_L(pkt->nad, 1) == 8 && strncmp("presence", NAD_ENAME(pkt->nad, 1), 8) == 0) { pkt->type = pkt_PRESENCE; if(attr >= 0) { if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unavailable", NAD_AVAL(pkt->nad, attr), 11) == 0) pkt->type = pkt_PRESENCE_UN; else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("probe", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_PRESENCE_PROBE; else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("subscribe", NAD_AVAL(pkt->nad, attr), 9) == 0) pkt->type = pkt_S10N; else if(NAD_AVAL_L(pkt->nad, attr) == 10 && strncmp("subscribed", NAD_AVAL(pkt->nad, attr), 10) == 0) pkt->type = pkt_S10N_ED; else if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unsubscribe", NAD_AVAL(pkt->nad, attr), 11) == 0) pkt->type = pkt_S10N_UN; else if(NAD_AVAL_L(pkt->nad, attr) == 12 && strncmp("unsubscribed", NAD_AVAL(pkt->nad, attr), 12) == 0) pkt->type = pkt_S10N_UNED; else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_PRESENCE | pkt_ERROR; } /* priority */ if((elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "priority", 1)) < 0) return pkt; if(NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19) return pkt; memcpy(pri, NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem)); pri[NAD_CDATA_L(pkt->nad, elem)] = '\0'; pkt->pri = atoi(pri); if(pkt->pri > 127) pkt->pri = 127; if(pkt->pri < -128) pkt->pri = -128; return pkt; } /* iq's are pretty easy, but also set xmlns */ if(NAD_ENAME_L(pkt->nad, 1) == 2 && strncmp("iq", NAD_ENAME(pkt->nad, 1), 2) == 0) { pkt->type = pkt_IQ; if (attr < 0) { log_write(sm->log, LOG_ERR, "dropping iq without type"); log_debug(ZONE, "dropping iq without type"); pkt_free(pkt); return NULL; } if (NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("result", NAD_AVAL(pkt->nad, attr), 6) == 0) pkt->type = pkt_IQ_RESULT; else if (NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_IQ | pkt_ERROR; else if (NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("set", NAD_AVAL(pkt->nad, attr), 3) == 0) pkt->type = pkt_IQ_SET; else if (NAD_AVAL_L(pkt->nad, attr) != 3 || strncmp("get", NAD_AVAL(pkt->nad, attr), 3)) { log_write(sm->log, LOG_ERR, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); log_debug(ZONE, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); pkt_free(pkt); return NULL; } if(pkt->nad->ecur > 2 && (ns = NAD_ENS(pkt->nad, 2)) >= 0) pkt->ns = (int) (long) xhash_getx(pkt->sm->xmlns, NAD_NURI(pkt->nad, ns), NAD_NURI_L(pkt->nad, ns)); return pkt; } log_debug(ZONE, "unknown client namespace packet"); return pkt; } /* sessions packets */ ns = nad_find_namespace(nad, 1, uri_SESSION, NULL); if(ns >= 0) { /* sessions */ if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("session", NAD_ENAME(pkt->nad, 1), 7) == 0) { /* find action */ attr = nad_find_attr(pkt->nad, 1, -1, "action", NULL); if(attr >= 0) { if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("start", NAD_AVAL(pkt->nad, attr), 5) >= 0) pkt->type = pkt_SESS; else if(NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("end", NAD_AVAL(pkt->nad, attr), 3) >= 0) pkt->type = pkt_SESS_END; else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("create", NAD_AVAL(pkt->nad, attr), 6) >= 0) pkt->type = pkt_SESS_CREATE; else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("delete", NAD_AVAL(pkt->nad, attr), 6) >= 0) pkt->type = pkt_SESS_DELETE; else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("started", NAD_AVAL(pkt->nad, attr), 7) >= 0) pkt->type = pkt_SESS | pkt_SESS_FAILED; else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("ended", NAD_AVAL(pkt->nad, attr), 5) >= 0) pkt->type = pkt_SESS_END | pkt_SESS_FAILED; else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("created", NAD_AVAL(pkt->nad, attr), 7) >= 0) pkt->type = pkt_SESS_CREATE | pkt_SESS_FAILED; else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("deleted", NAD_AVAL(pkt->nad, attr), 7) >= 0) pkt->type = pkt_SESS_DELETE | pkt_SESS_FAILED; return pkt; } else { log_debug(ZONE, "missing action on session packet"); return pkt; } } log_debug(ZONE, "unknown session namespace packet"); return pkt; } log_debug(ZONE, "unknown packet"); return pkt; } /* advertisements */ if(NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) { if(nad_find_attr(nad, 0, -1, "type", "unavailable") >= 0) pkt->rtype = route_ADV_UN; else pkt->rtype = route_ADV; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr >= 0) pkt->from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); return pkt; } log_debug(ZONE, "invalid component packet"); pkt_free(pkt); return NULL; } void pkt_free(pkt_t pkt) { log_debug(ZONE, "freeing pkt"); if (pkt != NULL) { if(pkt->rto != NULL) jid_free(pkt->rto); if(pkt->rfrom != NULL) jid_free(pkt->rfrom); if(pkt->to != NULL) jid_free(pkt->to); if(pkt->from != NULL) jid_free(pkt->from); if(pkt->nad != NULL) nad_free(pkt->nad); free(pkt); } } pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "route", 0); nad_add_namespace(nad, uri_SESSION, "sm"); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, elem, 1); if(type != NULL) nad_append_attr(nad, -1, "type", type); if(to != NULL) nad_append_attr(nad, -1, "to", to); if(from != NULL) nad_append_attr(nad, -1, "from", from); return pkt_new(sm, nad); } /** convenience - copy the packet id from src to dest */ void pkt_id(pkt_t src, pkt_t dest) { int attr; attr = nad_find_attr(src->nad, 1, -1, "id", NULL); if(attr >= 0) nad_set_attr(dest->nad, 1, -1, "id", NAD_AVAL(src->nad, attr), NAD_AVAL_L(src->nad, attr)); else nad_set_attr(dest->nad, 1, -1, "id", NULL, 0); } /** create an id value for new iq packets */ void pkt_id_new(pkt_t pkt) { char id[40]; int i, r; /* as we are not using ids for tracking purposes, these can be generated randomly */ for(i = 0; i < 40; i++) { r = (int) (36.0 * rand() / RAND_MAX); id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); } nad_set_attr(pkt->nad, 1, -1, "id", id, 40); return; } void pkt_router(pkt_t pkt) { mod_ret_t ret; int ns, scan; if(pkt == NULL) return; log_debug(ZONE, "delivering pkt to router"); if(pkt->to == NULL) { log_debug(ZONE, "no to address on packet, unable to route"); pkt_free(pkt); return; } if(pkt->rto != NULL) jid_free(pkt->rto); pkt->rto = jid_new(pkt->to->domain, -1); if(pkt->rto == NULL) { log_debug(ZONE, "invalid to address on packet, unable to route"); pkt_free(pkt); return; } nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0); if(pkt->rfrom != NULL) jid_free(pkt->rfrom); pkt->rfrom = jid_new(pkt->sm->id, -1); if(pkt->rfrom == NULL) { log_debug(ZONE, "invalid from address on packet, unable to route"); pkt_free(pkt); return; } nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0); ret = mm_out_router(pkt->sm->mm, pkt); switch(ret) { case mod_HANDLED: return; case mod_PASS: /* remove sm specifics */ ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL); /* remove them if there is no session elements in packet */ if(ns >= 0 && nad_find_elem(pkt->nad, 0, ns, NULL, 1) < 0) { nad_set_attr(pkt->nad, 1, ns, "c2s", NULL, 0); nad_set_attr(pkt->nad, 1, ns, "sm", NULL, 0); /* forget about the internal namespace too */ if(pkt->nad->elems[1].ns == ns) pkt->nad->elems[1].ns = pkt->nad->nss[ns].next; else { for(scan = pkt->nad->elems[1].ns; pkt->nad->nss[scan].next != -1 && pkt->nad->nss[scan].next != ns; scan = pkt->nad->nss[scan].next); /* got it */ if(pkt->nad->nss[scan].next != -1) pkt->nad->nss[scan].next = pkt->nad->nss[ns].next; } } sx_nad_write(pkt->sm->router, pkt->nad); /* nad already free'd, free the rest */ pkt->nad = NULL; pkt_free(pkt); break; default: pkt_router(pkt_error(pkt, -ret)); break; } } void pkt_sess(pkt_t pkt, sess_t sess) { mod_ret_t ret; if(pkt == NULL) return; log_debug(ZONE, "delivering pkt to session %s", jid_full(sess->jid)); if(pkt->rto != NULL) jid_free(pkt->rto); pkt->rto = jid_new(sess->c2s, -1); if(pkt->rto == NULL) { log_debug(ZONE, "invalid to address on packet, unable to route"); pkt_free(pkt); return; } nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0); if(pkt->rfrom != NULL) jid_free(pkt->rfrom); pkt->rfrom = jid_new(pkt->sm->id, -1); if(pkt->rfrom == NULL) { log_debug(ZONE, "invalid from address on packet, unable to route"); pkt_free(pkt); return; } nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0); ret = mm_out_sess(pkt->sm->mm, sess, pkt); switch(ret) { case mod_HANDLED: return; case mod_PASS: sess_route(sess, pkt); break; default: pkt_router(pkt_error(pkt, -ret)); break; } } /** add an x:delay stamp */ void pkt_delay(pkt_t pkt, time_t t, const char *from) { char timestamp[21]; int ns, elem; #ifdef ENABLE_SUPERSEDED datetime_out(t, dt_LEGACY, timestamp, 18); ns = nad_add_namespace(pkt->nad, uri_DELAY, NULL); elem = nad_insert_elem(pkt->nad, 1, ns, "x", NULL); nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0); if(from != NULL) nad_set_attr(pkt->nad, elem, -1, "from", from, 0); log_debug(ZONE, "added pkt XEP-0091 delay stamp %s", timestamp); #endif datetime_out(t, dt_DATETIME, timestamp, 21); ns = nad_add_namespace(pkt->nad, uri_URN_DELAY, NULL); elem = nad_insert_elem(pkt->nad, 1, ns, "delay", NULL); nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0); if(from != NULL) nad_set_attr(pkt->nad, elem, -1, "from", from, 0); log_debug(ZONE, "added pkt XEP-0203 delay stamp %s", timestamp); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/pres.c��������������������������������������������������������������������0000664�0000000�0000000�00000033631�12614627753�0016341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* vim: set et ts=4 sw=4: */ /* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/pres.c * @brief presence tracker * @author Robert Norris * $Date: 2005/06/02 04:48:25 $ * $Revision: 1.41 $ */ /* * there are four entry points * * pres_update(sess, pkt) - presence updates from a session (T1, T2, T3) * pres_in(user, pkt) - presence updates from a remote jid (T4, T5) * pres_error(sess, jid) - remote jid bounced an update (T6) * pres_deliver(sess, pkt) - outgoing directed presence (T7, T8) */ /** select a new top session based on current session presence */ static void _pres_top(user_t user) { sess_t scan; user->top = NULL; user->available = 0; /* loop the active sessions */ for(scan = user->sessions; scan != NULL; scan = scan->next) { if(scan->available) user->available = 1; /* non available and/or negative presence and/or fake can't become top session */ if(!scan->available || scan->pri < 0 || scan->fake) continue; /* if we don't have one, then this is it */ if(user->top == NULL) user->top = scan; /* if we have higher priority than current top, we're the new top */ if(scan->pri >= user->top->pri) user->top = scan; } if(user->top == NULL) { log_debug(ZONE, "no priority >= 0 sessions, so no top session"); } else { log_debug(ZONE, "top session for %s is now %s (priority %d)", jid_user(user->jid), jid_full(user->top->jid), user->top->pri); } } /** presence updates from a session */ void pres_update(sess_t sess, pkt_t pkt) { item_t item; int self; jid_t scan, next; sess_t sscan; switch(pkt->type) { case pkt_PRESENCE: log_debug(ZONE, "available presence for session %s", jid_full(sess->jid)); /* cache packet for later */ if(sess->pres != NULL) pkt_free(sess->pres); sess->pres = pkt; /* B1: forward to all in T, unless in E */ /* loop the roster, looking for trusted */ self = 0; if(xhash_iter_first(sess->user->roster)) do { xhash_iter_get(sess->user->roster, NULL, NULL, (void *) &item); /* if we're coming available, and we can see them, we need to probe them */ if(!sess->available && item->to) { log_debug(ZONE, "probing %s", jid_full(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "probe", jid_full(item->jid), jid_user(sess->jid))); /* flag if we probed ourselves */ if(strcmp(jid_user(sess->jid), jid_full(item->jid)) == 0) self = 1; } /* if they can see us, forward */ if(item->from && !jid_search(sess->E, item->jid)) { log_debug(ZONE, "forwarding available to %s", jid_full(item->jid)); pkt_router(pkt_dup(pkt, jid_full(item->jid), jid_full(sess->jid))); } } while(xhash_iter_next(sess->user->roster)); /* probe ourselves if we need to and didn't already */ if(!self && !sess->available) { log_debug(ZONE, "probing ourselves"); pkt_router(pkt_create(sess->user->sm, "presence", "probe", jid_user(sess->jid), jid_user(sess->jid))); } /* forward to our active sessions */ for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { if(sscan != sess && sscan->available && !sscan->fake) { log_debug(ZONE, "forwarding available to our session %s", jid_full(sscan->jid)); pkt_router(pkt_dup(pkt, jid_full(sscan->jid), jid_full(sess->jid))); } } /* update vars */ sess->available = 1; /* new priority */ sess->pri = pkt->pri; /* stamp the saved presence so future probes know how old it is */ pkt_delay(pkt, time(NULL), jid_full(pkt->from)); break; case pkt_PRESENCE_UN: log_debug(ZONE, "unavailable presence for session %s", jid_full(sess->jid)); /* free cached presence */ if(sess->pres != NULL) { pkt_free(sess->pres); sess->pres = NULL; } /* B2: forward to all in T and A, unless in E */ /* loop the roster, looking for trusted */ if(xhash_iter_first(sess->user->roster)) do { xhash_iter_get(sess->user->roster, NULL, NULL, (void *) &item); /* forward if they're trusted and they're not E */ if(item->from && !jid_search(sess->E, item->jid)) { log_debug(ZONE, "forwarding unavailable to %s", jid_full(item->jid)); pkt_router(pkt_dup(pkt, jid_full(item->jid), jid_full(sess->jid))); } } while(xhash_iter_next(sess->user->roster)); /* walk A and forward to untrusted */ for(scan = sess->A; scan != NULL; scan = scan->next) if(!pres_trust(sess->user, scan)) { log_debug(ZONE, "forwarding unavailable to %s", jid_full(scan)); pkt_router(pkt_dup(pkt, jid_full(scan), jid_full(sess->jid))); } /* forward to our active sessions */ for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { if(sscan != sess && sscan->available && !sscan->fake) { log_debug(ZONE, "forwarding available to our session %s", jid_full(sscan->jid)); pkt_router(pkt_dup(pkt, jid_full(sscan->jid), jid_full(sess->jid))); } } /* drop A, E */ scan = sess->A; while(scan != NULL) { next = scan->next; jid_free(scan); scan = next; } sess->A = NULL; scan = sess->E; while(scan != NULL) { next = scan->next; jid_free(scan); scan = next; } sess->E = NULL; /* update vars */ sess->available = 0; /* done */ pkt_free(pkt); break; default: log_debug(ZONE, "pres_update got packet type 0x%X, this shouldn't happen", pkt->type); pkt_free(pkt); return; } /* reset the top session */ _pres_top(sess->user); } /** presence updates from a remote jid - RFC 3921bis 4.3.2. */ void pres_in(user_t user, pkt_t pkt) { sess_t scan; log_debug(ZONE, "type 0x%X presence packet from %s", pkt->type, jid_full(pkt->from)); /* handle probes */ if(pkt->type == pkt_PRESENCE_PROBE) { /* unsubscribed for untrusted users */ if(!pres_trust(user, pkt->from)) { log_debug(ZONE, "unsubscribed untrusted %s", jid_full(pkt->from)); pkt_router(pkt_create(user->sm, "presence", "unsubscribed", jid_full(pkt->from), jid_full(pkt->to))); pkt_free(pkt); return; } /* respond with last unavailable presence if no available session */ if(!user->available) { os_t os; os_object_t o; nad_t nad; pkt_t pres; /* get user last presence stanza */ if(storage_get(user->sm->st, "status", jid_user(user->jid), NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); os_object_get_nad(os, o, "xml", &nad); if(nad != NULL) { pres = pkt_new(pkt->sm, nad_copy(nad)); nad_set_attr(pres->nad, 1, -1, "type", "unavailable", 11); pkt_router(pkt_dup(pres, jid_full(pkt->from), jid_user(user->jid))); pkt_free(pres); } os_free(os); } pkt_free(pkt); return; } } /* loop over each session */ for(scan = user->sessions; scan != NULL; scan = scan->next) { /* don't deliver to unavailable sessions: B4(a) */ if(!scan->available || scan->fake) continue; /* don't deliver to ourselves, lest we presence-bomb ourselves ;) */ if(jid_compare_full(pkt->from, scan->jid) == 0) continue; /* handle probes */ if(pkt->type == pkt_PRESENCE_PROBE) { log_debug(ZONE, "probe from %s for %s", jid_full(pkt->from), jid_full(scan->jid)); /* B3: respond (already checked for T) */ if(pkt->to->resource[0] != '\0') { /* this is a direct probe */ if(jid_compare_full(pkt->to, scan->jid) == 0) { /* respond with simple stanza only */ log_debug(ZONE, "responding with simple presence"); pkt_router(pkt_create(user->sm, "presence", NULL, jid_full(pkt->from), jid_full(pkt->to))); } else continue; } else { log_debug(ZONE, "responding with last presence update"); pkt_router(pkt_dup(scan->pres, jid_full(pkt->from), jid_full(scan->jid))); } /* remove from E */ scan->E = jid_zap(scan->E, pkt->from); continue; } /* deliver to session: B4(b) */ log_debug(ZONE, "forwarding to %s", jid_full(scan->jid)); pkt_sess(pkt_dup(pkt, jid_full(scan->jid), jid_full(pkt->from)), scan); } pkt_free(pkt); } void pres_error(sess_t sess, jid_t jid) { /* bounced updates: B5: add to E, remove from A */ log_debug(ZONE, "bounced presence from %s, adding to error list", jid_full(jid)); sess->E = jid_append(sess->E, jid); sess->A = jid_zap(sess->A, jid); } /** outgoing directed presence */ void pres_deliver(sess_t sess, pkt_t pkt) { if(jid_full(pkt->to) == NULL) { log_debug(ZONE, "invalid jid in directed presence packet"); pkt_free(pkt); return; } if(pkt->type == pkt_PRESENCE) { /* B6: forward, add to A (unless in T), remove from E */ log_debug(ZONE, "delivering directed available presence to %s", jid_full(pkt->to)); if(!pres_trust(sess->user, pkt->to)) sess->A = jid_append(sess->A, pkt->to); sess->E = jid_zap(sess->E, pkt->to); pkt_router(pkt); return; } if(pkt->type == pkt_PRESENCE_UN) { /* B7: forward, remove from A and E */ log_debug(ZONE, "delivering directed unavailable presence to %s", jid_full(pkt->to)); sess->A = jid_zap(sess->A, pkt->to); sess->E = jid_zap(sess->E, pkt->to); pkt_router(pkt); return; } log_debug(ZONE, "don't know how to deliver presence type %d to %s, dropping", pkt->type, jid_full(pkt->to)); pkt_free(pkt); } /** see if the jid is trusted (ie in the roster with s10n="from" or "both") */ int pres_trust(user_t user, jid_t jid) { item_t item = NULL; /* get roster item with bare jid*/ item = xhash_get(user->roster, jid_user(jid)); /* retry with full jid if not found */ if(item == NULL) item = xhash_get(user->roster, jid_full(jid)); /* trusted if they're in the roster and they can see us */ if(item != NULL && item->from) return 1; /* always trust ourselves */ if(jid_compare_user(user->jid, jid) == 0) return 1; return 0; } /** send presence based on roster changes */ void pres_roster(sess_t sess, item_t item) { /* if we're not available, then forget it */ if(!sess->available) return; /* if they were trusted previously, but aren't anymore, and we haven't * explicitly sent them presence, then make them forget */ if(!item->from && !jid_search(sess->A, item->jid) && !jid_search(sess->E, item->jid)) { log_debug(ZONE, "forcing unavailable to %s after roster change", jid_full(item->jid)); pkt_router(pkt_create(sess->user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(sess->jid))); return; } /* if they're now trusted and we haven't sent * them directed presence, then they get to see us for the first time */ if(item->from && !jid_search(sess->A, item->jid) && !jid_search(sess->E, item->jid)) { log_debug(ZONE, "forcing available to %s after roster change", jid_full(item->jid)); pkt_router(pkt_dup(sess->pres, jid_full(item->jid), jid_full(sess->jid))); } } void pres_probe(user_t user) { item_t item; log_debug(ZONE, "full roster probe for %s", jid_user(user->jid)); /* loop the roster, looked for trusted */ if(xhash_iter_first(user->roster)) do { xhash_iter_get(user->roster, NULL, NULL, (void *) &item); /* don't probe unless they trust us */ if(item->to) { log_debug(ZONE, "probing %s", jid_full(item->jid)); pkt_router(pkt_create(user->sm, "presence", "probe", jid_full(item->jid), jid_user(user->jid))); } } while(xhash_iter_next(user->roster)); } �������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/sess.c��������������������������������������������������������������������0000664�0000000�0000000�00000015160�12614627753�0016342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/sess.c * @brief session management * @author Robert Norris * $Date: 2005/07/25 20:38:06 $ * $Revision: 1.37 $ */ /** send a packet to the client for this session */ void sess_route(sess_t sess, pkt_t pkt) { int ns; log_debug(ZONE, "routing pkt 0x%X to %s (%s) for %s", pkt, sess->c2s, sess->c2s_id, jid_full(sess->jid)); if(pkt == NULL) return; /* wrap it up */ ns = nad_append_namespace(pkt->nad, 1, uri_SESSION, "sm"); nad_set_attr(pkt->nad, 1, ns, "c2s", sess->c2s_id, 0); nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0); nad_set_attr(pkt->nad, 0, -1, "to", sess->c2s, 0); nad_set_attr(pkt->nad, 0, -1, "from", sess->user->jid->domain, 0); /* remove error attribute */ nad_set_attr(pkt->nad, 0, -1, "error", NULL, 0); /* and send it out */ sx_nad_write(sess->user->sm->router, pkt->nad); /* free up the packet */ if(pkt->rto != NULL) jid_free(pkt->rto); if(pkt->rfrom != NULL) jid_free(pkt->rfrom); if(pkt->to != NULL) jid_free(pkt->to); if(pkt->from != NULL) jid_free(pkt->from); free(pkt); } static void _sess_end_guts(sess_t sess) { sess_t scan; /* fake an unavailable presence from this session, so that modules and externals know we're gone */ if(sess->available || sess->A != NULL) mm_in_sess(sess->user->sm->mm, sess, pkt_create(sess->user->sm, "presence", "unavailable", NULL, NULL)); /* inform the modules */ mm_sess_end(sess->user->sm->mm, sess); /* unlink it from this users sessions */ if(sess->user->sessions == sess) sess->user->sessions = sess->next; else { for(scan = sess->user->sessions; scan != NULL && scan->next != sess; scan = scan->next); if(scan != NULL) scan->next = sess->next; } /* and from global sessions */ xhash_zap(sess->user->sm->sessions, sess->sm_id); } void sess_end(sess_t sess) { log_debug(ZONE, "shutting down session %s", jid_full(sess->jid)); _sess_end_guts(sess); log_write(sess->user->sm->log, LOG_NOTICE, "session ended: jid=%s", jid_full(sess->jid)); /* if it was the last session, free the user */ if(sess->user->sessions == NULL) { mm_user_unload(sess->user->sm->mm, sess->user); log_write(sess->user->sm->log, LOG_NOTICE, "user unloaded jid=%s", jid_user(sess->jid)); user_free(sess->user); } /* free the session */ pool_free(sess->p); } sess_t sess_start(sm_t sm, jid_t jid) { pool_t p; user_t user; sess_t sess, scan; sha1_state_t sha1; unsigned char hash[20]; int replaced = 0; log_debug(ZONE, "session requested for %s", jid_full(jid)); /* check whether it is to serviced domain */ if(xhash_get(sm->hosts, jid->domain) == NULL) { log_write(sm->log, LOG_ERR, "request to start session in non-serviced domain: jid=%s", jid_full(jid)); return NULL; } /* get user data for this guy */ user = user_load(sm, jid); /* unknown user */ if(user == NULL) { if(config_get(sm->config, "user.auto-create") == NULL) { log_write(sm->log, LOG_NOTICE, "user not found and user.auto-create not enabled, can't start session: jid=%s", jid_full(jid)); return NULL; } log_debug(ZONE, "auto-creating user %s", jid_user(jid)); if(user_create(sm, jid) != 0) return NULL; user = user_load(sm, jid); if(user == NULL) { log_write(sm->log, LOG_NOTICE, "couldn't load user, can't start session: jid=%s", jid_full(jid)); return NULL; } } /* kill their old session if they have one */ for(scan = user->sessions; scan != NULL; scan = scan->next) if(jid_compare_full(scan->jid, jid) == 0) { log_debug(ZONE, "replacing session %s (%s)", jid_full(jid), scan->c2s_id); /* !!! this "replaced" stuff is a hack - its really a subaction of "ended". * hurrah, another control protocol rewrite is needed :( */ sm_c2s_action(scan, "replaced", NULL); _sess_end_guts(scan); pool_free(scan->p); replaced = 1; break; } /* make a new session */ p = pool_new(); sess = (sess_t) pmalloco(p, sizeof(struct sess_st)); sess->p = p; /* fill it out */ sess->pri = 0; sess->user = user; sess->jid = jid_dup(jid); pool_cleanup(sess->p, (void (*))(void *) jid_free, sess->jid); /* a place for modules to store stuff */ sess->module_data = (void **) pmalloco(sess->p, sizeof(void *) * sess->user->sm->mm->nindex); /* add it to the list */ sess->next = user->sessions; user->sessions = sess; /* who c2s should address things to */ sha1_init(&sha1); datetime_out(time(NULL), dt_DATETIME, sess->sm_id, 41); sha1_append(&sha1, sess->sm_id, strlen(sess->sm_id)); sha1_append(&sha1, jid_full(sess->jid), strlen(jid_full(sess->jid))); sha1_finish(&sha1, hash); hex_from_raw(hash, 20, sess->sm_id); log_debug(ZONE, "smid is %s", sess->sm_id); /* remember it */ xhash_put(sm->sessions, sess->sm_id, sess); /* inform the modules */ /* !!! catch the return value - if its 1, don't let them in */ mm_sess_start(sm->mm, sess); if(replaced) log_write(sm->log, LOG_NOTICE, "session replaced: jid=%s", jid_full(sess->jid)); else log_write(sm->log, LOG_NOTICE, "session started: jid=%s", jid_full(sess->jid)); return sess; } /** match a session by resource */ sess_t sess_match(user_t user, const char *resource) { sess_t sess; for(sess = user->sessions; sess != NULL; sess = sess->next) { /* exact matches */ if(strcmp(sess->jid->resource, resource) == 0) return sess; } return NULL; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/sm.c����������������������������������������������������������������������0000664�0000000�0000000�00000031264�12614627753�0016007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/sm.c * @brief stream / io callbacks * @author Robert Norris * $Date: 2005/08/17 07:48:28 $ * $Revision: 1.51 $ */ sig_atomic_t sm_lost_router = 0; /** our master callback */ int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { sm_t sm = (sm_t) arg; sx_buf_t buf = (sx_buf_t) data; sx_error_t *sxe; nad_t nad; pkt_t pkt; int len, ns, elem, attr; char *domain; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(sm->mio, sm->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(sm->mio, sm->fd); break; case event_READ: log_debug(ZONE, "reading from %d", sm->fd->fd); /* do the read */ len = recv(sm->fd->fd, buf->data, buf->len, 0); if (len < 0) { if (MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(sm->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if (len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", sm->fd->fd); len = send(sm->fd->fd, buf->data, buf->len, 0); if (len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if (MIO_WOULDBLOCK) return 0; log_write(sm->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(sm->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific); if(sxe->code == SX_ERR_AUTH) sx_close(s); break; case event_STREAM: break; case event_OPEN: log_write(sm->log, LOG_NOTICE, "connection to router established"); /* set connection attempts counter */ sm->retry_left = sm->retry_lost; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "bind", 0); nad_append_attr(nad, -1, "name", sm->id); log_debug(ZONE, "requesting component bind for '%s'", sm->id); sx_nad_write(sm->router, nad); if(xhash_iter_first(sm->hosts)) do { xhash_iter_get(sm->hosts, (void *) &domain, &len, NULL); /* skip already requested SM id */ if (strlen(sm->id) == len && strncmp(sm->id, domain, len) == 0) continue; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); elem = nad_append_elem(nad, ns, "bind", 0); nad_set_attr(nad, elem, -1, "name", domain, len); nad_append_attr(nad, -1, "multi", "to"); log_debug(ZONE, "requesting domain bind for '%.*s'", len, domain); sx_nad_write(sm->router, nad); } while(xhash_iter_next(sm->hosts)); break; case event_PACKET: nad = (nad_t) data; /* drop unqualified packets */ if (NAD_ENS(nad, 0) < 0) { nad_free(nad); return 0; } /* watch for the features packet */ if (s->state == state_STREAM) { if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) { log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping"); nad_free(nad); return 0; } #ifdef HAVE_SSL /* starttls if we can */ if (sm->sx_ssl != NULL && s->ssf == 0) { ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); if (ns >= 0) { elem = nad_find_elem(nad, 0, ns, "starttls", 1); if (elem >= 0) { if (sx_ssl_client_starttls(sm->sx_ssl, s, NULL, NULL) == 0) { nad_free(nad); return 0; } log_write(sm->log, LOG_NOTICE, "unable to establish encrypted session with router"); } } } #endif /* !!! pull the list of mechanisms, and choose the best one. * if there isn't an appropriate one, error and bail */ /* authenticate */ sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass); nad_free(nad); return 0; } /* watch for the bind response */ if (s->state == state_OPEN && !sm->online) { if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) { log_debug(ZONE, "got a packet from router, but we're not online, dropping"); nad_free(nad); return 0; } /* catch errors */ attr = nad_find_attr(nad, 0, -1, "error", NULL); if(attr >= 0) { log_write(sm->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); exit(1); } log_debug(ZONE, "coming online"); /* we're online */ sm->online = sm->started = 1; log_write(sm->log, LOG_NOTICE, "%s ready for sessions", sm->id); nad_free(nad); return 0; } log_debug(ZONE, "got a packet"); pkt = pkt_new(sm, nad); if (pkt == NULL) { log_debug(ZONE, "invalid packet, dropping"); return 0; } /* go */ dispatch(sm, pkt); return 0; case event_CLOSED: mio_close(sm->mio, sm->fd); sm->fd = NULL; return -1; } return 0; } int sm_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { sm_t sm = (sm_t) arg; int nbytes; switch (a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(sm->router); return 0; } return sx_can_read(sm->router); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(sm->router); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); log_write(sm->log, LOG_NOTICE, "connection to router closed"); sm_lost_router = 1; /* we're offline */ sm->online = 0; break; case action_ACCEPT: break; } return 0; } /** send a new action route */ void sm_c2s_action(sess_t dest, const char *action, const char *target) { nad_t nad; int rns, sns; nad = nad_new(); rns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, rns, "route", 0); nad_append_attr(nad, -1, "to", dest->c2s); nad_append_attr(nad, -1, "from", dest->user->sm->id); sns = nad_add_namespace(nad, uri_SESSION, "sc"); nad_append_elem(nad, sns, "session", 1); if (dest->c2s_id[0] != '\0') nad_append_attr(nad, sns, "c2s", dest->c2s_id); if (dest->sm_id[0] != '\0') nad_append_attr(nad, sns, "sm", dest->sm_id); nad_append_attr(nad, -1, "action", action); if (target != NULL) nad_append_attr(nad, -1, "target", target); log_debug(ZONE, "routing nad to %s from %s c2s %s s2s %s action %s target %s", dest->c2s, dest->user->sm->id, dest->c2s_id, dest->sm_id, action, target); sx_nad_write(dest->user->sm->router, nad); } /** this is gratuitous, but apache gets one, so why not? */ void sm_signature(sm_t sm, const char *str) { if (sm->siglen == 0) { snprintf(&sm->signature[sm->siglen], 2048 - sm->siglen, "%s", str); sm->siglen += strlen(str); } else { snprintf(&sm->signature[sm->siglen], 2048 - sm->siglen, " %s", str); sm->siglen += strlen(str) + 1; } } /** register a new global ns */ int sm_register_ns(sm_t sm, const char *uri) { int ns_idx; ns_idx = (int) (long) xhash_get(sm->xmlns, uri); if (ns_idx == 0) { ns_idx = xhash_count(sm->xmlns) + 2; xhash_put(sm->xmlns, pstrdup(xhash_pool(sm->xmlns), uri), (void *) (long) ns_idx); } xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) + 1)); return ns_idx; } /** unregister a global ns */ void sm_unregister_ns(sm_t sm, const char *uri) { int refcount = (int) (long) xhash_get(sm->xmlns_refcount, uri); if (refcount == 1) { xhash_zap(sm->xmlns, uri); xhash_zap(sm->xmlns_refcount, uri); } else if (refcount > 1) { xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) - 1)); } } /** get a globally registered ns */ int sm_get_ns(sm_t sm, const char *uri) { return (int) (long) xhash_get(sm->xmlns, uri); } // Rate limit check: Prevent denial-of-service due to excessive database queries // Make sure owner is responsible for the query! int sm_storage_rate_limit(sm_t sm, const char *owner) { rate_t rt; user_t user; sess_t sess; item_t item; if (sm->query_rate_total == 0 || owner == NULL) return FALSE; user = xhash_get(sm->users, owner); if (user != NULL) { rt = (rate_t) xhash_get(sm->query_rates, owner); if (rt == NULL) { rt = rate_new(sm->query_rate_total, sm->query_rate_seconds, sm->query_rate_wait); xhash_put(sm->query_rates, pstrdup(xhash_pool(sm->query_rates), owner), (void *) rt); pool_cleanup(xhash_pool(sm->query_rates), (void (*)(void *)) rate_free, rt); } if(rate_check(rt) == 0) { log_write(sm->log, LOG_WARNING, "[%s] is being disconnected, too many database queries within %d seconds", owner, sm->query_rate_seconds); user = xhash_get(sm->users, owner); for (sess = user->sessions; sess != NULL; sess = sess->next) { sm_c2s_action(sess, "ended", NULL); } if(xhash_iter_first(user->roster)) do { xhash_iter_get(user->roster, NULL, NULL, (void *) &item); if(item->to) { pkt_router(pkt_create(user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(user->jid))); } } while(xhash_iter_next(user->roster)); return TRUE; } else { rate_add(rt, 1); } } else { log_debug(ZONE, "Error: could not get user data for %s", owner); } return FALSE; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/sm.h����������������������������������������������������������������������0000664�0000000�0000000�00000051241�12614627753�0016011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * This program is free software; you can redistribute it and/or drvify * 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, MA02111-1307USA */ /** @file sm/sm.h * @brief data structures and prototypes for the session manager * @author Jeremie Miller * @author Robert Norris * $Date: 2005/09/09 05:34:13 $ * $Revision: 1.62 $ */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "sx/sx.h" #include "mio/mio.h" #include "util/util.h" #include "storage/storage.h" #ifdef HAVE_SIGNAL_H #include <signal.h> #endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif #ifdef _WIN32 #ifdef _USRDLL #define DLLEXPORT __declspec(dllexport) #define SM_API __declspec(dllimport) #else #define DLLEXPORT __declspec(dllimport) #define SM_API __declspec(dllexport) #endif #else #define DLLEXPORT #define SM_API #endif /* forward declarations */ typedef struct sm_st *sm_t; typedef struct user_st *user_t; typedef struct sess_st *sess_t; typedef struct aci_st *aci_t; typedef struct mm_st *mm_t; /* namespace uri strings */ #include "util/uri.h" /* indexed known namespace values */ #define ns_AUTH (1) #define ns_REGISTER (2) #define ns_ROSTER (3) #define ns_AGENTS (4) #define ns_DELAY (5) #define ns_BROWSE (6) #define ns_EVENT (7) #define ns_GATEWAY (8) #define ns_EXPIRE (9) #define ns_SEARCH (10) #define ns_DISCO (11) #define ns_DISCO_ITEMS (12) #define ns_DISCO_INFO (13) #define ns_AMP (14) #define ns_AMP_ERRORS (15) #define ns_AMP_ACTION_DROP (16) #define ns_AMP_ACTION_ERROR (17) #define ns_AMP_ACTION_NOTIFY (18) #define ns_AMP_CONDITION_DELIVER (19) #define ns_AMP_CONDITION_EXPIREAT (20) #define ns_AMP_CONDITION_MATCHRESOURCE (21) /** packet types */ typedef enum { pkt_NONE = 0x00, /**< no packet */ pkt_MESSAGE = 0x10, /**< message */ pkt_MESSAGE_CHAT = 0x11, /**< message (chat) */ pkt_MESSAGE_HEADLINE = 0x12,/**< message (headline) */ pkt_MESSAGE_GROUPCHAT = 0x14,/**< message (groupchat) */ pkt_PRESENCE = 0x20, /**< presence */ pkt_PRESENCE_UN = 0x21, /**< presence (unavailable) */ pkt_PRESENCE_PROBE = 0x24, /**< presence (probe) */ pkt_S10N = 0x40, /**< subscribe request */ pkt_S10N_ED = 0x41, /**< subscribed response */ pkt_S10N_UN = 0x42, /**< unsubscribe request */ pkt_S10N_UNED = 0x44, /**< unsubscribed response */ pkt_IQ = 0x80, /**< info/query (get) */ pkt_IQ_SET = 0x81, /**< info/query (set) */ pkt_IQ_RESULT = 0x82, /**< info/query (result) */ pkt_SESS = 0x100, /**< session start request */ pkt_SESS_END = 0x101, /**< session end request */ pkt_SESS_CREATE = 0x102, /**< session create request */ pkt_SESS_DELETE = 0x104, /**< session delete request */ pkt_SESS_FAILED = 0x08, /**< session request failed (mask) */ pkt_SESS_MASK = 0x10f, /**< session request (mask) */ pkt_ERROR = 0x200 /**< packet error */ } pkt_type_t; /** route types */ typedef enum { route_NONE = 0x00, /**< no route */ route_UNICAST = 0x10, /**< unicast */ route_BROADCAST = 0x11, /**< broadcast */ route_ADV = 0x20, /**< advertisement (available) */ route_ADV_UN = 0x21, /**< advertisement (unavailable) */ route_ERROR = 0x40 /**< route error */ } route_type_t; /** packet summary data wrapper */ typedef struct pkt_st { sm_t sm; /**< sm context */ sess_t source; /**< session this packet came from */ jid_t rto, rfrom; /**< addressing of enclosing route */ route_type_t rtype; /**< type of enclosing route */ pkt_type_t type; /**< packet type */ jid_t to, from; /**< packet addressing (not used for routing) */ int ns; /**< iq sub-namespace */ int pri; /**< presence priority */ nad_t nad; /**< nad of the entire packet */ } *pkt_t; /** roster items */ typedef struct item_st { jid_t jid; /**< id of this item */ const char *name; /**< display name */ const char **groups; /**< groups this item is in */ int ngroups; /**< number of groups in groups array */ int to, from; /**< subscription to this item (they get presence FROM us, they send presence TO us) */ int ask; /**< pending subscription (0 == none, 1 == subscribe, 2 == unsubscribe) */ int ver; /**< roster item version number */ } *item_t; /** session manager global context */ struct sm_st { const char *id; /**< component id */ const char *router_ip; /**< ip to connect to the router at */ int router_port; /**< port to connect to the router at */ const char *router_user; /**< username to authenticate to the router as */ const char *router_pass; /**< password to authenticate to the router with */ const char *router_pemfile; /**< name of file containing a SSL certificate & key for channel to the router */ const char *router_private_key_password; /** password for private key if pemfile key is encrypted */ const char *router_ciphers; /** TLS ciphers */ mio_t mio; /**< mio context */ sx_env_t sx_env; /**< SX environment */ sx_plugin_t sx_sasl; /**< SX SASL plugin */ sx_plugin_t sx_ssl; /**< SX SSL plugin */ sx_t router; /**< SX of router connection */ mio_fd_t fd; /**< file descriptor of router connection */ xht users; /**< pointers to currently loaded users (key is user@@domain) */ xht sessions; /**< pointers to all connected sessions (key is random sm id) */ xht xmlns; /**< index of namespaces (for iq sub-namespace in pkt_t) */ xht xmlns_refcount; /**< ref-counting for modules namespaces */ xht features; /**< feature index (key is feature string */ config_t config; /**< config context */ log_t log; /**< log context */ log_type_t log_type; /**< log type */ const char *log_facility; /**< syslog facility (local0 - local7) */ const char *log_ident; /**< log identifier */ int retry_init; /**< number of times to try connecting to the router at startup */ int retry_lost; /**< number of times to try reconnecting to the router if the connection drops */ int retry_sleep; /**< sleep interval between retries */ int retry_left; /**< number of tries left before failure */ storage_t st; /**< storage subsystem */ mm_t mm; /**< module subsystem */ xht acls; /**< access control lists (key is list name, value is jid_t list) */ char signature[2048]; /**< server signature */ int siglen; /**< length of signature */ int started; /**< true if we've connected to the router at least once */ int online; /**< true if we're currently bound in the router */ xht hosts; /**< vHosts map */ /** Database query rate limits */ int query_rate_total; int query_rate_seconds; int query_rate_wait; xht query_rates; }; /** data for a single user */ struct user_st { pool_t p; /**< memory pool this user is allocated off */ sm_t sm; /**< sm context */ jid_t jid; /**< user jid (user@@host) */ xht roster; /**< roster for this user (key is full jid of item, value is item_t) */ sess_t sessions; /**< list of action sessions */ sess_t top; /**< top priority session */ int available; /**< true if this user has any available session */ time_t active; /**< time that user first logged in (ever) */ void **module_data; /**< per-user module data */ }; /** data for a single session */ struct sess_st { pool_t p; /**< memory pool this session is allocated off */ user_t user; /**< user this session belongs to */ jid_t jid; /**< session jid (user@@host/res) */ char c2s[1024]; /**< id of c2s that is handling their connection */ char sm_id[41]; /**< local id (for session control) */ char c2s_id[44]; /**< remote id (for session control) */ pkt_t pres; /**< copy of the last presence packet we received */ int available; /**< true if this session is available */ int pri; /**< current priority of this session */ int fake; /**< true if session is fake (ie. PBX) */ jid_t A; /**< list of jids that this session has sent directed presence to */ jid_t E; /**< list of jids that bounced presence updates we sent them */ void **module_data; /**< per-session module data */ sess_t next; /**< next session (in a list of sessions) */ }; extern sig_atomic_t sm_lost_router; /* functions */ SM_API xht aci_load(sm_t sm); SM_API int aci_check(xht acls, const char *type, jid_t jid); SM_API void aci_unload(xht acls); SM_API int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg); SM_API int sm_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg); SM_API void sm_timestamp(time_t t, char timestamp[18]); SM_API void sm_c2s_action(sess_t dest, const char *action, const char *target); SM_API void sm_signature(sm_t sm, const char *str); SM_API int sm_register_ns(sm_t sm, const char *uri); SM_API void sm_unregister_ns(sm_t sm, const char *uri); SM_API int sm_get_ns(sm_t sm, const char *uri); SM_API int sm_storage_rate_limit(sm_t sm, const char *owner); SM_API void dispatch(sm_t sm, pkt_t pkt); SM_API pkt_t pkt_error(pkt_t pkt, int err); SM_API pkt_t pkt_tofrom(pkt_t pkt); SM_API pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from); SM_API pkt_t pkt_new(sm_t sm, nad_t nad); SM_API void pkt_free(pkt_t pkt); SM_API pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from); SM_API void pkt_id(pkt_t src, pkt_t dest); SM_API void pkt_id_new(pkt_t pkt); SM_API void pkt_delay(pkt_t pkt, time_t t, const char *from); SM_API void pkt_router(pkt_t pkt); SM_API void pkt_sess(pkt_t pkt, sess_t sess); SM_API int pres_trust(user_t user, jid_t jid); SM_API void pres_roster(sess_t sess, item_t item); SM_API void pres_update(sess_t sess, pkt_t pres); SM_API void pres_error(sess_t sess, jid_t jid); SM_API void pres_deliver(sess_t sess, pkt_t pres); SM_API void pres_in(user_t user, pkt_t pres); SM_API void pres_probe(user_t user); SM_API void sess_route(sess_t sess, pkt_t pkt); SM_API sess_t sess_start(sm_t sm, jid_t jid); SM_API void sess_end(sess_t sess); SM_API sess_t sess_match(user_t user, const char *resource); SM_API user_t user_load(sm_t sm, jid_t jid); SM_API void user_free(user_t user); SM_API int user_create(sm_t sm, jid_t jid); SM_API void user_delete(sm_t sm, jid_t jid); SM_API void feature_register(sm_t sm, const char *feature); SM_API void feature_unregister(sm_t sm, const char *feature); /* driver module manager */ /** module return values */ typedef enum { mod_HANDLED, /**< packet was handled (and freed) */ mod_PASS /**< packet was unhandled, should be passed to the next module */ } mod_ret_t; /** module chain types */ typedef enum { chain_SESS_START, /**< session start, load per-session data */ chain_SESS_END, /**< session ended, save & free per-session data */ chain_IN_SESS, /**< packet from an active session */ chain_IN_ROUTER, /**< packet from the router */ chain_OUT_SESS, /**< packet to an active session */ chain_OUT_ROUTER, /**< packet to a router */ chain_PKT_SM, /**< packet for the sm itself */ chain_PKT_USER, /**< packet for a user */ chain_PKT_ROUTER, /**< packet from the router (special purpose) */ chain_USER_LOAD, /**< user loaded, load per-user data */ chain_USER_CREATE, /**< user creation, generate and save per-user data */ chain_USER_DELETE, /**< user deletion, delete saved per-user data */ chain_USER_UNLOAD, /**< user is about to be unloaded */ chain_DISCO_EXTEND /**< disco request, extend sm disco#info */ } mod_chain_t; typedef struct module_st *module_t; typedef struct mod_instance_st *mod_instance_t; /** module manager data */ struct mm_st { sm_t sm; /**< sm context */ xht modules; /**< pointers to module data (key is module name) */ int nindex; /**< counter for module instance sequence (!!! should be local to mm_new) */ /** sess-start chain */ mod_instance_t *sess_start; int nsess_start; /** sess-end chain */ mod_instance_t *sess_end; int nsess_end; /** in-sess chain */ mod_instance_t *in_sess; int nin_sess; /** in-router chain */ mod_instance_t *in_router; int nin_router; /** out-sess chain */ mod_instance_t *out_sess; int nout_sess; /** out-router chain */ mod_instance_t *out_router; int nout_router; /** pkt-sm chain */ mod_instance_t *pkt_sm; int npkt_sm; /** pkt-user chain */ mod_instance_t *pkt_user; int npkt_user; /** pkt-router chain */ mod_instance_t *pkt_router; int npkt_router; /** user-load chain */ mod_instance_t *user_load; int nuser_load; /** user-create chain */ mod_instance_t *user_create; int nuser_create; /** user-delete chain */ mod_instance_t *user_delete; int nuser_delete; /** disco-extend chain */ mod_instance_t *disco_extend; int ndisco_extend; /** user-unload chain */ mod_instance_t *user_unload; int nuser_unload; }; /** data for a single module */ struct module_st { mm_t mm; /**< module manager */ const char *name; /**< name of module */ int index; /**< module index. this is the index into user->module_data and sess->module_data where the module can store its own per-user/per-session data */ void *handle; /**< module handle */ int (*module_init_fn)(mod_instance_t); /**< module init function */ int init; /**< number of times the module intialiser has been called */ void *private; /**< module private data */ int (*sess_start)(mod_instance_t mi, sess_t sess); /**< sess-start handler */ void (*sess_end)(mod_instance_t mi, sess_t sess); /**< sess-end handler */ mod_ret_t (*in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt); /**< in-sess handler */ mod_ret_t (*in_router)(mod_instance_t mi, pkt_t pkt); /**< in-router handler */ mod_ret_t (*out_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt); /**< out-sess handler */ mod_ret_t (*out_router)(mod_instance_t mi, pkt_t pkt); /**< out-router handler */ mod_ret_t (*pkt_sm)(mod_instance_t mi, pkt_t pkt); /**< pkt-sm handler */ mod_ret_t (*pkt_user)(mod_instance_t mi, user_t user, pkt_t pkt); /**< pkt-user handler */ mod_ret_t (*pkt_router)(mod_instance_t mi, pkt_t pkt); /**< pkt-router handler */ int (*user_load)(mod_instance_t mi, user_t user); /**< user-load handler */ int (*user_unload)(mod_instance_t mi, user_t user); /**< user-load handler */ int (*user_create)(mod_instance_t mi, jid_t jid); /**< user-create handler */ void (*user_delete)(mod_instance_t mi, jid_t jid); /**< user-delete handler */ void (*disco_extend)(mod_instance_t mi, pkt_t pkt); /**< disco-extend handler */ void (*free)(module_t mod); /**< called when module is freed */ }; /** single instance of a module in a chain */ struct mod_instance_st { sm_t sm; /**< sm context */ module_t mod; /**< module that this is an instance of */ int seq; /**< number of this instance */ mod_chain_t chain; /**< chain this instance is in */ const char *arg; /**< option arg that this instance was started with */ }; /** allocate a module manager instance, and loads the modules */ SM_API mm_t mm_new(sm_t sm); /** free a mm instance */ SM_API void mm_free(mm_t mm); /** fire sess-start chain */ SM_API int mm_sess_start(mm_t mm, sess_t sess); /** fire sess-end chain */ SM_API void mm_sess_end(mm_t mm, sess_t sess); /** fire in-sess chain */ SM_API mod_ret_t mm_in_sess(mm_t mm, sess_t sess, pkt_t pkt); /** fire in-router chain */ SM_API mod_ret_t mm_in_router(mm_t mm, pkt_t pkt); /** fire out-sess chain */ SM_API mod_ret_t mm_out_sess(mm_t mm, sess_t sess, pkt_t pkt); /** fire out-router chain */ SM_API mod_ret_t mm_out_router(mm_t mm, pkt_t pkt); /** fire pkt-sm chain */ SM_API mod_ret_t mm_pkt_sm(mm_t mm, pkt_t pkt); /** fire pkt-user chain */ SM_API mod_ret_t mm_pkt_user(mm_t mm, user_t user, pkt_t pkt); /** fire pkt-router chain */ SM_API mod_ret_t mm_pkt_router(mm_t mm, pkt_t pkt); /** fire user-load chain */ SM_API int mm_user_load(mm_t mm, user_t user); /** fire user-unload chain */ SM_API int mm_user_unload(mm_t mm, user_t user); /** fire user-create chain */ SM_API int mm_user_create(mm_t mm, jid_t jid); /** fire user-delete chain */ SM_API void mm_user_delete(mm_t mm, jid_t jid); /** fire disco-extend chain */ SM_API void mm_disco_extend(mm_t mm, pkt_t pkt); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sm/user.c��������������������������������������������������������������������0000664�0000000�0000000�00000010031�12614627753�0016333�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sm.h" /** @file sm/user.c * @brief user management * @author Robert Norris * $Date: 2005/06/02 04:48:25 $ * $Revision: 1.23 $ */ /** make a new one */ static user_t _user_alloc(sm_t sm, jid_t jid) { pool_t p; user_t user; p = pool_new(); user = (user_t) pmalloco(p, sizeof(struct user_st)); user->p = p; user->sm = sm; user->jid = jid_dup(jid); pool_cleanup(p, (void (*)(void *)) jid_free, user->jid); /* a place for modules to store stuff */ user->module_data = (void **) pmalloco(p, sizeof(void *) * sm->mm->nindex); return user; } /** fetch user data */ user_t user_load(sm_t sm, jid_t jid) { user_t user; /* already loaded */ user = xhash_get(sm->users, jid_user(jid)); if(user != NULL) { log_debug(ZONE, "returning previously-created user data for %s", jid_user(jid)); return user; } /* make a new one */ user = _user_alloc(sm, jid); /* get modules to setup */ if(mm_user_load(sm->mm, user) != 0) { log_debug(ZONE, "modules failed user load for %s", jid_user(jid)); pool_free(user->p); return NULL; } /* save them for later */ xhash_put(sm->users, jid_user(user->jid), (void *) user); log_debug(ZONE, "loaded user data for %s", jid_user(jid)); return user; } void user_free(user_t user) { log_debug(ZONE, "freeing user %s", jid_user(user->jid)); xhash_zap(user->sm->users, jid_user(user->jid)); pool_free(user->p); } /** initialise a user */ int user_create(sm_t sm, jid_t jid) { user_t user; log_debug(ZONE, "create user request for %s", jid_user(jid)); /* check whether it is to serviced domain */ if(xhash_get(sm->hosts, jid->domain) == NULL) { log_write(sm->log, LOG_ERR, "request to create user for non-serviced domain: jid=%s", jid_user(jid)); log_debug(ZONE, "no such domain, not creating"); return 1; } user = user_load(sm, jid); if(user != NULL) { log_write(sm->log, LOG_ERR, "request to create already-active user: jid=%s", jid_user(jid)); log_debug(ZONE, "user already active, not creating"); return 1; } /* modules create */ if(mm_user_create(sm->mm, jid) != 0) { log_write(sm->log, LOG_ERR, "user creation failed: jid=%s", jid_user(jid)); log_debug(ZONE, "user create failed, forcing deletion for cleanup"); mm_user_delete(sm->mm, jid); return 1; } log_write(sm->log, LOG_NOTICE, "created user: jid=%s", jid_user(jid)); return 0; } /** trash a user */ void user_delete(sm_t sm, jid_t jid) { user_t user; sess_t scan, next; log_debug(ZONE, "delete user request for %s", jid_user(jid)); user = user_load(sm, jid); if(user == NULL) { log_debug(ZONE, "user doesn't exist, can't delete"); return; } /* close their sessions first (this will free user, after the last session ends) */ scan = user->sessions; while(scan != NULL) { next = scan->next; sm_c2s_action(scan, "ended", NULL); sess_end(scan); scan = next; } mm_user_delete(sm->mm, jid); log_write(sm->log, LOG_NOTICE, "deleted user: jid=%s", jid_user(jid)); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/���������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016243�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/Makefile.am����������������������������������������������������������0000664�0000000�0000000�00000007620�12614627753�0020304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������EXTRA_DIST = authreg_ntlogon.c authreg_sspi.c AM_CFLAGS = -I$(top_srcdir)/c2s -I@top_srcdir@ LIBTOOL += --quiet MODULE_LDFLAGS = -module -avoid-version MODULE_LIBADD = -lexpat -L$(top_srcdir)/util pkglib_LTLIBRARIES = pkglib_LTLIBRARIES += libstorage.la libstorage_la_SOURCES = storage.h storage.c object.c libstorage_la_CPPFLAGS = -DLIBRARY_DIR=\"$(pkglibdir)\" if STORAGE_ANON pkglib_LTLIBRARIES += authreg_anon.la authreg_anon_la_SOURCES = authreg_anon.c authreg_anon_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_anon_la_LIBADD = $(MODULE_LIBADD) endif if STORAGE_DB pkglib_LTLIBRARIES += authreg_db.la storage_db.la authreg_db_la_SOURCES = authreg_db.c authreg_db_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_db_la_LIBADD = $(MODULE_LIBADD) $(DB_LIBS) storage_db_la_SOURCES = storage_db.c storage_db_la_LDFLAGS = $(MODULE_LDFLAGS) storage_db_la_LIBADD = $(MODULE_LIBADD) $(DB_LIBS) ../util/libutil.la endif if STORAGE_FS pkglib_LTLIBRARIES += storage_fs.la storage_fs_la_SOURCES = storage_fs.c storage_fs_la_LDFLAGS = $(MODULE_LDFLAGS) storage_fs_la_LIBADD = $(MODULE_LIBADD) endif if STORAGE_LDAP pkglib_LTLIBRARIES += authreg_ldap.la authreg_ldapfull.la storage_ldapvcard.la authreg_ldap_la_SOURCES = authreg_ldap.c authreg_ldap_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_ldap_la_LIBADD = $(MODULE_LIBADD) $(LDAP_LIBS) authreg_ldapfull_la_SOURCES = authreg_ldapfull.c authreg_ldapfull_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_ldapfull_la_LIBADD = $(MODULE_LIBADD) $(LDAP_LIBS) storage_ldapvcard_la_SOURCES = storage_ldapvcard.c storage_ldapvcard_la_LDFLAGS = $(MODULE_LDFLAGS) storage_ldapvcard_la_LIBADD = $(MODULE_LIBADD) $(LDAP_LIBS) ../util/libutil.la endif if STORAGE_MYSQL pkglib_LTLIBRARIES += authreg_mysql.la storage_mysql.la authreg_mysql_la_SOURCES = authreg_mysql.c authreg_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS) authreg_mysql_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_mysql_la_LIBADD = $(MODULE_LIBADD) $(MYSQL_LIBS) ../util/libutil.la if HAVE_CRYPT authreg_mysql_la_LIBADD += -lcrypt endif storage_mysql_la_SOURCES = storage_mysql.c storage_mysql_la_CPPFLAGS = $(MYSQL_CFLAGS) storage_mysql_la_LDFLAGS = $(MODULE_LDFLAGS) storage_mysql_la_LIBADD = $(MODULE_LIBADD) $(MYSQL_LIBS) endif if STORAGE_ORACLE pkglib_LTLIBRARIES += authreg_oracle.la storage_oracle.la authreg_oracle_la_SOURCES = authreg_oracle.c authreg_oracle_la_CPPFLAGS = $(ORACLE_CPPFLAGS) authreg_oracle_la_LDFLAGS = $(MODULE_LDFLAGS) $(ORACLE_LDFLAGS) authreg_oracle_la_LIBADD = $(MODULE_LIBADD) $(ORACLE_LIBS) storage_oracle_la_SOURCES = storage_oracle.c storage_oracle_la_CPPFLAGS = $(ORACLE_CPPFLAGS) storage_oracle_la_LDFLAGS = $(MODULE_LDFLAGS) $(ORACLE_LDFLAGS) storage_oracle_la_LIBADD = $(MODULE_LIBADD) $(ORACLE_LIBS) endif if STORAGE_PAM pkglib_LTLIBRARIES += authreg_pam.la authreg_pam_la_SOURCES = authreg_pam.c authreg_pam_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_pam_la_LIBADD = $(MODULE_LIBADD) $(PAM_LIBS) endif if STORAGE_PGSQL pkglib_LTLIBRARIES += authreg_pgsql.la storage_pgsql.la authreg_pgsql_la_SOURCES = authreg_pgsql.c authreg_pgsql_la_CPPFLAGS = $(PGSQL_CFLAGS) authreg_pgsql_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_pgsql_la_LIBADD = $(MODULE_LIBADD) $(PGSQL_LIBS) ../util/libutil.la storage_pgsql_la_SOURCES = storage_pgsql.c storage_pgsql_la_CPPFLAGS = $(PGSQL_CFLAGS) storage_pgsql_la_LDFLAGS = $(MODULE_LDFLAGS) storage_pgsql_la_LIBADD = $(MODULE_LIBADD) $(PGSQL_LIBS) endif if STORAGE_PIPE pkglib_LTLIBRARIES += authreg_pipe.la authreg_pipe_la_SOURCES = authreg_pipe.c authreg_pipe_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_pipe_la_LIBADD = $(MODULE_LIBADD) ../util/libutil.la endif if STORAGE_SQLITE pkglib_LTLIBRARIES += authreg_sqlite.la storage_sqlite.la authreg_sqlite_la_SOURCES = authreg_sqlite.c authreg_sqlite_la_LDFLAGS = $(MODULE_LDFLAGS) authreg_sqlite_la_LIBADD = $(MODULE_LIBADD) $(SQLITE_LIBS) storage_sqlite_la_SOURCES = storage_sqlite.c storage_sqlite_la_LDFLAGS = $(MODULE_LDFLAGS) storage_sqlite_la_LIBADD = $(MODULE_LIBADD) $(SQLITE_LIBS) endif ����������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_anon.c�������������������������������������������������������0000664�0000000�0000000�00000002436�12614627753�0021066�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this is a simple anonymous plugin. It uses the check_password method to * force authentication to succeed regardless of what credentials the client * provides */ #include "c2s.h" static int _ar_anon_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { /* always exists */ return 1; } /** start me up */ DLLEXPORT int ar_init(authreg_t ar) { ar->user_exists = _ar_anon_user_exists; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_db.c���������������������������������������������������������0000664�0000000�0000000�00000021712�12614627753�0020516�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this module uses the Berkeley DB v4 (db4) to store the auth credentials */ /* * !!! we must catch DB_RUNRECOVERY and call _ar_db_panic(). I would argue that * Berkeley should do this for all cases, not just for the process that * caused the fault, but I'm not sure they see it that way. (I have asked, * just waiting for a reply) * * Sleepycat SR#7019 resolved this. There is an unreleased patch available * (I have a copy) that will be in 4.2 (due in June). */ #include "c2s.h" #include <db.h> /** internal structure, holds auth credentials for one user */ typedef struct creds_st { char username[257]; char realm[257]; char password[257]; } *creds_t; /** internal structure, holds our data */ typedef struct moddata_st { DB_ENV *env; const char *path; int sync; xht realms; DB *def_realm; } *moddata_t; /** open/create the database for this realm */ static DB *_ar_db_get_realm_db(authreg_t ar, const char *realm) { moddata_t data = (moddata_t) ar->private; DB *db; int err; if(realm[0] == '\0') db = data->def_realm; else db = xhash_get(data->realms, realm); if(db != NULL) return db; log_debug(ZONE, "creating new db handle for realm '%s'", realm); err = db_create(&db, data->env, 0); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't create db: %s", db_strerror(err)); return NULL; } err = db->open(db, NULL, "authreg.db", realm, DB_HASH, DB_CREATE, 0); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't open db for realm '%s': %s", realm, db_strerror(err)); db->close(db, 0); return NULL; } if(realm[0] == '\0') data->def_realm = db; else xhash_put(data->realms, pstrdup(xhash_pool(data->realms), realm), (void *) db); log_debug(ZONE, "db for realm '%s' is online", realm); return db; } /** pull a user out of the db */ static creds_t _ar_db_fetch_user(authreg_t ar, const char *username, const char *realm) { DB *db; DBT key, val; int err; creds_t creds; log_debug(ZONE, "fetching auth creds for user '%s' realm '%s'", username, realm); db = _ar_db_get_realm_db(ar, realm); if(db == NULL) return NULL; memset(&key, 0, sizeof(DBT)); memset(&val, 0, sizeof(DBT)); key.data = (void*)username; key.size = strlen(username); err = db->get(db, NULL, &key, &val, 0); if(err == 0) creds = (creds_t) val.data; else if(err == DB_NOTFOUND) creds = NULL; else { log_write(ar->c2s->log, LOG_ERR, "db: couldn't fetch auth creds for user '%s' (realm '%s'): %s", username, realm, db_strerror(err)); return NULL; } log_debug(ZONE, "auth creds: 0x%4X", creds); return creds; } /** store the user into the db */ static int _ar_db_store_user(authreg_t ar, creds_t creds) { moddata_t data = (moddata_t) ar->private; DB *db; DBT key, val; int err; log_debug(ZONE, "storing auth creds for user '%s' realm '%s'", creds->username, creds->realm); db = _ar_db_get_realm_db(ar, creds->realm); if(db == NULL) return 1; memset(&key, 0, sizeof(DBT)); memset(&val, 0, sizeof(DBT)); key.data = creds->username; key.size = strlen(creds->username); val.data = creds; val.size = sizeof(struct creds_st); err = db->put(db, NULL, &key, &val, 0); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't store auth creds for user '%s' (realm '%s'): %s", creds->username, creds->realm, db_strerror(err)); return 1; } if(data->sync) db->sync(db, 0); return 0; } static int _ar_db_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { return (int) (long) _ar_db_fetch_user(ar, username, realm); } static int _ar_db_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { creds_t creds; if((creds = _ar_db_fetch_user(ar, username, realm)) == NULL) return 1; strcpy(password, creds->password); return 0; } static int _ar_db_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { creds_t creds; if((creds = _ar_db_fetch_user(ar, username, realm)) == NULL) return 1; strcpy(creds->password, password); if(_ar_db_store_user(ar, creds) != 0) return 1; return 0; } static int _ar_db_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { creds_t creds; int ret; if((creds = _ar_db_fetch_user(ar, username, realm)) != NULL) return 1; creds = (creds_t) calloc(1, sizeof(struct creds_st)); strcpy(creds->username, username); strcpy(creds->realm, realm); ret = _ar_db_store_user(ar, creds); free(creds); return ret; } static int _ar_db_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { DB *db; DBT key; int err; if(_ar_db_fetch_user(ar, username, realm) == NULL) return 1; db = _ar_db_get_realm_db(ar, realm); if(db == NULL) return 1; memset(&key, 0, sizeof(DBT)); key.data = (void*)username; key.size = strlen(username); err = db->del(db, NULL, &key, 0); if(err != 0) log_write(ar->c2s->log, LOG_ERR, "db: couldn't delete auth creds for user '%s' (realm '%s'): %s", username, realm, db_strerror(err)); return err; } static void _ar_db_free_walker(const char *key, int keylen, void *val, void *arg) { DB *db = (DB *) val; log_debug(ZONE, "closing '%.*s' db", keylen, key); db->close(db, 0); } static void _ar_db_free(authreg_t ar) { DB_ENV *env; moddata_t data = (moddata_t) ar->private; log_debug(ZONE, "db module shutting down"); xhash_walk(data->realms, _ar_db_free_walker, NULL); xhash_free(data->realms); data->env->close(data->env, 0); /* remove db environment files if no longer required */ if (db_env_create(&env, 0) == 0) env->remove(env, data->path, 0); free(data); } /** panic function */ static void _ar_db_panic(DB_ENV *env, int errval) { log_t log = (log_t) env->app_private; log_write(log, LOG_CRIT, "db: corruption detected! close all jabberd processes and run db_recover"); exit(2); } /** start me up */ int ar_init(authreg_t ar) { const char *path; int err; DB_ENV *env; moddata_t data; path = config_get_one(ar->c2s->config, "authreg.db.path", 0); if(path == NULL) { log_write(ar->c2s->log, LOG_ERR, "db: no authreg path specified in config file"); return 1; } err = db_env_create(&env, 0); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't create environment: %s", db_strerror(err)); return 1; } err = env->set_paniccall(env, _ar_db_panic); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't set panic call: %s", db_strerror(err)); return 1; } /* store the log context in case we panic */ env->app_private = ar->c2s->log; err = env->set_flags(env, DB_AUTO_COMMIT, 1); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't set environment for automatic transaction commit: %s", db_strerror(err)); env->close(env, 0); return 1; } err = env->open(env, path, DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN | DB_CREATE, 0); if(err != 0) { log_write(ar->c2s->log, LOG_ERR, "db: couldn't open environment: %s", db_strerror(err)); env->close(env, 0); return 1; } data = (moddata_t) calloc(1, sizeof(struct moddata_st)); data->env = env; data->path = path; if(config_get_one(ar->c2s->config, "authreg.db.sync", 0) != NULL) data->sync = 1; data->realms = xhash_new(51); ar->private = data; ar->user_exists = _ar_db_user_exists; ar->get_password = _ar_db_get_password; ar->set_password = _ar_db_set_password; ar->create_user = _ar_db_create_user; ar->delete_user = _ar_db_delete_user; ar->free = _ar_db_free; return 0; } ������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_ldap.c�������������������������������������������������������0000664�0000000�0000000�00000044025�12614627753�0021053�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this plugin authenticates against an LDAP directory by attempting to bind * as the user. It won't store or retrieve any actual data, so only the * plaintext mechanism is available. * * !!! this doesn't do any caching. It really should. * * !!! this blocks for every auth. We're stuck with this until authreg can * return a pending state. The timeout helps, but its still icky. */ #include "c2s.h" #include <stddef.h> #include <lber.h> #define LDAP_DEPRECATED 1 #include <ldap.h> #define AR_LDAP_FLAGS_NONE (0x0) #define AR_LDAP_FLAGS_STARTTLS (0x1) #define AR_LDAP_FLAGS_SSL (0x2) #define AR_LDAP_FLAGS_V3 (0x4) #define AR_LDAP_FLAGS_RECONNECT (0x8) #define AR_LDAP_FLAGS_DISABLE_REFERRALS (0x10) #define AR_LDAP_FLAGS_APPEND_REALM (0x20) typedef enum uidattr_order_e { AR_LDAP_UAO_UNUSED, AR_LDAP_UAO_USERNAME_DOMAIN, AR_LDAP_UAO_DOMAIN_USERNAME, AR_LDAP_UAO_USERNAME } uidattr_order_t; /** internal structure, holds our data */ typedef struct moddata_st { authreg_t ar; LDAP *ld; const char *host; long port; int flags; int timeout; const char *binddn; const char *bindpw; const char *uidattr; const char *query; uidattr_order_t uidattr_order; xht basedn; const char *default_basedn; } *moddata_t; /** utility function to get ld_errno */ static int _ldap_get_lderrno(LDAP *ld) { int ld_errno; ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno); return ld_errno; } /** utility function to generate a printf format string from a "%u@%r" configuration string * accepted user parameters are %u for username and %r for realm/domain. * * \params uidattr_fmt a string containing %u for username and possibly %r for realm. This string will be modified to replace %u and %r with %s * \params order a returned value saying whether the username appears alone, before domain, or after domain * * \return 1 for error * * \warning We do not clean up the supplied string. As this is a configuration parameter * and not a user-supplied string the risk is considered limited, but still exists */ static int _create_user_filter(moddata_t data) { char *pos_u; char *pos_d; ptrdiff_t u_d_diff; if (data->query == NULL) { data->uidattr_order = AR_LDAP_UAO_UNUSED; return 1; } pos_u = strstr(data->query, "%u"); if (pos_u == NULL) { data->uidattr_order = AR_LDAP_UAO_UNUSED; return 1; } pos_u[1] = 's'; pos_d = strstr(data->query, "%r"); if (pos_d != NULL) pos_d[1] = 's'; u_d_diff = pos_u - pos_d; if (u_d_diff == (ptrdiff_t)pos_u) { data->uidattr_order = AR_LDAP_UAO_USERNAME; return 0; } else { if (u_d_diff > 0) { data->uidattr_order = AR_LDAP_UAO_DOMAIN_USERNAME; return 0; } else { data->uidattr_order = AR_LDAP_UAO_USERNAME_DOMAIN; return 0; } } /* shouldn't arrive here */ data->uidattr_order = AR_LDAP_UAO_UNUSED; return 1; } /** entry-point function for following referrals, required in some cases by Active Directory */ static int rebindProc(LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *mdata) { moddata_t data = mdata; data->ld = ld; if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: bind failed (to %s): %s", url, ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; // return NULL; // TODO FIXME Wrong: It is the same as LDAP_SUCCESS return LDAP_OPERATIONS_ERROR;// TODO check if it is correct } return LDAP_SUCCESS; } /** connect to the ldap host */ static int _ldap_connect(moddata_t data) { char url[1024]; int version = (data->flags & AR_LDAP_FLAGS_V3) ? 3 : 2; struct timeval timeout = {data->timeout,0}; /* ssl "wrappermode" */ if(data->flags & AR_LDAP_FLAGS_SSL) { snprintf(url, sizeof(url), "ldaps://%s:%ld", data->host, data->port); // TODO FIXME data->port shall be at most 'unsigned int' ldap_initialize(&data->ld, url); } /* non-SSL connect method */ else data->ld = ldap_init(data->host, data->port); if(data->ld != NULL) { /* explicitly set ldap version for all connections */ if(ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &version)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't use version %d: %s", version, ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return 1; } /* starttls */ if(data->flags & AR_LDAP_FLAGS_STARTTLS) { if(ldap_start_tls_s(data->ld, NULL, NULL)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't start TLS: %s", ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return 1; } } /* referrals */ if(data->flags & AR_LDAP_FLAGS_DISABLE_REFERRALS) { if( ldap_set_option( data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS ) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set Referrals Off: %s", ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return 1; } } /* timeout */ if( ldap_set_option( data->ld, LDAP_OPT_NETWORK_TIMEOUT, &timeout ) != LDAP_OPT_SUCCESS || ldap_set_option( data->ld, LDAP_OPT_TIMEOUT, &timeout ) != LDAP_OPT_SUCCESS ) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set Timeout: %s", ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return 1; } } else { log_write(data->ar->c2s->log, LOG_ERR, "ldap: connect to server at %s:%d failed", data->host, data->port); return 1; } return 0; } /** Reconnect */ static int _ldap_reconnect(moddata_t data) { if (data->ld != NULL) { ldap_unbind_s(data->ld); data->ld = NULL; } return (_ldap_connect(data)); } /** do a search, return the dn */ static char *_ldap_search(moddata_t data, const char *realm, const char *username) { char filter[1024], *dn, *no_attrs[] = { NULL }; const char *basedn; LDAPMessage *result, *entry; basedn = xhash_get(data->basedn, realm); if(basedn == NULL) basedn = data->default_basedn; if(basedn == NULL) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: no basedn specified for realm '%s'", realm); ldap_unbind_s(data->ld); data->ld = NULL; return NULL; } if (data->flags & AR_LDAP_FLAGS_RECONNECT) { if (_ldap_reconnect(data)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: reconnect failed: %s realm: %s basedn: %s binddn: %s pass: %s", ldap_err2string(_ldap_get_lderrno(data->ld)), realm, basedn, data->binddn, data->bindpw ); return NULL; } } if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw) && (_ldap_connect(data) || ldap_simple_bind_s(data->ld, data->binddn, data->bindpw))) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: bind failed: %s realm: %s basedn: %s binddn: %s pass: %s", ldap_err2string(_ldap_get_lderrno(data->ld)), realm, basedn, data->binddn, data->bindpw ); ldap_unbind_s(data->ld); data->ld = NULL; return NULL; } if (data->query) { /* custom uid format search fun */ switch(data->uidattr_order) { case AR_LDAP_UAO_USERNAME_DOMAIN: snprintf(filter, 1024, data->query, username, realm); break; case AR_LDAP_UAO_DOMAIN_USERNAME: snprintf(filter, 1024, data->query, realm, username); break; case AR_LDAP_UAO_USERNAME: snprintf(filter, 1024, data->query, username); break; default: log_write(data->ar->c2s->log, LOG_ERR, "ldap: creating filter failed: expected valid custom query, check your <query> config parameter"); log_debug(ZONE, "got unhandled %d for uidattr_order", data->uidattr_order); return NULL; } } else if (data->flags & AR_LDAP_FLAGS_APPEND_REALM) { snprintf(filter, 1024, "(%s=%s@%s)", data->uidattr, username, realm); } else { snprintf(filter, 1024, "(%s=%s)", data->uidattr, username); } log_debug(ZONE, "LDAP: will query with filter: %s\n", filter); if(ldap_set_rebind_proc(data->ld, &rebindProc, data)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: set_rebind_proc failed: %s", ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return NULL; } if(ldap_search_s(data->ld, basedn, LDAP_SCOPE_SUBTREE, filter, no_attrs, 0, &result)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", filter, ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return NULL; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return NULL; } dn = ldap_get_dn(data->ld, entry); ldap_msgfree(result); log_debug(ZONE, "got dn '%s' from realm '%s', user '%s'", dn, realm, username); return dn; } /** do we have this user? */ static int _ldap_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { char *dn; moddata_t data; if(xhash_iter_first((xht) ar->private)) do { xhash_iter_get((xht) ar->private, NULL, NULL, (void *) &data); if( ! (data->ld == NULL && _ldap_connect(data)) ) { dn = _ldap_search(data, realm, username); if (dn != NULL) { ldap_memfree(dn); return 1; } } } while(xhash_iter_next((xht) ar->private)); return 0; } /** check the password */ static int _ldap_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { moddata_t data; char *dn; if(password[0] == '\0') return 1; if(xhash_iter_first((xht) ar->private)) do { xhash_iter_get((xht) ar->private, NULL, NULL, (void *) &data); if( ! (data->ld == NULL && _ldap_connect(data)) ) { dn = _ldap_search(data, realm, username); if (dn != NULL) { if(ldap_simple_bind_s(data->ld, dn, password) ) { if(_ldap_get_lderrno(data->ld) != LDAP_INVALID_CREDENTIALS) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: bind as '%s' on host '%s' failed: %s", dn,data->host, ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; } ldap_memfree(dn); } else { ldap_memfree(dn); return 0; } } } } while(xhash_iter_next((xht) ar->private)); return 1; } /** shut me down */ static void _ldap_free(authreg_t ar) { moddata_t data; if(xhash_iter_first((xht) ar->private)) do { xhash_iter_get((xht) ar->private, NULL, NULL, (void *) &data); if(data->ld != NULL) ldap_unbind_s(data->ld); xhash_free(data->basedn); free(data); } while(xhash_iter_next((xht) ar->private)); xhash_free((xht) ar->private); return; } /** start me up */ int ar_init(authreg_t ar) { moddata_t data; char ldap_entry[128]; const char *host, *realm; config_elem_t basedn; int i,l=0; xht domains; domains = xhash_new(17); ldap_entry[15]='\0'; /* while we have more ldap entries*/ do { if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.host", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.host"); host = config_get_one(ar->c2s->config, ldap_entry, 0); if(host == NULL) { log_write(ar->c2s->log, LOG_ERR, "ldap: no host specified in config file"); return 1; } if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.basedn", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.basedn"); basedn = config_get(ar->c2s->config, ldap_entry); if(basedn == NULL) { log_write(ar->c2s->log, LOG_ERR, "ldap: no basedn specified in config file"); return 1; } data = (moddata_t) calloc(1, sizeof(struct moddata_st)); data->basedn = xhash_new(101); for(i = 0; i < basedn->nvalues; i++) { realm = (basedn->attrs[i] != NULL) ? j_attr((const char **) basedn->attrs[i], "realm") : NULL; if(realm == NULL) data->default_basedn = basedn->values[i]; else xhash_put(data->basedn, realm, (void*)basedn->values[i]); log_debug(ZONE, "realm '%s' has base dn '%s'", realm, basedn->values[i]); } log_write(ar->c2s->log, LOG_NOTICE, "ldap: configured %d realms", i); data->host = host; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.port", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.port"); data->port = j_atoi(config_get_one(ar->c2s->config, ldap_entry, 0), 389); if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.timeout", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.timeout"); data->timeout = j_atoi(config_get_one(ar->c2s->config, ldap_entry, 0), 5); data->flags = AR_LDAP_FLAGS_NONE; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.reconnect", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.reconnect"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_RECONNECT; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.v3", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.v3"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_V3; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.starttls", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.starttls"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_STARTTLS; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.ssl", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.ssl"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_SSL; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.disablereferrals", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.disablereferrals"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_DISABLE_REFERRALS; /* Append realm is deprecated, use <query> option instead! */ if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.append-realm", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.append-realm"); if(config_get(ar->c2s->config, ldap_entry) != NULL) data->flags |= AR_LDAP_FLAGS_APPEND_REALM; if((data->flags & AR_LDAP_FLAGS_STARTTLS) && (data->flags & AR_LDAP_FLAGS_SSL)) { log_write(ar->c2s->log, LOG_ERR, "ldap: not possible to use both SSL and starttls"); return 1; } if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.binddn", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.binddn"); data->binddn = config_get_one(ar->c2s->config, ldap_entry, 0); if(data->binddn != NULL) { if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.bindpw", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.bindpw"); data->bindpw = config_get_one(ar->c2s->config, ldap_entry, 0); } if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.uidattr", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.uidattr"); data->uidattr = config_get_one(ar->c2s->config, ldap_entry, 0); if(data->uidattr == NULL) data->uidattr = "uid"; if (l>0) snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d.query", l ); else snprintf(ldap_entry, sizeof(ldap_entry), "authreg.ldap.query"); data->query = config_get_one(ar->c2s->config, ldap_entry, 0); if(_create_user_filter(data)) data->query = NULL; data->ar = ar; if(_ldap_connect(data)) { xhash_free(data->basedn); free(data); return 1; } xhash_put(domains, data->host, data); l++; snprintf(ldap_entry,sizeof(ldap_entry), "authreg.ldap%d", l ); } while ( config_count(ar->c2s->config, ldap_entry) > 0 ); ar->private = domains; ar->user_exists = _ldap_user_exists; ar->check_password = _ldap_check_password; ar->free = _ldap_free; return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_ldapfull.c���������������������������������������������������0000664�0000000�0000000�00000072424�12614627753�0021742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* * Written by Nikita Smirnov in 2004 * on basis of authreg_ldap.c */ /* * !!! this doesn't do any caching. It really should. * * !!! this blocks for every auth. */ #define _XOPEN_SOURCE 500 // need this to get crypt() #include "c2s.h" #ifdef STORAGE_LDAP #ifdef HAVE_CRYPT #include <unistd.h> #endif #ifdef HAVE_SSL #include <openssl/rand.h> #endif #include <lber.h> #define LDAP_DEPRECATED 1 #include <ldap.h> #define LDAPFULL_PASSBUF_MAX 257 #define LDAPFULL_DN_MAX 4096 #define LDAPFULL_SRVTYPE_LDAP 1 #define LDAPFULL_SRVTYPE_AD 2 #define LDAPFULL_SEARCH_MAX_RETRIES 1 /** internal structure, holds our data */ typedef struct moddata_st { authreg_t ar; LDAP *ld; const char *uri; const char *binddn; const char *bindpw; const char *objectclass; const char *uidattr; const char *validattr; const char *group_dn; const char *pwattr; const char *pwscheme; int fulluid; // use "uid@realm" in ldap searches (1) or just use "uid" (0) int binded; // if we are binded with binddn and bindpw, then 1, otherwise 0 int srvtype; xht basedn; const char *default_basedn; } *moddata_t; ////////////////////////////////////////////////////////////////////////////// // // Here is stuff for hashing passwords // ideas and some part of code are taken from cyrus-sasl/saslauthd // ////////////////////////////////////////////////////////////////////////////// #ifdef HAVE_SSL #include <openssl/evp.h> #include <openssl/des.h> #endif typedef struct _ldapfull_pw_scheme { char *name; char *scheme; char *prefix; int saltlen; int (*check) (moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd); int (*set) (moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen); } ldapfull_pw_scheme; int _ldapfull_hash_init(); // call it before use of other stuff #ifdef HAVE_SSL static int _ldapfull_chk_hashed(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd); static int _ldapfull_set_hashed(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen); #endif #ifdef HAVE_CRYPT static int _ldapfull_chk_crypt(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd); static int _ldapfull_set_crypt(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen); #endif static int _ldapfull_chk_clear(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd); static int _ldapfull_set_clear(moddata_t data, const char* scheme, const char* prefix, int saltlen, const char* passwd, char* buf, int buflen); static int _ldapfull_check_passhash(moddata_t data, const char *hash, const char *passwd); static int _ldapfull_set_passhash(moddata_t data, const char* scheme_name, const char* passwd, char* buf, int buflen); static int _ldapfull_check_password_bind(authreg_t ar, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]); ldapfull_pw_scheme _ldapfull_pw_schemas[] = { #ifdef HAVE_SSL { "sha", "sha1", "{SHA}", 0, _ldapfull_chk_hashed, _ldapfull_set_hashed }, { "ssha", "sha1", "{SSHA}", 4, _ldapfull_chk_hashed, _ldapfull_set_hashed }, #endif #ifdef HAVE_CRYPT { "crypt", "crypt", "", 2, _ldapfull_chk_crypt, _ldapfull_set_crypt }, #endif { "clear", "", "", 0, _ldapfull_chk_clear, _ldapfull_set_clear }, { "bind", "", "", 0, NULL, NULL }, { NULL, NULL, NULL, 0, NULL, NULL } }; // general check_password // returns 1 if password is checked, 0 otherwise int _ldapfull_check_passhash(moddata_t data, const char *hash, const char *passwd) { int n; int plen; int hlen; if( ! hash ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: hash is NULL"); return 0; } if( ! passwd ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: passwd is NULL"); return 0; } hlen = strlen(hash); for( n=0 ; _ldapfull_pw_schemas[n].name != NULL ; n++ ) { plen = strlen(_ldapfull_pw_schemas[n].prefix); if( (plen <= hlen) && !strncmp(hash,_ldapfull_pw_schemas[n].prefix,plen) ) { // if scheme found is cleartext and hash begins with '{', than maybe it is // unknown scheme, so don't pass it if( ! strlen(_ldapfull_pw_schemas[n].scheme) && hlen ) { if( hash[0] == '{' ) { continue; } } if( _ldapfull_pw_schemas[n].check ) { return _ldapfull_pw_schemas[n].check( data, _ldapfull_pw_schemas[n].scheme, _ldapfull_pw_schemas[n].saltlen, hash + plen,passwd); } else { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: no check function for schema %s", _ldapfull_pw_schemas[n].name); return 0; } } } return 0; } // general set_password // returns 1 if password in buf is set, 0 otherwise // must provide with buffer of sufficient length, or it will fail int _ldapfull_set_passhash(moddata_t data, const char *scheme_name, const char *passwd, char *buf, int buflen) { int n; if( ! passwd ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: passwd is NULL"); return 0; } if( ! buf ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: buf is NULL"); return 0; } for( n=0 ; _ldapfull_pw_schemas[n].name != NULL ; n++ ) { if( !strcmp(scheme_name,_ldapfull_pw_schemas[n].name) ) { if( _ldapfull_pw_schemas[n].set ) { return _ldapfull_pw_schemas[n].set( data, _ldapfull_pw_schemas[n].scheme, _ldapfull_pw_schemas[n].prefix, _ldapfull_pw_schemas[n].saltlen, passwd, buf, buflen); } else { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: no set function for schema %s", _ldapfull_pw_schemas[n].name); return 0; } } } return 0; } int _ldapfull_chk_clear(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) { return !strcmp(hash,passwd); } int _ldapfull_set_clear(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) { if( buflen <= strlen(passwd) ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_clear: buffer is too short (%i bytes)",buflen); return 0; } strcpy(buf, passwd); return 1; } #ifdef HAVE_SSL int _ldapfull_base64_decode( const char *src, const unsigned char **ret, int *rlen ) { unsigned int rc, tlen = 0; int i; unsigned char *text; EVP_ENCODE_CTX EVP_ctx; text = (unsigned char *)malloc(((strlen(src)+3)/4 * 3) + 1); if (text == NULL) { return 0; } EVP_DecodeInit(&EVP_ctx); rc = EVP_DecodeUpdate(&EVP_ctx, text, &i, (const unsigned char *)src, strlen(src)); if (rc < 0) { free(text); return 0; } tlen+=i; EVP_DecodeFinal(&EVP_ctx, (unsigned char*)text, &i); *ret = text; if (rlen != NULL) { *rlen = tlen; } return 1; } static int _ldapfull_base64_encode( const unsigned char *src, int srclen, char **ret, int *rlen ) { int tlen = 0; unsigned char *text; EVP_ENCODE_CTX EVP_ctx; text = (unsigned char *)malloc((srclen*4/3) + 1 ); if (text == NULL) { return 0; } EVP_EncodeInit(&EVP_ctx); EVP_EncodeUpdate(&EVP_ctx, text, &tlen, src, srclen); EVP_EncodeFinal(&EVP_ctx, text, &tlen); *ret = (char*)text; if (rlen != NULL) { *rlen = tlen; } return 1; } int _ldapfull_chk_hashed(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) { const unsigned char *bhash; // binary hash, will get it from base64 EVP_MD_CTX mdctx; const EVP_MD *md; unsigned char digest[EVP_MAX_MD_SIZE]; int bhlen, rc; md = EVP_get_digestbyname(scheme); if (!md) { return 0; } if( ! _ldapfull_base64_decode(hash, &bhash, &bhlen) ) { return 0; } EVP_DigestInit(&mdctx, md); EVP_DigestUpdate(&mdctx, passwd, strlen(passwd)); if (salted) { EVP_DigestUpdate(&mdctx, &bhash[EVP_MD_size(md)], bhlen - EVP_MD_size(md)); } EVP_DigestFinal(&mdctx, digest, NULL); rc = memcmp((char *)bhash, (char *)digest, EVP_MD_size(md)); free((void*)bhash); return !rc; } int _ldapfull_set_hashed(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) { char *hash = 0; // base64 hash EVP_MD_CTX mdctx; const EVP_MD *md; unsigned char *digest; unsigned char *salt; int hlen=0; int plen, rc; unsigned int dlen; md = EVP_get_digestbyname(scheme); if (!md) { return 0; } EVP_DigestInit(&mdctx, md); EVP_DigestUpdate(&mdctx, passwd, strlen(passwd)); if (saltlen) { salt = (unsigned char *)malloc(saltlen); if( !salt ) { EVP_MD_CTX_cleanup(&mdctx); return 0; } if( !RAND_bytes(salt,saltlen) ) { EVP_MD_CTX_cleanup(&mdctx); free(salt); } EVP_DigestUpdate(&mdctx, salt, saltlen); } digest = (unsigned char *)malloc(EVP_MD_size(md) + saltlen); if( !digest ) { if (saltlen) { free(salt); } EVP_MD_CTX_cleanup(&mdctx); return 0; } EVP_DigestFinal(&mdctx, digest, &dlen); memcpy(digest+dlen,salt,saltlen); if (saltlen) { free(salt); } rc = _ldapfull_base64_encode(digest, dlen+saltlen, &hash, &hlen); if( hash[hlen-1] == '\n' ) { hash[--hlen] = '\0'; } free(digest); if( !rc ) { free(hash); return 0; } plen = strlen(prefix); if( hlen + plen >= buflen ) { log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_hashed: buffer is too short (%i bytes)",buflen); free(hash); return 0; } memcpy(buf,prefix,plen); memcpy(buf+plen,hash,hlen); buf[hlen+plen]='\0'; free(hash); return 1; } #endif // HAVE_SSL #ifdef HAVE_CRYPT /** Check UNIX style crypt hashed password */ int _ldapfull_chk_crypt(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) { const char *encrypted; char salt[3]; if (strlen(hash) != 13) { log_write(data->ar->c2s->log, LOG_ERR, "Invalid crypt hash length %d", strlen(hash)); return 0; } salt[0] = hash[0]; salt[1] = hash[1]; salt[2] = 0; encrypted = crypt(passwd, salt); return !strcmp(encrypted, hash); } int _ldapfull_set_crypt(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) { const char *encrypted; char salt[3]; static const char saltchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; if ((saltlen != 2) || (buflen < 14)) { log_write(data->ar->c2s->log, LOG_ERR, "Invalid crypt hash params"); return 0; } #ifdef HAVE_SSL if( !RAND_bytes((unsigned char*)salt, saltlen) ) return 0; salt[0] = saltchars[salt[0] % 64]; salt[1] = saltchars[salt[1] % 64]; salt[2] = 0; #else /* Note: This is not a cryptographically secure random number generator */ salt[0] = saltchars[random() % 64]; salt[1] = saltchars[random() % 64]; salt[2] = 0; #endif encrypted = crypt(passwd, salt); strncpy(buf, encrypted, buflen); buf[buflen-1] = 0; return 1; } #endif // HAVE_CRYPT /** Makes a copy of enough LDAP data in order to establish a second connection */ static void copy_ldap_config(moddata_t from, moddata_t to) { memset(to, 0, sizeof(struct moddata_st)); to->uri = from->uri; to->ar = from->ar; } int _ldapfull_hash_init() { #ifdef HAVE_SSL OpenSSL_add_all_digests(); #else srandom(time(NULL) ^ getpid()); #endif return 1; } ////////////////////////////////////////////////////////////////////////////// // // end of stuff for hashing passwords // ////////////////////////////////////////////////////////////////////////////// /** utility function to get ld_errno */ static int _ldapfull_get_lderrno(LDAP *ld) { int ld_errno; ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno); return ld_errno; } /** connect to the ldap host */ static int _ldapfull_connect(moddata_t data) { int ldapversion = LDAP_VERSION3; int rc; if(data->ld != NULL) ldap_unbind_s(data->ld); data->binded=0; rc = ldap_initialize(&(data->ld), data->uri); if( rc != LDAP_SUCCESS ) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: ldap_initialize failed, uri=%s (%d): %s", data->uri, rc, ldap_err2string(rc)); return 1; } if (ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_SUCCESS) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set v3 protocol"); return 1; } if (ldap_set_option(data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set LDAP_OPT_REFERRALS"); } log_debug(ZONE, "connected to ldap server"); return 0; } /** unbind and clear variables */ static int _ldapfull_unbind(moddata_t data) { ldap_unbind_s(data->ld); data->ld = NULL; data->binded = 0; log_debug(ZONE, "unbinded from ldap server"); return 0; } /** connect to ldap and bind as data->binddn */ static int _ldapfull_connect_bind(moddata_t data) { if(data->ld != NULL && data->binded ) { return 0; } if( _ldapfull_connect(data) ) { return 1; } if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: bind as '%s' failed: %s", data->binddn, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); return 1; } log_debug(ZONE, "binded to ldap server"); data->binded = 1; return 0; } /** do a search, return the dn */ static char *_ldapfull_search(moddata_t data, const char *realm, const char *username) { char validfilter[256], filter[1024], *dn, *no_attrs[] = { NULL }; const char *basedn; LDAPMessage *result, *entry; int tried = 0; log_debug(ZONE, "searching for %s", username); basedn = xhash_get(data->basedn, realm); if(basedn == NULL) basedn = data->default_basedn; if(basedn == NULL) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: no basedn specified for realm '%s'", realm); _ldapfull_unbind(data); return NULL; } // for AD validattr should be =TRUE, for [open]ldap =1 if( data->validattr ) { validfilter[0] = '\0'; if( data->srvtype == LDAPFULL_SRVTYPE_AD ) { snprintf(validfilter, 256, "(%s=TRUE)", data->validattr); } else { snprintf(validfilter, 256, "(%s=1)", data->validattr); } if( data->fulluid ) { snprintf(filter, 1024, "(&(objectClass=%s)%s(%s=%s@%s))", data->objectclass, validfilter, data->uidattr, username, realm); } else { snprintf(filter, 1024, "(&(objectClass=%s)%s(%s=%s))", data->objectclass, validfilter, data->uidattr, username); } } else { if( data->fulluid ) { snprintf(filter, 1024, "(&(objectClass=%s)(%s=%s@%s))", data->objectclass, data->uidattr, username, realm); } else { snprintf(filter, 1024, "(&(objectClass=%s)(%s=%s))", data->objectclass, data->uidattr, username); } } log_debug(ZONE, "search filter: %s", filter); retry: if(ldap_search_s(data->ld, basedn, LDAP_SCOPE_SUBTREE, filter, no_attrs, 0, &result)) { if( tried++ < LDAPFULL_SEARCH_MAX_RETRIES ) { log_debug(ZONE, "ldap: search fail, will retry; %s: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); if( _ldapfull_connect_bind(data) == 0 ) { goto retry; } else { return NULL; } } log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); return NULL; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return NULL; } dn = ldap_get_dn(data->ld, entry); ldap_msgfree(result); log_debug(ZONE, "found user %s: dn=%s", username, dn); return dn; } /** Is this user part of the given LDAP group? */ static int _ldapfull_user_in_group(moddata_t data, const char *user_dn, const char *group_dn) { LDAPMessage *result, *entry; int tried = 0; char filter[1024]; log_debug(ZONE, "checking whether user with dn %s is in group %s", user_dn, group_dn); memset(filter, 0, 1024); snprintf(filter, 1024, "(member=%s)", user_dn); // TODO Check if snprintf result was truncated retry: if(ldap_search_s(data->ld, group_dn, LDAP_SCOPE_BASE, filter, NULL, 0, &result)) { if( tried++ < LDAPFULL_SEARCH_MAX_RETRIES ) { log_debug(ZONE, "ldap: group search fail, will retry; %s: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); if( _ldapfull_connect_bind(data) == 0 ) { goto retry; } else { return 0; } } log_write(data->ar->c2s->log, LOG_ERR, "ldap: group search %s failed: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); return 0; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return 0; } else { ldap_msgfree(result); return 1; } } /** Get distinguished name for this user if we have it */ static int _ldapfull_find_user_dn(moddata_t data, const char *username, const char *realm, const char **dn) { *dn = NULL; if(_ldapfull_connect_bind(data)) return 0; // error log_debug(ZONE, "checking existance of %s", username); *dn = _ldapfull_search(data, realm, username); return *dn != NULL; } /** do we have this user? */ static int _ldapfull_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { const char *dn; if (_ldapfull_find_user_dn((moddata_t) ar->private, username, realm, &dn)) { if(((moddata_t) ar->private)->group_dn != NULL && !_ldapfull_user_in_group((moddata_t) ar->private, dn, ((moddata_t) ar->private)->group_dn)) { ldap_memfree((void*)dn); return 0; } ldap_memfree((void*)dn); return 1; } return 0; } /** This method determines the DN of the user and does a new simple bind of the LDAP server. If the server allows it, the user has been authenticated. */ static int _ldapfull_check_password_bind(authreg_t ar, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) { moddata_t data = (moddata_t) ar->private; struct moddata_st bind_data; int invalid; const char *dn; if (!_ldapfull_find_user_dn(data, username, realm, &dn)) { log_debug(ZONE, "User %s not found", username); return 1; } /* Try logging in to the LDAP server as this user's DN */ copy_ldap_config(data, &bind_data); bind_data.binddn = dn; bind_data.bindpw = password; invalid = _ldapfull_connect_bind(&bind_data); if (!invalid) _ldapfull_unbind(&bind_data); ldap_memfree((void*)dn); return invalid; } // get password from jabberPassword attribute static int _ldapfull_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) { moddata_t data = (moddata_t) ar->private; LDAPMessage *result, *entry; const char *dn, *no_attrs[] = { data->pwattr, NULL }; char **vals; log_debug(ZONE, "getting password for %s", username); if( _ldapfull_connect_bind(data) ) { return 1; } dn = _ldapfull_search(data, realm, username); if(dn == NULL) return 1; if(ldap_search_s(data->ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)", (char**)no_attrs, 0, &result)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld))); ldap_memfree((void*)dn); _ldapfull_unbind(data); return 1; } ldap_memfree((void*)dn); entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return 1; } vals=ldap_get_values(data->ld,entry,data->pwattr); if( ldap_count_values(vals) <= 0 ) { ldap_value_free(vals); ldap_msgfree(result); return 1; } strncpy(password,vals[0],LDAPFULL_PASSBUF_MAX-1); password[LDAPFULL_PASSBUF_MAX-1] = '\0'; ldap_value_free(vals); ldap_msgfree(result); log_debug(ZONE, "found password for %s", username); return 0; } // set password from jabberPassword attribute static int _ldapfull_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) { moddata_t data = (moddata_t) ar->private; LDAPMessage *result, *entry; LDAPMod *mods[2], attr_pw; char buf[LDAPFULL_PASSBUF_MAX]; char *pdn, *attrs[] = { NULL }, *pw_mod_vals[] = { buf, NULL }; char dn[LDAPFULL_DN_MAX]; log_debug(ZONE, "setting password for %s", username); if( ! _ldapfull_set_passhash(data,data->pwscheme,password,buf,LDAPFULL_PASSBUF_MAX) ) { log_debug(ZONE, "password scheme is not defined"); return 1; } if( _ldapfull_connect_bind(data) ) { return 1; } pdn = _ldapfull_search(data, realm, username); if(pdn == NULL) return 1; strncpy(dn, pdn, LDAPFULL_DN_MAX-1); dn[LDAPFULL_DN_MAX-1] = '\0'; ldap_memfree(pdn); if(ldap_search_s(data->ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)", attrs, 0, &result)) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); return 1; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return 1; } ldap_msgfree(result); attr_pw.mod_op = LDAP_MOD_REPLACE; attr_pw.mod_type = (char*)data->pwattr; attr_pw.mod_values = pw_mod_vals; mods[0] = &attr_pw; mods[1] = NULL; if( ldap_modify_s(data->ld, dn, mods) != LDAP_SUCCESS ) { log_write(data->ar->c2s->log, LOG_ERR, "ldap: error modifying %s: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld))); _ldapfull_unbind(data); return 1; } log_debug(ZONE, "password was set for %s", username); return 0; } /** check the password */ static int _ldapfull_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) { moddata_t data = (moddata_t) ar->private; char buf[LDAPFULL_PASSBUF_MAX]; const char *dn = NULL; log_debug(ZONE, "checking password for %s", username); if(password[0] == '\0') return 1; if(data->group_dn != NULL) { if (!_ldapfull_find_user_dn(data, username, realm, &dn)) return 1; } /* The bind scheme doesn't need the password read first, so short circuit the whole passhash scheme */ if (!strcmp(data->pwscheme, "bind")) { if(_ldapfull_check_password_bind(ar, username, realm, password) == 0) { if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn)) { ldap_memfree((void*)dn); return 1; } else { ldap_memfree((void*)dn); return 0; } } } if( _ldapfull_get_password(ar,sess,username,realm,buf) != 0 ) { if(dn != NULL) ldap_memfree((void*)dn); return 1; } if(_ldapfull_check_passhash(data,buf,password)){ if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn)) { ldap_memfree((void*)dn); return 1; } else { if(dn != NULL) ldap_memfree((void*)dn); return 0; } } else { if(dn != NULL) ldap_memfree((void*)dn); return 1; } } static int _ldapfull_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { if( _ldapfull_user_exists(ar,sess,username,realm) ) { return 0; } else { return 1; } } static int _ldapfull_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { return 0; } /** shut me down */ static void _ldapfull_free(authreg_t ar) { moddata_t data = (moddata_t) ar->private; _ldapfull_unbind(data); xhash_free(data->basedn); free(data); return; } /** start me up */ DLLEXPORT int ar_init(authreg_t ar) { moddata_t data; const char *uri, *realm, *srvtype_s; config_elem_t basedn; int i,hascheck,srvtype_i; uri = config_get_one(ar->c2s->config, "authreg.ldapfull.uri", 0); if(uri == NULL) { log_write(ar->c2s->log, LOG_ERR, "ldap: no uri specified in config file"); return 1; } basedn = config_get(ar->c2s->config, "authreg.ldapfull.basedn"); if(basedn == NULL) { log_write(ar->c2s->log, LOG_ERR, "ldap: no basedn specified in config file"); return 1; } srvtype_s = config_get_one(ar->c2s->config, "authreg.ldapfull.type", 0); if( srvtype_s == NULL ) { srvtype_i = LDAPFULL_SRVTYPE_LDAP; } else if( !strcmp(srvtype_s, "ldap") ) { srvtype_i = LDAPFULL_SRVTYPE_LDAP; } else if( !strcmp(srvtype_s, "ad") ) { srvtype_i = LDAPFULL_SRVTYPE_AD; } else { log_write(ar->c2s->log, LOG_ERR, "ldap: unknown server type: %s", srvtype_s); return 1; } data = (moddata_t) calloc(1, sizeof(struct moddata_st)); data->basedn = xhash_new(101); for(i = 0; i < basedn->nvalues; i++) { realm = (basedn->attrs[i] != NULL) ? j_attr((const char **) basedn->attrs[i], "realm") : NULL; if(realm == NULL) data->default_basedn = basedn->values[i]; else xhash_put(data->basedn, realm, (void*)basedn->values[i]); log_debug(ZONE, "realm '%s' has base dn '%s'", realm, basedn->values[i]); } log_write(ar->c2s->log, LOG_NOTICE, "ldap: configured %d realms", i); data->uri = uri; data->srvtype = srvtype_i; data->binddn = config_get_one(ar->c2s->config, "authreg.ldapfull.binddn", 0); if(data->binddn != NULL) data->bindpw = config_get_one(ar->c2s->config, "authreg.ldapfull.bindpw", 0); data->uidattr = config_get_one(ar->c2s->config, "authreg.ldapfull.uidattr", 0); if(data->uidattr == NULL) data->uidattr = "uid"; data->validattr = config_get_one(ar->c2s->config, "authreg.ldapfull.validattr", 0); data->group_dn = config_get_one(ar->c2s->config, "authreg.ldapfull.group_dn", 0); data->pwattr = config_get_one(ar->c2s->config, "authreg.ldapfull.pwattr", 0); if(data->pwattr == NULL) data->pwattr = "jabberPassword"; data->pwscheme = config_get_one(ar->c2s->config, "authreg.ldapfull.pwscheme", 0); if(data->pwscheme == NULL) { data->pwscheme = "clear"; hascheck=0; } else { hascheck=1; } data->objectclass = config_get_one(ar->c2s->config, "authreg.ldapfull.objectclass", 0); if(data->objectclass == NULL) data->objectclass = "jabberUser"; if( (char *)config_get_one(ar->c2s->config, "authreg.ldapfull.fulluid", 0) != NULL ) { data->fulluid = 1; } data->ar = ar; if(_ldapfull_connect_bind(data)) { xhash_free(data->basedn); free(data); return 1; } _ldapfull_hash_init(); ar->private = data; ar->user_exists = _ldapfull_user_exists; ar->create_user = _ldapfull_create_user; ar->delete_user = _ldapfull_delete_user; ar->set_password = _ldapfull_set_password; if( hascheck ) { ar->check_password = _ldapfull_check_password; } else { ar->get_password = _ldapfull_get_password; } ar->free = _ldapfull_free; return 0; } #endif // STORAGE_LDAP ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_mysql.c������������������������������������������������������0000664�0000000�0000000�00000052012�12614627753�0021273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this module talks to a MySQL server via libmysqlclient */ #define _XOPEN_SOURCE 500 #include "c2s.h" #include <mysql.h> /* Windows does not have the crypt() function, let's take DES_crypt from OpenSSL instead */ #if defined(HAVE_OPENSSL_CRYPTO_H) && defined(_WIN32) #include <openssl/des.h> #define crypt DES_crypt #define HAVE_CRYPT 1 #else #ifdef HAVE_CRYPT #include <unistd.h> #endif #endif #ifdef HAVE_SSL /* We use OpenSSL's MD5 routines for the a1hash password type */ #include <openssl/md5.h> #include <util/crypt_blowfish.h> #endif #define MYSQL_LU 1024 /* maximum length of username - should correspond to field length */ #define MYSQL_LR 256 /* maximum length of realm - should correspond to field length */ #define MYSQL_LP 256 /* maximum length of password - should correspond to field length */ enum mysql_pws_crypt { MPC_PLAIN, #ifdef HAVE_CRYPT MPC_CRYPT, #endif #ifdef HAVE_SSL MPC_A1HASH, MPC_BCRYPT #endif }; #ifdef HAVE_CRYPT static char salter[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; #endif typedef struct mysqlcontext_st { MYSQL * conn; const char * sql_create; const char * sql_select; const char * sql_setpassword; const char * sql_delete; const char * field_password; enum mysql_pws_crypt password_type; #ifdef HAVE_SSL int bcrypt_cost; #endif } *mysqlcontext_t; #ifdef HAVE_SSL static void calc_a1hash(const char *username, const char *realm, const char *password, char *a1hash) { #define A1PPASS_LEN MYSQL_LU + 1 + MYSQL_LR + 1 + MYSQL_LP + 1 /* user:realm:password\0 */ char buf[A1PPASS_LEN]; unsigned char md5digest[MD5_DIGEST_LENGTH]; int i; snprintf(buf, A1PPASS_LEN, "%.*s:%.*s:%.*s", MYSQL_LU, username, MYSQL_LR, realm, MYSQL_LP, password); MD5((unsigned char*)buf, strlen(buf), md5digest); for(i=0; i<16; i++) { sprintf(a1hash+i*2, "%02hhx", md5digest[i]); } } static void bcrypt_hash(const char *password, int cost, char* hash) { char salt[16]; if(!RAND_bytes(salt, 16)) ; //we've got a problem char* gen = bcrypt_gensalt("$2y$", cost, salt, 16); strcpy(hash, bcrypt(password, gen)); } static int bcrypt_verify(const char *password, const char* hash) { char *ret; ret = bcrypt(password, hash); if(strlen(ret) != strlen(hash)) return 1; int status = 0; int i = 0; for(i; i < strlen(ret); i++) status |= (ret[i] ^ hash[i]); return status != 0; } static int bcrypt_needs_rehash(int current_cost, const char* hash) { int hash_cost; sscanf(hash, "$2y$%d$", &hash_cost); if(current_cost != hash_cost) return 1; return 0; } #endif static MYSQL_RES *_ar_mysql_get_user_tuple(authreg_t ar, const char *username, const char *realm) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; char iuser[MYSQL_LU+1], irealm[MYSQL_LR+1]; char euser[MYSQL_LU*2+1], erealm[MYSQL_LR*2+1], sql[1024 + MYSQL_LU*2 + MYSQL_LR*2 + 1]; /* query(1024) + euser + erealm + \0(1) */ MYSQL_RES *res; if(mysql_ping(conn) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: connection to database lost"); return NULL; } snprintf(iuser, MYSQL_LU+1, "%s", username); snprintf(irealm, MYSQL_LR+1, "%s", realm); mysql_real_escape_string(conn, euser, iuser, strlen(iuser)); mysql_real_escape_string(conn, erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_select, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); if(mysql_query(conn, sql) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql select failed: %s", mysql_error(conn)); return NULL; } res = mysql_store_result(conn); if(res == NULL) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql result retrieval failed: %s", mysql_error(conn)); return NULL; } if(mysql_num_rows(res) != 1) { mysql_free_result(res); return NULL; } return res; } static int _ar_mysql_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { MYSQL_RES *res = _ar_mysql_get_user_tuple(ar, username, realm); if(res != NULL) { mysql_free_result(res); return 1; } return 0; } static int _ar_mysql_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; MYSQL_RES *res = _ar_mysql_get_user_tuple(ar, username, realm); MYSQL_FIELD *field; MYSQL_ROW tuple; int i, fpass = 0; if(res == NULL) return 1; for(i = mysql_num_fields(res) - 1; i >= 0; i--) { field = mysql_fetch_field_direct(res, i); if(strcmp(field->name, ctx->field_password) == 0) { fpass = i; break; } } if((tuple = mysql_fetch_row(res)) == NULL) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql tuple retrieval failed: %s", mysql_error(conn)); mysql_free_result(res); return 1; } if(tuple[fpass] == NULL) { mysql_free_result(res); return 1; } strcpy(password, tuple[fpass]); mysql_free_result(res); return 0; } static int _ar_mysql_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; char iuser[MYSQL_LU+1], irealm[MYSQL_LR+1]; char euser[MYSQL_LU*2+1], erealm[MYSQL_LR*2+1], epass[513], sql[1024+MYSQL_LU*2+MYSQL_LR*2+512+1]; /* query(1024) + euser + erealm + epass(512) + \0(1) */ if(mysql_ping(conn) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: connection to database lost"); return 1; } snprintf(iuser, MYSQL_LU+1, "%s", username); snprintf(irealm, MYSQL_LR+1, "%s", realm); #ifdef HAVE_CRYPT if (ctx->password_type == MPC_CRYPT) { char salt[39] = "$6$rounds=50000$"; int i; srand(time(0)); for(i=0; i<22; i++) salt[16+i] = salter[rand()%64]; salt[38] = '\0'; strcpy(password, crypt(password, salt)); } #endif #ifdef HAVE_SSL if (ctx->password_type == MPC_A1HASH) { calc_a1hash(username, realm, password, password); } else if (ctx->password_type == MPC_BCRYPT) { bcrypt_hash(password, ctx->bcrypt_cost, password); } #endif password[256]= '\0'; mysql_real_escape_string(conn, euser, iuser, strlen(iuser)); mysql_real_escape_string(conn, erealm, irealm, strlen(irealm)); mysql_real_escape_string(conn, epass, password, strlen(password)); sprintf(sql, ctx->sql_setpassword, epass, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); if(mysql_query(conn, sql) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql update failed: %s", mysql_error(conn)); return 1; } return 0; } static int _ar_mysql_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; char db_pw_value[257]; #ifdef HAVE_CRYPT char *crypted_pw; #endif #ifdef HAVE_SSL char a1hash_pw[33]; #endif int ret; ret = _ar_mysql_get_password(ar, sess, username, realm, db_pw_value); /* return if error */ if (ret) return ret; switch (ctx->password_type) { case MPC_PLAIN: ret = (strcmp(password, db_pw_value) != 0); break; #ifdef HAVE_CRYPT case MPC_CRYPT: crypted_pw = crypt(password,db_pw_value); ret = (strcmp(crypted_pw, db_pw_value) != 0); break; #endif #ifdef HAVE_SSL case MPC_A1HASH: if (strchr(username, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Username cannot contain : with a1hash encryption type."); break; } if (strchr(realm, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Realm cannot contain : with a1hash encryption type."); break; } calc_a1hash(username, realm, password, a1hash_pw); ret = (strncmp(a1hash_pw, db_pw_value, 32) != 0); break; case MPC_BCRYPT: ret = bcrypt_verify(password, db_pw_value); if(ret == 0) { if(bcrypt_needs_rehash(ctx->bcrypt_cost, db_pw_value)) { char tmp[257]; strcpy(tmp, password); _ar_mysql_set_password(ar, sess, username, realm, tmp); } } break; #endif default: /* should never happen */ ret = 1; log_write(ar->c2s->log, LOG_ERR, "Unknown encryption type which passed through config check."); break; } return ret; } static int _ar_mysql_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; char iuser[MYSQL_LU+1], irealm[MYSQL_LR+1]; char euser[MYSQL_LU*2+1], erealm[MYSQL_LR*2+1], sql[1024+MYSQL_LU*2+MYSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ MYSQL_RES *res = _ar_mysql_get_user_tuple(ar, username, realm); if(res != NULL) { mysql_free_result(res); return 1; } mysql_free_result(res); if(mysql_ping(conn) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: connection to database lost"); return 1; } snprintf(iuser, MYSQL_LU+1, "%s", username); snprintf(irealm, MYSQL_LR+1, "%s", realm); mysql_real_escape_string(conn, euser, iuser, strlen(iuser)); mysql_real_escape_string(conn, erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_create, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); if(mysql_query(conn, sql) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql insert failed: %s", mysql_error(conn)); return 1; } return 0; } static int _ar_mysql_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; char iuser[MYSQL_LU+1], irealm[MYSQL_LR+1]; char euser[MYSQL_LU*2+1], erealm[MYSQL_LR*2+1], sql[1024+MYSQL_LU*2+MYSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ if(mysql_ping(conn) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: connection to database lost"); return 1; } snprintf(iuser, MYSQL_LU+1, "%s", username); snprintf(irealm, MYSQL_LR+1, "%s", realm); mysql_real_escape_string(conn, euser, iuser, strlen(iuser)); mysql_real_escape_string(conn, erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_delete, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); if(mysql_query(conn, sql) != 0) { log_write(ar->c2s->log, LOG_ERR, "mysql: sql insert failed: %s", mysql_error(conn)); return 1; } return 0; } static void _ar_mysql_free(authreg_t ar) { mysqlcontext_t ctx = (mysqlcontext_t) ar->private; MYSQL *conn = ctx->conn; if(conn != NULL) mysql_close(conn); free((void*)ctx->sql_create); free((void*)ctx->sql_select); free((void*)ctx->sql_setpassword); free((void*)ctx->sql_delete); free(ctx); } /** Provide a configuration parameter or default value. */ static const char * _ar_mysql_param( config_t c, const char * key, const char * def ) { const char * value = config_get_one( c, key, 0 ); if( value == NULL ) return def; else return value; } /* Ensure the sprintf template is less than 1K long and contains the */ /* required parameter placeholder types. The types string contains */ /* one each, in order, of the one character sprintf types that are */ /* expected to follow the escape characters '%' in the template. */ /* Returns 0 on success, or an error message on failures. */ static char * _ar_mysql_check_template( const char * template, const char * types ) { int pScan = 0; int pType = 0; char c; /* check that it's 1K or less */ if( strlen( template ) > 1024 ) return "longer than 1024 characters"; /* count the parameter placeholders */ while( pScan < strlen( template ) ) { if( template[ pScan++ ] != '%' ) continue; c = template[ pScan++ ]; if( c == '%' ) continue; /* ignore escaped precentages */ if( c == types[ pType ] ) { /* we found the placeholder */ pType++; /* search for the next type */ continue; } /* we found an unexpected placeholder type */ return "contained unexpected placeholder type"; } if( pType < strlen( types ) ) return "contained too few placeholders"; else return 0; } /* Ensure the SQL template is less than 1K long and contains the */ /* required parameter placeholders. If there is an error, it is */ /* written to the error log. */ /* Returns 0 on success, or 1 on errors. */ static int _ar_mysql_check_sql( authreg_t ar, const char * sql, const char * types ) { const char * error; error = _ar_mysql_check_template( sql, types ); if( error == 0 ) return 0; /* alls right :) */ /* signal error */ log_write( ar->c2s->log, LOG_ERR, "mysql: template error: %s - %s", error, sql ); return 1; } /** start me up */ DLLEXPORT int ar_init(authreg_t ar) { const char *host, *port, *dbname, *user, *pass; char *create, *select, *setpassword, *delete; const char *table, *username, *realm; char *template; int strlentur; /* string length of table, user, and realm strings */ MYSQL *conn; mysqlcontext_t mysqlcontext; /* configure the database context with field names and SQL statements */ mysqlcontext = (mysqlcontext_t) malloc( sizeof( struct mysqlcontext_st ) ); ar->private = mysqlcontext; ar->free = _ar_mysql_free; /* determine our field names and table name */ username = _ar_mysql_param( ar->c2s->config , "authreg.mysql.field.username" , "username" ); realm = _ar_mysql_param( ar->c2s->config , "authreg.mysql.field.realm" , "realm" ); mysqlcontext->field_password = _ar_mysql_param( ar->c2s->config , "authreg.mysql.field.password" , "password" ); table = _ar_mysql_param( ar->c2s->config , "authreg.mysql.table" , "authreg" ); /* get encryption type used in DB */ if (config_get_one(ar->c2s->config, "authreg.mysql.password_type.plaintext", 0)) { mysqlcontext->password_type = MPC_PLAIN; #ifdef HAVE_CRYPT } else if (config_get_one(ar->c2s->config, "authreg.mysql.password_type.crypt", 0)) { mysqlcontext->password_type = MPC_CRYPT; #endif #ifdef HAVE_SSL } else if (config_get_one(ar->c2s->config, "authreg.mysql.password_type.a1hash", 0)) { mysqlcontext->password_type = MPC_A1HASH; } else if (config_get_one(ar->c2s->config, "authreg.mysql.password_type.bcrypt", 0)) { mysqlcontext->password_type = MPC_BCRYPT; int cost; if(cost = j_atoi(config_get_attr(ar->c2s->config, "authreg.mysql.password_type.bcrypt", 0, "cost"), 0)) { if(cost < 4 || cost > 31) { log_write(ar->c2s->log, LOG_ERR, "bcrypt cost has to be higher than 3 and lower than 32."); mysqlcontext->bcrypt_cost = 10; // use default } else { mysqlcontext->bcrypt_cost = cost; } } #endif } else { mysqlcontext->password_type = MPC_PLAIN; } /* craft the default SQL statements */ /* we leave unused statements allocated to simplify code - a small price to pay */ /* bounds checking and parameter format verification will be perfomed if the statement is used (see next section) */ /* For malloc(), there is no +1 for trailing 0 as parameter substitution will net us several extra characters */ strlentur = strlen( table ) + strlen( username) + strlen( realm ); /* avoid repetition */ template = "INSERT INTO `%s` ( `%s`, `%s` ) VALUES ( '%%s', '%%s' )"; create = malloc( strlen( template ) + strlentur ); sprintf( create, template, table, username, realm ); template = "SELECT `%s` FROM `%s` WHERE `%s` = '%%s' AND `%s` = '%%s'"; select = malloc( strlen( template ) + strlen( mysqlcontext->field_password ) + strlentur ); sprintf( select, template , mysqlcontext->field_password , table, username, realm ); template = "UPDATE `%s` SET `%s` = '%%s' WHERE `%s` = '%%s' AND `%s` = '%%s'"; setpassword = malloc( strlen( template ) + strlentur + strlen( mysqlcontext->field_password ) ); sprintf( setpassword, template, table, mysqlcontext->field_password, username, realm ); template = "DELETE FROM `%s` WHERE `%s` = '%%s' AND `%s` = '%%s'"; delete = malloc( strlen( template ) + strlentur ); sprintf( delete, template, table, username, realm ); /* allow the default SQL statements to be overridden; also verify the statements format and length */ mysqlcontext->sql_create = strdup(_ar_mysql_param( ar->c2s->config , "authreg.mysql.sql.create" , create )); if( _ar_mysql_check_sql( ar, mysqlcontext->sql_create, "ss" ) != 0 ) return 1; mysqlcontext->sql_select = strdup(_ar_mysql_param( ar->c2s->config , "authreg.mysql.sql.select" , select )); if( _ar_mysql_check_sql( ar, mysqlcontext->sql_select, "ss" ) != 0 ) return 1; mysqlcontext->sql_setpassword = strdup(_ar_mysql_param( ar->c2s->config , "authreg.mysql.sql.setpassword" , setpassword )); if( _ar_mysql_check_sql( ar, mysqlcontext->sql_setpassword, "sss" ) != 0 ) return 1; mysqlcontext->sql_delete = strdup(_ar_mysql_param( ar->c2s->config , "authreg.mysql.sql.delete" , delete )); if( _ar_mysql_check_sql( ar, mysqlcontext->sql_delete, "ss" ) != 0 ) return 1; /* echo our configuration to debug */ log_debug( ZONE, "SQL to create account: %s", mysqlcontext->sql_create ); log_debug( ZONE, "SQL to query user information: %s", mysqlcontext->sql_select ); log_debug( ZONE, "SQL to set password: %s", mysqlcontext->sql_setpassword ); log_debug( ZONE, "SQL to delete account: %s", mysqlcontext->sql_delete ); free(create); free(select); free(setpassword); free(delete); host = config_get_one(ar->c2s->config, "authreg.mysql.host", 0); port = config_get_one(ar->c2s->config, "authreg.mysql.port", 0); dbname = config_get_one(ar->c2s->config, "authreg.mysql.dbname", 0); user = config_get_one(ar->c2s->config, "authreg.mysql.user", 0); pass = config_get_one(ar->c2s->config, "authreg.mysql.pass", 0); if(host == NULL || port == NULL || dbname == NULL || user == NULL || pass == NULL) { log_write(ar->c2s->log, LOG_ERR, "mysql: invalid module config"); return 1; } log_debug( ZONE, "mysql connecting as '%s' to database '%s' on %s:%s", user, dbname, host, port ); conn = mysql_init(NULL); mysqlcontext->conn = conn; if(conn == NULL) { log_write(ar->c2s->log, LOG_ERR, "mysql: unable to allocate database connection state"); return 1; } mysql_options(conn, MYSQL_READ_DEFAULT_GROUP, "jabberd"); mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8"); /* connect with CLIENT_INTERACTIVE to get a (possibly) higher timeout value than default */ if(mysql_real_connect(conn, host, user, pass, dbname, atoi(port), NULL, CLIENT_INTERACTIVE) == NULL) { log_write(ar->c2s->log, LOG_ERR, "mysql: connection to database failed: %s", mysql_error(conn)); return 1; } mysql_query(conn, "SET NAMES 'utf8'"); /* Set reconnect flag to 1 (set to 0 by default from mysql 5 on) */ conn->reconnect = 1; ar->user_exists = _ar_mysql_user_exists; if (MPC_PLAIN == mysqlcontext->password_type) { /* only possible with plaintext passwords */ ar->get_password = _ar_mysql_get_password; } else { ar->get_password = NULL; } ar->check_password = _ar_mysql_check_password; ar->set_password = _ar_mysql_set_password; ar->create_user = _ar_mysql_create_user; ar->delete_user = _ar_mysql_delete_user; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_ntlogon.c����������������������������������������������������0000664�0000000�0000000�00000005342�12614627753�0021612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2005 Adam Strzelecki * * 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, MA02111-1307USA */ /* this plugin uses NT logon LogonUser authentication */ #include "c2s.h" #ifdef _WIN32 typedef BOOL (CALLBACK FNLOGONUSERA)(LPTSTR, LPTSTR, LPTSTR, DWORD, DWORD, PHANDLE); FNLOGONUSERA *_LogonUserA = NULL; HANDLE hModule = NULL; static int _ar_ntlogon_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { /* we can't check if a user exists, so we just assume we have them all the time */ return 1; } static int _ar_ntlogon_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { HANDLE hToken = NULL; if(!_LogonUserA) return 1; if(!_LogonUserA(username, realm, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hToken)) { log_write(ar->c2s->log, LOG_ERR, "ntlogon: user '%s', realm '%s' logon failed", username, realm); return 1; } log_write(ar->c2s->log, LOG_NOTICE, "ntlogon: user '%s', realm '%s' logged in", username, realm); CloseHandle(hToken); return 0; } static void _ar_ntlogon_free(authreg_t ar) { if(hModule) FreeLibrary(hModule); } /** start me up */ DLLEXPORT int ar_init(authreg_t ar) { if(!(hModule = LoadLibraryA("Advapi32.dll"))) { log_write(ar->c2s->log, LOG_ERR, "ntlogon: module requires Windows NT or higher OS"); return 1; } if(!(_LogonUserA = (FNLOGONUSERA *)GetProcAddress(hModule, "LogonUserA"))) { log_write(ar->c2s->log, LOG_ERR, "ntlogon: entry point for LogonUserA cannot be found"); return 1; } ar->user_exists = _ar_ntlogon_user_exists; ar->check_password = _ar_ntlogon_check_password; ar->free = _ar_ntlogon_free; /* reset mechanism to digest only */ /* ar->c2s->ar_mechanisms &= AR_MECH_TRAD_PLAIN; ar->c2s->ar_ssl_mechanisms &= AR_MECH_TRAD_PLAIN; */ log_write(ar->c2s->log, LOG_NOTICE, "ntlogon: module initialised"); return 0; } #else /* _WIN32 */ DLLEXPORT int ar_init(authreg_t ar) { log_write(ar->c2s->log, LOG_ERR, "ntlogon: module is not supported on non-Windows platforms"); return 1; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_oracle.c�����������������������������������������������������0000664�0000000�0000000�00000047057�12614627753�0021410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Ubiquecom Inc. * Copyright (c) 2007 liulw * * 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, MA02111-1307USA */ /* this module talks to a Oracle server via libmysqlclient */ #include "c2s.h" #include <string.h> #include <oci.h> //#define ORACLE_LU 1024 /* maximum length of username - should correspond to field length */ //#define MYSQL_LR 256 /* maximum length of realm - should correspond to field length */ //#define MYSQL_LP 256 /* maximum length of password - should correspond to field length */ #define BLOCKSIZE (1024) #define PWSIZE (257) typedef struct Oracle_context_st { OCIEnv* ociEnvironment; OCIError* ociError; OCISvcCtx* ociService; OCIStmt* ociStatement; OCIDefine* ociDefine; // OCIBind* ociBind; // xht filters; // char *prefix; // char *svUser; // char *svPass; char* sql_create; char* sql_select; char* sql_delete; char* sql_setpassword; } *Oracle_context_t; /** internal: do and return the math and ensure it gets realloc'd */ static int _st_oracle_realloc(void **oblocks, int len) { void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen; } #define ORACLE_SAFE(blocks, size, len) if((size) > len){ len = _st_oracle_realloc((void**)&(blocks),(size)); } int checkOCIError( authreg_t ar, const char *szDoing, OCIError *m_ociError, sword nStatus ) { text txtErrorBuffer[512]; ub4 nErrorCode; switch (nStatus) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: log_write(ar->c2s->log, LOG_ERR, "(%s) Error - OCI_SUCCESS_WITH_INFO\n", szDoing); break; case OCI_NEED_DATA: log_write(ar->c2s->log, LOG_ERR, "(%s) Error - OCI_NEED_DATA\n", szDoing); break; case OCI_NO_DATA: log_write(ar->c2s->log, LOG_ERR, "(%s) Error - OCI_NODATA\n", szDoing); break; case OCI_ERROR: OCIErrorGet(m_ociError, (ub4) 1, (text *) NULL, &nErrorCode, txtErrorBuffer, (ub4) sizeof(txtErrorBuffer), OCI_HTYPE_ERROR); log_write(ar->c2s->log, LOG_ERR, "(%s) Error - %s\n", szDoing, txtErrorBuffer); break; case OCI_INVALID_HANDLE: log_write(ar->c2s->log, LOG_ERR, "(%s) Error - OCI_INVALID_HANDLE\n", szDoing); break; case OCI_STILL_EXECUTING: log_write(ar->c2s->log, LOG_ERR, "(%s) Error - OCI_STILL_EXECUTE\n", szDoing); break; default: break; } return nStatus; } static int _sql_length( char* sql ) { const char* _pt = sql; int _num = 0; while( *_pt != '\0' ) { if( *_pt == '"' )++_num; ++_pt; } return (strlen(sql) - _num); } static int _ar_oracle_get_user_tuple( authreg_t ar, char* username, char* realm ) { Oracle_context_t _ctx = (Oracle_context_t)ar->private; char* _sqlbuf = NULL; int _nNumberOfFields = 0; int _nResultCode = 0; int _len = 0; char _password[64] = { '\0' }; ORACLE_SAFE( _sqlbuf, strlen(username) + strlen(realm) + _sql_length(_ctx->sql_select), _len ); sprintf( _sqlbuf, _ctx->sql_select, username, realm ); // fprintf( stdout, "_sqlbuf = %s\n", _sqlbuf ); _nResultCode = checkOCIError( ar, "_ar_oracle_get_user_tuple: prepare statement", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, \ _ctx->ociError, _sqlbuf, strlen(_sqlbuf), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { fprintf( stdout, "OCIStmtPrepare\n" ); free( _sqlbuf ); return 1; } _nResultCode = checkOCIError(ar, "_ar_oracle_get_user_tuple:define pos", _ctx->ociError, OCIDefineByPos( _ctx->ociStatement, \ &_ctx->ociDefine, _ctx->ociError, 1, &_password, 65, SQLT_STR, 0, 0, 0, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { fprintf( stdout, "OCIDefineByPos\n" ); free( _sqlbuf ); return 1; } _nResultCode = checkOCIError( ar, "_ar_oracle_get_user_tuple:execse", _ctx->ociError, OCIStmtExecute( _ctx->ociService, \ _ctx->ociStatement, _ctx->ociError, 0, 0, 0, 0, OCI_STMT_SCROLLABLE_READONLY ) ); if( _nResultCode != 0 ) { fprintf( stdout, "OCIStmtExecute\n" ); free( _sqlbuf ); return 1; } OCIStmtFetch2( _ctx->ociStatement, _ctx->ociError, 1, OCI_FETCH_FIRST, 0, OCI_DEFAULT); free( _sqlbuf ); if( strlen(_password) != 0 )return 1; else return 0; } static int _ar_oracle_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { if( _ar_oracle_get_user_tuple(ar, username, realm ) > 0 ) { return 1; } return 0; } static int _ar_oracle_create_user( authreg_t ar, sess_t sess, const char *username, const char *realm ) { Oracle_context_t _ctx = (Oracle_context_t)ar->private; char* _sqlbuf = NULL; int _len = 0; int _nResultCode = 0; int errcode; char errbuf[512]; ORACLE_SAFE( _sqlbuf, strlen(username) + strlen(realm) + _sql_length(_ctx->sql_create), _len ); sprintf( _sqlbuf, _ctx->sql_create, username, realm ); _nResultCode = checkOCIError( ar, "_ar_oracle_create_user:prepare", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, _ctx->ociError,\ _sqlbuf, (ub4)strlen(_sqlbuf), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "_ar_oracle_create_user:execute", _ctx->ociError, OCIStmtExecute( _ctx->ociService, _ctx->ociStatement, _ctx->ociError, 1, 0, 0, 0, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { OCIErrorGet((dvoid *)_ctx->ociError, (ub4)1, (text *)NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); fprintf(stdout, "%.*s\n", 512, errbuf); fprintf( stdout, "eaarror..\n" ); return -1; } return 0; } int _ar_oracle_get_authreg_user( authreg_t ar ) { Oracle_context_t _ctx = (Oracle_context_t)ar->private; char _sql[] = { "select count(*) from \"authreg\"" }; int _nNumberOfFields = 0; int _nResultCode = 0; /*start action via oracle*/ _nResultCode = checkOCIError( ar, "_st_oracle_get: prepare statement", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, _ctx->ociError,\ _sql, (ub4)strlen(_sql), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "_st_oracle_get: Define pos", _ctx->ociError, OCIDefineByPos( _ctx->ociStatement, &_ctx->ociDefine, \ _ctx->ociError, 1, (dvoid*)&_nNumberOfFields, sizeof(_nNumberOfFields), SQLT_INT, 0, 0, 0, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "_st_oracle_get: Statement descript", _ctx->ociError, OCIStmtExecute( _ctx->ociService, \ _ctx->ociStatement, _ctx->ociError, 0, 0, 0, 0, OCI_STMT_SCROLLABLE_READONLY ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "", _ctx->ociError, OCIStmtFetch2( _ctx->ociStatement, _ctx->ociError, 1, OCI_FETCH_FIRST, 0, \ OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } return _nNumberOfFields; } static int _ar_oracle_get_password( authreg_t ar, sess_t sess, const char *username, const char *realm, char password[PWSIZE] ) { Oracle_context_t _ctx = (Oracle_context_t)ar->private; char* _sqlbuf = NULL; int _nNumberOfFields = 0; int _nResultCode = 0; int _len = 0; char _password[PWSIZE]; memset( _password, '\0', sizeof(_password) ); ORACLE_SAFE( _sqlbuf, strlen(username) + strlen(realm) + _sql_length(_ctx->sql_select), _len ); sprintf( _sqlbuf, _ctx->sql_select, username, realm ); _nResultCode = checkOCIError( ar, "_ar_oracle_get_user_tuple: prepare statement", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, \ _ctx->ociError, _sqlbuf, strlen(_sqlbuf), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { free( _sqlbuf ); return -1; } _nResultCode = checkOCIError(ar, "_ar_oracle_get_user_tuple:define pos", _ctx->ociError, OCIDefineByPos( _ctx->ociStatement, \ &_ctx->ociDefine, _ctx->ociError, 1, &_password, PWSIZE, SQLT_STR, 0, 0, 0, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { free( _sqlbuf ); return -1; } _nResultCode = checkOCIError( ar, "_ar_oracle_get_user_tuple:execse", _ctx->ociError, OCIStmtExecute( _ctx->ociService, \ _ctx->ociStatement, _ctx->ociError, 0, 0, 0, 0, OCI_STMT_SCROLLABLE_READONLY ) ); if( _nResultCode != 0 ) { free( _sqlbuf ); return -1; } OCIStmtFetch2( _ctx->ociStatement, _ctx->ociError, 1, OCI_FETCH_FIRST, 0, OCI_DEFAULT ); free( _sqlbuf ); strncpy( password, _password, PWSIZE - 1 ); password[PWSIZE - 1] = '\0'; return 0; } static int _ar_oracle_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[PWSIZE]) { Oracle_context_t _ctx = (Oracle_context_t)ar->private; char* _sqlbuf = NULL; int _len = 0; int _nResultCode = 0; ORACLE_SAFE( _sqlbuf, strlen(username) + strlen(realm) + strlen(password) + _sql_length(_ctx->sql_setpassword), _len ); sprintf( _sqlbuf, _ctx->sql_setpassword, password, username, realm ); _nResultCode = checkOCIError( ar, "_ar_oracle_set_password:prepare", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, _ctx->ociError,\ _sqlbuf, (ub4)strlen(_sqlbuf), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "_ar_oracle_set_password:execute", _ctx->ociError, OCIStmtExecute( _ctx->ociService, \ _ctx->ociStatement, _ctx->ociError, 1, 0, 0, 0, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { fprintf( stdout, "error \n" ); return -1; } return 0; } static int _ar_oracle_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { if( _ar_oracle_get_user_tuple(ar, username, realm ) == 0 )return 0; Oracle_context_t _ctx = (Oracle_context_t)ar->private; char* _sqlbuf = NULL; int _len = 0; int _nResultCode = 0; ORACLE_SAFE( _sqlbuf, strlen(username) + strlen(realm) + _sql_length(_ctx->sql_delete), _len ); sprintf( _sqlbuf, _ctx->sql_delete, username, realm ); _nResultCode = checkOCIError( ar, "_ar_oracle_delete_user:prepare", _ctx->ociError, OCIStmtPrepare( _ctx->ociStatement, _ctx->ociError,\ _sqlbuf, (ub4)strlen(_sqlbuf), OCI_NTV_SYNTAX, OCI_DEFAULT ) ); if( _nResultCode != 0 ) { return -1; } _nResultCode = checkOCIError( ar, "_ar_oracle_delete_user:execute", _ctx->ociError, OCIStmtExecute( _ctx->ociService, \ _ctx->ociStatement, _ctx->ociError, 1, 0, 0, 0, OCI_COMMIT_ON_SUCCESS ) ); if( _nResultCode != 0 ) { return -1; } return 0; } static void _ar_oracle_free( authreg_t ar ) { Oracle_context_t ctx = (Oracle_context_t)ar->private; OCILogoff( ctx->ociService, ctx->ociError ); OCIHandleFree( (dvoid *)ctx->ociStatement, OCI_HTYPE_STMT ); OCIHandleFree( (dvoid *)ctx->ociService, OCI_HTYPE_SVCCTX ); OCIHandleFree( (dvoid *)ctx->ociError, OCI_HTYPE_ERROR ); OCIHandleFree( (dvoid *)ctx->ociEnvironment, OCI_HTYPE_ENV ); free(ctx); } /** Provide a configuration parameter or default value. */ static char * _ar_oracle_param( config_t c, const char * key, const char * def ) { char * value = config_get_one( c, key, 0 ); if( value == NULL ) return def; else return value; } /** start me up */ int ar_init(authreg_t ar) { char *host, *port, *dbname, *user, *pass, *oracle_server_host = NULL; char *create, *select, *setpassword, *delete; char table[] = { "\"authreg\"" }; char username[] = { "\"username\"" }; char realm[] = { "\"realm\"" }; char password[] = { "\"password\"" }; int nResultCode = 0, _len = 0; static char* oracle_server_parameters = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=\"%s\")(PORT=\"%s\"))(CONNECT_DATA=(SID=\"%s\")))"; Oracle_context_t oraclecontext; OCIEnv *ociEnvironment; OCIError *ociError; OCISvcCtx *ociService; OCIStmt *ociStatement; /* configure the database context with field names and SQL statements */ oraclecontext = (Oracle_context_t)malloc( sizeof( struct Oracle_context_st ) ); ar->private = oraclecontext; ar->free = _ar_oracle_free; /* craft the default SQL statements */ /* we leave unused statements allocated to simplify code - a small price to pay */ /* bounds checking and parameter format verification will be perfomed if the statement is used (see next section) */ /* For malloc(), there is no +1 for trailing 0 as parameter substitution will net us several extra characters */ create = strdup( "INSERT INTO \"authreg\" ( \"username\", \"realm\" ) VALUES ( '%s', '%s' )" ); select = strdup( "SELECT \"password\" FROM \"authreg\" WHERE \"username\" = '%s' AND \"realm\" = '%s'" ); setpassword = strdup( "UPDATE \"authreg\" SET \"password\" = '%s' WHERE \"username\" = '%s' AND \"realm\" = '%s'" ); delete = strdup( "DELETE FROM \"authreg\" WHERE \"username\" = '%s' AND \"realm\" = '%s'" ); /* allow the default SQL statements to be overridden; also verify the statements format and length */ oraclecontext->sql_create = strdup(_ar_oracle_param( ar->c2s->config , "authreg.oracle.sql.create" , create )); oraclecontext->sql_select = strdup(_ar_oracle_param( ar->c2s->config , "authreg.oracle.sql.select" , select )); oraclecontext->sql_setpassword = strdup(_ar_oracle_param( ar->c2s->config , "authreg.oracle.sql.setpassword" , setpassword )); oraclecontext->sql_delete = strdup(_ar_oracle_param( ar->c2s->config , "authreg.oracle.sql.delete" , delete )); /* echo our configuration to debug */ log_debug( ZONE, "SQL to create account: %s", oraclecontext->sql_create ); log_debug( ZONE, "SQL to query user information: %s", oraclecontext->sql_select ); log_debug( ZONE, "SQL to set password: %s", oraclecontext->sql_setpassword ); log_debug( ZONE, "SQL to delete account: %s", oraclecontext->sql_delete ); free(create); free(select); free(setpassword); free(delete); host = config_get_one(ar->c2s->config, "authreg.oracle.host", 0); port = config_get_one(ar->c2s->config, "authreg.oracle.port", 0); dbname = config_get_one(ar->c2s->config, "authreg.oracle.dbname", 0); user = config_get_one(ar->c2s->config, "authreg.oracle.user", 0); pass = config_get_one(ar->c2s->config, "authreg.oracle.pass", 0); if(host == NULL || port == NULL || dbname == NULL || user == NULL || pass == NULL) { log_write(ar->c2s->log, LOG_ERR, "oracle: invalid module config"); return 1; } ORACLE_SAFE( oracle_server_host, strlen(host) + strlen(port) + strlen(dbname) + _sql_length(oracle_server_parameters), _len ); sprintf( oracle_server_host, oracle_server_parameters, host, port, dbname ); log_debug( ZONE, "OCI connecting as '%s' to database '%s' on %s:%s", user, dbname, host, port ); nResultCode = OCIEnvCreate( (OCIEnv**)&ociEnvironment, OCI_DEFAULT, (dvoid*)0, 0, 0, 0, (size_t)0, (dvoid **)0 ); if (nResultCode != 0) { log_write(ar->c2s->log, LOG_ERR, "(st_oracle_init: ) Could not Initialize OCI Environment (%d)", nResultCode); return 1; } /* Initialize handles */ nResultCode = OCIHandleAlloc( (dvoid *)ociEnvironment, (dvoid **) &ociError, OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0 ); if (nResultCode != 0) { log_write(ar->c2s->log, LOG_ERR, "(st_oracle_init: ) Could not create OCI Error object (%d)" , nResultCode); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return 1; } nResultCode = checkOCIError(ar, "st_oracle_init: Allocate Service", ociError, OCIHandleAlloc((dvoid *)ociEnvironment, (dvoid **)&ociService, OCI_HTYPE_SVCCTX, (size_t)NULL, (dvoid **)NULL) ); if (nResultCode != 0) { nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return 1; } /* Connect to database server */ nResultCode = checkOCIError(ar, "st_oracle_init: Connect to Server", ociError, OCILogon(ociEnvironment, ociError, &ociService, user, strlen(user), pass, strlen(pass), oracle_server_host, strlen(oracle_server_host))); if (nResultCode != 0) { nResultCode = OCIHandleFree((dvoid *) ociService, OCI_HTYPE_SVCCTX); nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return 1; } /* Allocate and prepare SQL statement */ nResultCode = checkOCIError(ar, "st_oracle_init: Allocate Statement", ociError, OCIHandleAlloc((dvoid *)ociEnvironment, (dvoid **)&ociStatement, OCI_HTYPE_STMT, (size_t)NULL, (dvoid **)NULL)); if (nResultCode != 0) { nResultCode = OCILogoff(ociService, ociError); nResultCode = OCIHandleFree((dvoid *) ociService, OCI_HTYPE_SVCCTX); nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return 1; } free(oracle_server_host); oraclecontext->ociEnvironment = ociEnvironment; oraclecontext->ociError = ociError; oraclecontext->ociService = ociService; oraclecontext->ociStatement = ociStatement; ar->user_exists = _ar_oracle_user_exists; ar->get_password = _ar_oracle_get_password; ar->set_password = _ar_oracle_set_password; ar->create_user = _ar_oracle_create_user; ar->delete_user = _ar_oracle_delete_user; return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_pam.c��������������������������������������������������������0000664�0000000�0000000�00000007464�12614627753�0020716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this plugin uses PAM for authentication */ #include "c2s.h" #include <security/pam_appl.h> static int _ar_pam_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { /* we can't check if a user exists, so we just assume we have them all the time */ return 1; } static int _ar_pam_conversation(int nmsg, const struct pam_message **msg, struct pam_response **res, void *arg) { int i; struct pam_response *reply; if(nmsg <= 0) return PAM_CONV_ERR; reply = (struct pam_response *) calloc(1, sizeof(struct pam_response) * nmsg); for(i = 0; i < nmsg; i++) { if(msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || msg[i]->msg_style == PAM_PROMPT_ECHO_ON) { reply[i].resp = strdup((char *) arg); reply[i].resp_retcode = 0; } } *res = reply; return PAM_SUCCESS; } #ifdef PAM_FAIL_DELAY static int _ar_pam_delay(int ret, unsigned int usec, void *arg) { /* !!! hack the current byterate limit to throttle the connection */ return PAM_SUCCESS; } #endif static int _ar_pam_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { struct pam_conv conv; pam_handle_t *pam; int ret, user_len, realm_len; char *user_realm = 0; conv.conv = _ar_pam_conversation; conv.appdata_ptr = password; if (realm) { realm_len = strlen(realm); if (realm_len > 0) { user_len = strlen(username); user_realm = malloc(user_len + realm_len + 2); strcpy(user_realm, username); *(user_realm + user_len) = '@'; strcpy(user_realm + user_len + 1, realm); } } if (user_realm) { ret = pam_start("jabberd", user_realm, &conv, &pam); } else { ret = pam_start("jabberd", username, &conv, &pam); } if (user_realm) free(user_realm); if(ret != PAM_SUCCESS) { log_write(ar->c2s->log, LOG_ERR, "pam: couldn't initialise PAM: %s", pam_strerror(NULL, ret)); return 1; } #ifdef PAM_FAIL_DELAY ret = pam_set_item(pam, PAM_FAIL_DELAY, _ar_pam_delay); if(ret != PAM_SUCCESS) { log_write(ar->c2s->log, LOG_ERR, "pam: couldn't disable fail delay: %s", pam_strerror(NULL, ret)); return 1; } #endif ret = pam_authenticate(pam, 0); if(ret == PAM_AUTHINFO_UNAVAIL || ret == PAM_USER_UNKNOWN) { pam_end(pam, ret); return 1; } if(ret != PAM_SUCCESS) { log_write(ar->c2s->log, LOG_ERR, "pam: couldn't authenticate: %s", pam_strerror(NULL, ret)); pam_end(pam, ret); return 1; } ret = pam_acct_mgmt(pam, 0); if(ret != PAM_SUCCESS) { log_write(ar->c2s->log, LOG_ERR, "pam: authentication succeeded, but can't use account: %s", pam_strerror(NULL, ret)); pam_end(pam, ret); return 1; } pam_end(pam, ret); return 0; } /** start me up */ int ar_init(authreg_t ar) { ar->user_exists = _ar_pam_user_exists; ar->check_password = _ar_pam_check_password; return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_pgsql.c������������������������������������������������������0000664�0000000�0000000�00000062137�12614627753�0021265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this module talks to a PostgreSQL server via libpq */ #define _XOPEN_SOURCE 500 #include "c2s.h" #include <libpq-fe.h> /* Windows does not have the crypt() function, let's take DES_crypt from OpenSSL instead */ #if defined(HAVE_OPENSSL_CRYPTO_H) && defined(_WIN32) #include <openssl/des.h> #define crypt DES_crypt #define HAVE_CRYPT 1 #else #ifdef HAVE_CRYPT #include <unistd.h> #endif #endif #ifdef HAVE_SSL /* We use OpenSSL's MD5 routines for the a1hash password type */ #include <openssl/md5.h> #include <openssl/rand.h> #include <util/crypt_blowfish.h> #endif #define PGSQL_LU 1024 /* maximum length of username - should correspond to field length */ #define PGSQL_LR 256 /* maximum length of realm - should correspond to field length */ #define PGSQL_LP 256 /* maximum length of password - should correspond to field length */ enum pgsql_pws_crypt { MPC_PLAIN, #ifdef HAVE_CRYPT MPC_CRYPT, #endif #ifdef HAVE_SSL MPC_A1HASH, MPC_BCRYPT, #endif }; #ifdef HAVE_CRYPT static char salter[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; #endif typedef struct pgsqlcontext_st { PGconn * conn; const char * sql_create; const char * sql_select; const char * sql_setpassword; const char * sql_delete; const char * sql_check_password; const char * field_password; enum pgsql_pws_crypt password_type; #ifdef HAVE_SSL int bcrypt_cost; #endif } *pgsqlcontext_t; #ifdef HAVE_SSL static void calc_a1hash(const char *username, const char *realm, const char *password, char *a1hash) { #define A1PPASS_LEN PGSQL_LU + 1 + PGSQL_LR + 1 + PGSQL_LP + 1 /* user:realm:password\0 */ char buf[A1PPASS_LEN]; unsigned char md5digest[MD5_DIGEST_LENGTH]; int i; snprintf(buf, A1PPASS_LEN, "%.*s:%.*s:%.*s", PGSQL_LU, username, PGSQL_LR, realm, PGSQL_LP, password); MD5((unsigned char*)buf, strlen(buf), md5digest); for(i=0; i<16; i++) { sprintf(a1hash+i*2, "%02hhx", md5digest[i]); } } static void bcrypt_hash(const char *password, int cost, char* hash) { char salt[16]; if(!RAND_bytes(salt, 16)) ; //we've got a problem char* gen = bcrypt_gensalt("$2y$", cost, salt, 16); strcpy(hash, bcrypt(password, gen)); } static int bcrypt_verify(const char *password, const char* hash) { char *ret; ret = bcrypt(password, hash); if(strlen(ret) != strlen(hash)) return 1; int status = 0; int i = 0; for(i; i < strlen(ret); i++) status |= (ret[i] ^ hash[i]); return status != 0; } static int bcrypt_needs_rehash(int current_cost, const char* hash) { int hash_cost; sscanf(hash, "$2y$%d$", &hash_cost); if(current_cost != hash_cost) return 1; return 0; } #endif static PGresult *_ar_pgsql_get_user_tuple(authreg_t ar, const char *username, const char *realm) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; char iuser[PGSQL_LU+1], irealm[PGSQL_LR+1]; char euser[PGSQL_LU*2+1], erealm[PGSQL_LR*2+1], sql[1024+PGSQL_LU*2+PGSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ PGresult *res; snprintf(iuser, PGSQL_LU+1, "%s", username); snprintf(irealm, PGSQL_LR+1, "%s", realm); PQescapeString(euser, iuser, strlen(iuser)); PQescapeString(erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_select, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); res = PQexec(conn, sql); if(PQresultStatus(res) != PGRES_TUPLES_OK && PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(conn); if(PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); return NULL; } res = PQexec(conn, sql); } if(PQresultStatus(res) != PGRES_TUPLES_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: sql select failed: %s", PQresultErrorMessage(res)); PQclear(res); return NULL; } if(PQntuples(res) != 1) { PQclear(res); return NULL; } return res; } static int _ar_pgsql_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { /* check a user exists regardless of password type */ PGresult *res = _ar_pgsql_get_user_tuple(ar, username, realm); if(res != NULL) { PQclear(res); return 1; } return 0; } static int _ar_pgsql_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGresult *res = _ar_pgsql_get_user_tuple(ar, username, realm); int fpass; if(res == NULL) return 1; fpass = PQfnumber(res, ctx->field_password); if(fpass == -1) { log_debug(ZONE, "weird, password field wasn't returned"); PQclear(res); return 1; } if(PQgetisnull(res, 0, fpass)) { PQclear(res); return 1; } strcpy(password, PQgetvalue(res, 0, fpass)); PQclear(res); return 0; } static int _ar_pgsql_dbcheck_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; char iuser[PGSQL_LU+1], irealm[PGSQL_LR+1], ipassword[PGSQL_LR+1]; char euser[PGSQL_LU*2+1], erealm[PGSQL_LR*2+1], epassword[PGSQL_LR*2+1], sql[1024+PGSQL_LU*2+PGSQL_LR*2+1+PGSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ PGresult *res; snprintf(iuser, PGSQL_LU+1, "%s", username); snprintf(irealm, PGSQL_LR+1, "%s", realm); snprintf(ipassword, PGSQL_LR+1, "%s", password); PQescapeString(euser, iuser, strlen(iuser)); PQescapeString(erealm, irealm, strlen(irealm)); PQescapeString(epassword, ipassword, strlen(ipassword)); sprintf(sql, ctx->sql_check_password, euser, epassword, erealm); log_debug(ZONE, "prepared sql: %s", sql); res = PQexec(conn, sql); if(PQresultStatus(res) != PGRES_TUPLES_OK && PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(conn); if(PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); return 1; } res = PQexec(conn, sql); } if(PQresultStatus(res) != PGRES_TUPLES_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: sql select failed: %s", PQresultErrorMessage(res)); PQclear(res); return 1; } if(PQntuples(res) != 1) { log_write(ar->c2s->log, LOG_ERR, "pgsql: Empty result"); PQclear(res); return 1; } int retval = 1; if(PQgetisnull(res, 0, 0)) { log_debug(ZONE, "pgsql: check_password returns NULL"); PQclear(res); return 1; } const char *result = PQgetvalue(res, 0, 0); log_debug(ZONE, "pgsql: check_password result: '%s'", result); if (strcmp("0", result) != 0) { // something except 0 -> authenticated retval = 0; } else { retval = 1; } PQclear(res); return retval; }; static int _ar_pgsql_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; char iuser[PGSQL_LU+1], irealm[PGSQL_LR+1]; char euser[PGSQL_LU*2+1], erealm[PGSQL_LR*2+1], epass[513], sql[1024+PGSQL_LU*2+PGSQL_LR*2+512+1]; /* query(1024) + euser + erealm + epass(512) + \0(1) */ PGresult *res; snprintf(iuser, PGSQL_LU+1, "%s", username); snprintf(irealm, PGSQL_LR+1, "%s", realm); #ifdef HAVE_CRYPT if (ctx->password_type == MPC_CRYPT) { char salt[39] = "$6$rounds=50000$"; int i; srand(time(0)); for(i=0; i<22; i++) salt[16+i] = salter[rand()%64]; salt[38] = '\0'; strcpy(password, crypt(password, salt)); } #endif #ifdef HAVE_SSL if (ctx->password_type == MPC_A1HASH) { calc_a1hash(username, realm, password, password); } else if (ctx->password_type == MPC_BCRYPT) { bcrypt_hash(password, ctx->bcrypt_cost, password); } #endif PQescapeString(euser, iuser, strlen(iuser)); PQescapeString(erealm, irealm, strlen(irealm)); PQescapeString(epass, password, strlen(password)); sprintf(sql, ctx->sql_setpassword, epass, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); res = PQexec(conn, sql); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(conn); if(PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); return 1; } res = PQexec(conn, sql); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: sql update failed: %s", PQresultErrorMessage(res)); PQclear(res); return 1; } PQclear(res); return 0; } static int _ar_pgsql_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; char db_pw_value[257]; #ifdef HAVE_CRYPT char *crypted_pw; #endif #ifdef HAVE_SSL char a1hash_pw[33]; #endif int ret; ret = _ar_pgsql_get_password(ar, sess, username, realm, db_pw_value); /* return if error */ if (ret) return ret; switch (ctx->password_type) { case MPC_PLAIN: ret = (strcmp(password, db_pw_value) != 0); break; #ifdef HAVE_CRYPT case MPC_CRYPT: crypted_pw = crypt(password,db_pw_value); ret = (strcmp(crypted_pw, db_pw_value) != 0); break; #endif #ifdef HAVE_SSL case MPC_A1HASH: if (strchr(username, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Username cannot contain : with a1hash encryption type."); break; } if (strchr(realm, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Realm cannot contain : with a1hash encryption type."); break; } calc_a1hash(username, realm, password, a1hash_pw); ret = (strncmp(a1hash_pw, db_pw_value, 32) != 0); break; case MPC_BCRYPT: ret = bcrypt_verify(password, db_pw_value); if(ret == 0) { if (bcrypt_needs_rehash(ctx->bcrypt_cost, db_pw_value)) { char tmp[257]; strcpy(tmp, password); _ar_pgsql_set_password(ar, sess, username, realm, tmp); } } break; #endif default: /* should never happen */ ret = 1; log_write(ar->c2s->log, LOG_ERR, "Unknown encryption type which passed through config check."); break; } return ret; } static int _ar_pgsql_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; char iuser[PGSQL_LU+1], irealm[PGSQL_LR+1]; char euser[PGSQL_LU*2+1], erealm[PGSQL_LR*2+1], sql[1024+PGSQL_LU*2+PGSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ PGresult *res; res = _ar_pgsql_get_user_tuple(ar, username, realm); if(res != NULL) { PQclear(res); return 1; } PQclear(res); snprintf(iuser, PGSQL_LU+1, "%s", username); snprintf(irealm, PGSQL_LR+1, "%s", realm); PQescapeString(euser, iuser, strlen(iuser)); PQescapeString(erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_create, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); res = PQexec(conn, sql); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(conn); if(PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); return 1; } res = PQexec(conn, sql); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: sql insert failed: %s", PQresultErrorMessage(res)); PQclear(res); return 1; } PQclear(res); return 0; } static int _ar_pgsql_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; char iuser[PGSQL_LU+1], irealm[PGSQL_LR+1]; char euser[PGSQL_LU*2+1], erealm[PGSQL_LR*2+1], sql[1024+PGSQL_LU*2+PGSQL_LR*2+1]; /* query(1024) + euser + erealm + \0(1) */ PGresult *res; snprintf(iuser, PGSQL_LU+1, "%s", username); snprintf(irealm, PGSQL_LR+1, "%s", realm); PQescapeString(euser, iuser, strlen(iuser)); PQescapeString(erealm, irealm, strlen(irealm)); sprintf(sql, ctx->sql_delete, euser, erealm); log_debug(ZONE, "prepared sql: %s", sql); res = PQexec(conn, sql); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(conn); if(PQstatus(conn) != CONNECTION_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); return 1; } res = PQexec(conn, sql); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(ar->c2s->log, LOG_ERR, "pgsql: sql delete failed: %s", PQresultErrorMessage(res)); PQclear(res); return 1; } PQclear(res); return 0; } static void _ar_pgsql_free(authreg_t ar) { pgsqlcontext_t ctx = (pgsqlcontext_t) ar->private; PGconn *conn = ctx->conn; if(conn != NULL) PQfinish(conn); free((void*)ctx->sql_create); free((void*)ctx->sql_select); free((void*)ctx->sql_setpassword); free((void*)ctx->sql_delete); if (ctx->sql_check_password) { free((void*)ctx->sql_check_password); } free(ctx); } /** Provide a configuration parameter or default value. */ static const char * _ar_pgsql_param( config_t c, const char * key, const char * def ) { const char * value = config_get_one( c, key, 0 ); if( value == NULL ) return def; else return value; } /* Ensure the sprintf template is less than 1K long and contains the */ /* required parameter placeholder types. The types string contains */ /* one each, in order, of the one character sprintf types that are */ /* expected to follow the escape characters '%' in the template. */ /* Returns 0 on success, or an error message on failures. */ static const char * _ar_pgsql_check_template( const char * template, const char * types ) { int pScan = 0; int pType = 0; char c; /* check that it's 1K or less */ if( strlen( template ) > 1024 ) return "longer than 1024 characters"; /* count the parameter placeholders */ while( pScan < strlen( template ) ) { if( template[ pScan++ ] != '%' ) continue; c = template[ pScan++ ]; if( c == '%' ) continue; /* ignore escaped precentages */ if( c == types[ pType ] ) { /* we found the placeholder */ pType++; /* search for the next type */ continue; } /* we found an unexpected placeholder type */ return "contained unexpected placeholder type"; } if( pType < strlen( types ) ) return "contained too few placeholders"; else return 0; } /* Ensure the SQL template is less than 1K long and contains the */ /* required parameter placeholders. If there is an error, it is */ /* written to the error log. */ /* Returns 0 on success, or 1 on errors. */ int _ar_pgsql_check_sql( authreg_t ar, const char * sql, const char * types ) { const char * error; error = _ar_pgsql_check_template( sql, types ); if( error == 0 ) return 0; /* alls right :) */ /* signal error */ log_write( ar->c2s->log, LOG_ERR, "pgsql: template error: %s - %s", error, sql ); return 1; } #ifdef HAVE_SSL extern int sx_openssl_initialized; #endif /** start me up */ int ar_init(authreg_t ar) { const char *host, *port, *dbname, *schema, *user, *pass, *conninfo; char *create, *select, *setpassword, *delete, *setsearchpath; const char *table, *username, *realm; char *template; int strlentur; /* string length of table, user, and realm strings */ PGconn *conn; pgsqlcontext_t pgsqlcontext; /* configure the database context with field names and SQL statements */ pgsqlcontext = (pgsqlcontext_t) calloc(1, sizeof( struct pgsqlcontext_st ) ); ar->private = pgsqlcontext; ar->free = _ar_pgsql_free; /* determine our field names and table name */ username = _ar_pgsql_param( ar->c2s->config , "authreg.pgsql.field.username" , "username" ); realm = _ar_pgsql_param( ar->c2s->config , "authreg.pgsql.field.realm" , "realm" ); pgsqlcontext->field_password = _ar_pgsql_param( ar->c2s->config , "authreg.pgsql.field.password" , "password" ); table = _ar_pgsql_param( ar->c2s->config , "authreg.pgsql.table" , "authreg" ); /* get encryption type used in DB */ if (config_get_one(ar->c2s->config, "authreg.pgsql.password_type.plaintext", 0)) { pgsqlcontext->password_type = MPC_PLAIN; #ifdef HAVE_CRYPT } else if (config_get_one(ar->c2s->config, "authreg.pgsql.password_type.crypt", 0)) { pgsqlcontext->password_type = MPC_CRYPT; #endif #ifdef HAVE_SSL } else if (config_get_one(ar->c2s->config, "authreg.pgsql.password_type.a1hash", 0)) { pgsqlcontext->password_type = MPC_A1HASH; } else if (config_get_one(ar->c2s->config, "authreg.pgsql.password_type.bcrypt", 0)) { pgsqlcontext->password_type = MPC_BCRYPT; int cost; if(cost = j_atoi(config_get_attr(ar->c2s->config, "authreg.pgsql.password_type.bcrypt", 0, "cost"), 0)) { if (cost < 4 || cost > 31) { log_write(ar->c2s->log, LOG_ERR, "bcrypt cost has to be higher than 3 and lower than 32."); pgsqlcontext->bcrypt_cost = 10; // use default } else { pgsqlcontext->bcrypt_cost = cost; } } #endif } else { pgsqlcontext->password_type = MPC_PLAIN; } /* craft the default SQL statements */ /* we leave unused statements allocated to simplify code - a small price to pay */ /* bounds checking and parameter format verification will be perfomed if the statement is used (see next section) */ /* For malloc(), there is no +1 for trailing 0 as parameter substitution will net us several extra characters */ strlentur = strlen( table ) + strlen( username) + strlen( realm ); /* avoid repetition */ template = "INSERT INTO \"%s\" ( \"%s\", \"%s\" ) VALUES ( '%%s', '%%s' )"; create = malloc( strlen( template ) + strlentur ); sprintf( create, template, table, username, realm ); template = "SELECT \"%s\" FROM \"%s\" WHERE \"%s\" = '%%s' AND \"%s\" = '%%s'"; select = malloc( strlen( template ) + strlen( pgsqlcontext->field_password ) + strlentur ); sprintf( select, template , pgsqlcontext->field_password , table, username, realm ); template = "UPDATE \"%s\" SET \"%s\" = '%%s' WHERE \"%s\" = '%%s' AND \"%s\" = '%%s'"; setpassword = malloc( strlen( template ) + strlentur + strlen( pgsqlcontext->field_password ) ); sprintf( setpassword, template, table, pgsqlcontext->field_password, username, realm ); template = "DELETE FROM \"%s\" WHERE \"%s\" = '%%s' AND \"%s\" = '%%s'"; delete = malloc( strlen( template ) + strlentur ); sprintf( delete, template, table, username, realm ); /* allow the default SQL statements to be overridden; also verify the statements format and length */ pgsqlcontext->sql_create = strdup(_ar_pgsql_param( ar->c2s->config , "authreg.pgsql.sql.create" , create )); if( _ar_pgsql_check_sql( ar, pgsqlcontext->sql_create, "ss" ) != 0 ) return 1; pgsqlcontext->sql_select = strdup(_ar_pgsql_param( ar->c2s->config , "authreg.pgsql.sql.select" , select )); if( _ar_pgsql_check_sql( ar, pgsqlcontext->sql_select, "ss" ) != 0 ) return 1; pgsqlcontext->sql_setpassword = strdup(_ar_pgsql_param( ar->c2s->config , "authreg.pgsql.sql.setpassword" , setpassword )); if( _ar_pgsql_check_sql( ar, pgsqlcontext->sql_setpassword, "sss" ) != 0 ) return 1; pgsqlcontext->sql_delete = strdup(_ar_pgsql_param( ar->c2s->config , "authreg.pgsql.sql.delete" , delete )); if( _ar_pgsql_check_sql( ar, pgsqlcontext->sql_delete, "ss" ) != 0 ) return 1; // Check password is optional const char *sql_check_password = _ar_pgsql_param( ar->c2s->config, "authreg.pgsql.sql.checkpassword", 0); if (sql_check_password) { ar->check_password = _ar_pgsql_dbcheck_password; pgsqlcontext->sql_check_password = strdup(sql_check_password); if( _ar_pgsql_check_sql( ar, pgsqlcontext->sql_check_password, "sss" ) != 0 ) return 1; } else ar->check_password = _ar_pgsql_check_password; /* echo our configuration to debug */ log_debug( ZONE, "SQL to create account: %s", pgsqlcontext->sql_create ); log_debug( ZONE, "SQL to query user information: %s", pgsqlcontext->sql_select ); log_debug( ZONE, "SQL to set password: %s", pgsqlcontext->sql_setpassword ); log_debug( ZONE, "SQL to delete account: %s", pgsqlcontext->sql_delete ); log_debug( ZONE, "SQL to check password: %s", pgsqlcontext->sql_check_password ); free(create); free(select); free(setpassword); free(delete); #ifdef HAVE_SSL if(sx_openssl_initialized) PQinitSSL(0); #endif host = config_get_one(ar->c2s->config, "authreg.pgsql.host", 0); port = config_get_one(ar->c2s->config, "authreg.pgsql.port", 0); dbname = config_get_one(ar->c2s->config, "authreg.pgsql.dbname", 0); schema = config_get_one(ar->c2s->config, "authreg.pgsql.schema", 0); user = config_get_one(ar->c2s->config, "authreg.pgsql.user", 0); pass = config_get_one(ar->c2s->config, "authreg.pgsql.pass", 0); conninfo = config_get_one(ar->c2s->config,"authreg.pgsql.conninfo",0); if(conninfo) { /* don't log connection info for it can contain password */ log_debug( ZONE, "pgsql connecting to the databse"); conn = PQconnectdb(conninfo); } else { /* compatibility settings */ log_debug( ZONE, "pgsql connecting as '%s' to database '%s' on %s:%s", user, dbname, host, port ); conn = PQsetdbLogin(host, port, NULL, NULL, dbname, user, pass); } if(conn == NULL) { log_write(ar->c2s->log, LOG_ERR, "pgsql: unable to allocate database connection state"); return 1; } if(PQstatus(conn) != CONNECTION_OK) log_write(ar->c2s->log, LOG_ERR, "pgsql: connection to database failed, will retry later: %s", PQerrorMessage(conn)); if (schema) { template = "SET search_path TO \"%s\""; setsearchpath = malloc( strlen( template ) + strlen(schema) ); sprintf( setsearchpath, template, schema ); PQexec(conn, setsearchpath); free(setsearchpath); } pgsqlcontext->conn = conn; ar->user_exists = _ar_pgsql_user_exists; if (MPC_PLAIN == pgsqlcontext->password_type) { /* only possible with plaintext passwords */ ar->get_password = _ar_pgsql_get_password; } else { ar->get_password = NULL; } ar->set_password = _ar_pgsql_set_password; ar->create_user = _ar_pgsql_create_user; ar->delete_user = _ar_pgsql_delete_user; return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_pipe.c�������������������������������������������������������0000664�0000000�0000000�00000023072�12614627753�0021067�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* * this is the fabled pipe authenticator. it forks and executes a * script, and talks to it via stdio. this is a great way to take * advantage of existing code (in any language) to do authentication and * registration. * * there is an example script, tools/pipe-auth.pl, which can be used to * get started writing a pipe module. the protocol is documented in * docs/dev/c2s-pipe-authenticator */ /* * !!! this is highly experimental - be prepared for random acts of weirdness * if you decide to use this. */ #include "c2s.h" #include <sys/wait.h> /** internal structure, holds our data */ typedef struct moddata_st { const char *exec; pid_t child; int in, out; } *moddata_t; static int _ar_pipe_write(authreg_t ar, int fd, const char *msgfmt, ...) { va_list args; char buf[1024]; int ret; va_start(args, msgfmt); vsnprintf(buf, 1024, msgfmt, args); va_end(args); log_debug(ZONE, "writing to pipe: %s", buf); ret = write(fd, buf, strlen(buf)); if(ret < 0) log_write(ar->c2s->log, LOG_ERR, "pipe: write to pipe failed: %s", strerror(errno)); return ret; } static int _ar_pipe_read(authreg_t ar, int fd, char *buf, int buflen) { int ret; char *c; ret = read(fd, buf, buflen); if(ret == 0) log_write(ar->c2s->log, LOG_ERR, "pipe: got EOF from pipe"); if(ret < 0) log_write(ar->c2s->log, LOG_ERR, "pipe: read from pipe failed: %s", strerror(errno)); if(ret <= 0) return ret; buf[ret] = '\0'; c = strchr(buf, '\n'); if(c != NULL) *c = '\0'; log_debug(ZONE, "read from pipe: %s", buf); return ret; } static int _ar_pipe_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { moddata_t data = (moddata_t) ar->private; char buf[1024]; if(_ar_pipe_write(ar, data->out, "USER-EXISTS %s %s\n", username, realm) < 0) return 0; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 0; if(buf[0] != 'O' || buf[1] != 'K') return 0; return 1; } static int _ar_pipe_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { moddata_t data = (moddata_t) ar->private; char buf[1024]; if(_ar_pipe_write(ar, data->out, "GET-PASSWORD %s %s\n", username, realm) < 0) return 1; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 1; if(buf[0] != 'O' || buf[1] != 'K') return 1; if(buf[2] != ' ' || buf[3] == '\0') { log_debug(ZONE, "malformed response from pipe"); return 1; } if(apr_base64_decode_len(&buf[3], strlen(&buf[3])) >= 256) { log_debug(ZONE, "decoded password longer than buffer"); return 1; } apr_base64_decode(password, &buf[3], strlen(&buf[3])); log_debug(ZONE, "got password: %s", password); return 0; } static int _ar_pipe_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { moddata_t data = (moddata_t) ar->private; char buf[1024]; int plen; plen = strlen(password); if(apr_base64_encode_len(plen) >= 1023) { log_debug(ZONE, "unable to encode password"); return 1; } apr_base64_encode(buf, password, plen); if(_ar_pipe_write(ar, data->out, "CHECK-PASSWORD %s %s %s\n", username, buf, realm) < 0) return 1; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 1; if(buf[0] != 'O' || buf[1] != 'K') return 1; return 0; } static int _ar_pipe_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { moddata_t data = (moddata_t) ar->private; char buf[1024]; int plen; plen = strlen(password); if(apr_base64_encode_len(plen) >= 1023) { log_debug(ZONE, "unable to encode password"); return 1; } apr_base64_encode(buf, password, plen); if(_ar_pipe_write(ar, data->out, "SET-PASSWORD %s %s %s\n", username, buf, realm) < 0) return 1; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 1; if(buf[0] != 'O' || buf[1] != 'K') return 1; return 0; } static int _ar_pipe_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { moddata_t data = (moddata_t) ar->private; char buf[1024]; if(_ar_pipe_write(ar, data->out, "CREATE-USER %s %s\n", username, realm) < 0) return 1; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 1; if(buf[0] != 'O' || buf[1] != 'K') return 1; return 0; } static int _ar_pipe_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { moddata_t data = (moddata_t) ar->private; char buf[1024]; if(_ar_pipe_write(ar, data->out, "DELETE-USER %s %s\n", username, realm) < 0) return 1; if(_ar_pipe_read(ar, data->in, buf, 1023) <= 0) return 1; if(buf[0] != 'O' || buf[1] != 'K') return 1; return 0; } static void _ar_pipe_free(authreg_t ar) { moddata_t data = (moddata_t) ar->private; if(_ar_pipe_write(ar, data->out, "FREE\n") < 0) return; close(data->in); close(data->out); free(data); return; } static void _ar_pipe_signal(int signum) { wait(NULL); /* !!! attempt to restart the pipe, or shutdown c2s */ } /** start me up */ int ar_init(authreg_t ar) { moddata_t data; int to[2], from[2], ret; char buf[1024], *tok, *c; data = (moddata_t) calloc(1, sizeof(struct moddata_st)); data->exec = config_get_one(ar->c2s->config, "authreg.pipe.exec", 0); if(data->exec == NULL) { log_write(ar->c2s->log, LOG_ERR, "pipe: no executable specified in config file"); free(data); return 1; } if(pipe(to) < 0) { log_write(ar->c2s->log, LOG_ERR, "pipe: failed to create pipe: %s", strerror(errno)); free(data); return 1; } if(pipe(from) < 0) { log_write(ar->c2s->log, LOG_ERR, "pipe: failed to create pipe: %s", strerror(errno)); close(to[0]); close(to[1]); free(data); return 1; } signal(SIGCHLD, _ar_pipe_signal); log_debug(ZONE, "attempting to fork"); data->child = fork(); if(data->child < 0) { log_write(ar->c2s->log, LOG_ERR, "pipe: failed to fork: %s", strerror(errno)); close(to[0]); close(to[1]); close(from[0]); close(from[1]); free(data); return 1; } /* child */ if(data->child == 0) { log_debug(ZONE, "executing %s", data->exec); close(STDIN_FILENO); close(STDOUT_FILENO); dup2(to[0], STDIN_FILENO); dup2(from[1], STDOUT_FILENO); close(to[0]); close(to[1]); close(from[0]); close(from[1]); execl(data->exec, data->exec, NULL); log_write(ar->c2s->log, LOG_ERR, "pipe: failed to execute %s: %s", data->exec, strerror(errno)); free(data); exit(1); } log_write(ar->c2s->log, LOG_NOTICE, "pipe authenticator %s running (pid %d)", data->exec, data->child); /* parent */ close(to[0]); close(from[1]); data->in = from[0]; data->out = to[1]; ret = _ar_pipe_read(ar, data->in, buf, 1023); if(ret <= 0) { close(data->in); close(data->out); free(data); return 1; } c = buf; while(c != NULL) { tok = c; c = strchr(c, ' '); if(c != NULL) { *c = '\0'; c++; } /* first token must be OK */ if(tok == buf) { if(strcmp(tok, "OK") == 0) continue; log_write(ar->c2s->log, LOG_ERR, "pipe: pipe authenticator failed to initialise"); kill(data->child, SIGTERM); close(data->in); close(data->out); free(data); return 1; } /* its an option */ log_debug(ZONE, "module feature: %s", tok); if(strcmp(tok, "USER-EXISTS") == 0) ar->user_exists = _ar_pipe_user_exists; else if(strcmp(tok, "GET-PASSWORD") == 0) ar->get_password = _ar_pipe_get_password; else if(strcmp(tok, "CHECK-PASSWORD") == 0) ar->check_password = _ar_pipe_check_password; else if(strcmp(tok, "SET-PASSWORD") == 0) ar->set_password = _ar_pipe_set_password; else if(strcmp(tok, "CREATE-USER") == 0) ar->create_user = _ar_pipe_create_user; else if(strcmp(tok, "DELETE-USER") == 0) ar->delete_user = _ar_pipe_delete_user; else if(strcmp(tok, "FREE") == 0) ar->free = _ar_pipe_free; } ar->private = (void *) data; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_sqlite.c�����������������������������������������������������0000664�0000000�0000000�00000030254�12614627753�0021433�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** * @file authreg_sqlite.c * @brief sqlite 3 authentication code for jabberd2 * @author Christopher Parker * @bug no known bugs */ /* Released under the GPL by Christopher Parker <parkerc@i-vsn.com>, IVSN * to the Jabberd project. */ #define _XOPEN_SOURCE 500 #include "c2s.h" #include <sqlite3.h> /* Windows does not have the crypt() function, let's take DES_crypt from OpenSSL instead */ #if defined(HAVE_OPENSSL_CRYPTO_H) && defined(_WIN32) #include <openssl/des.h> #define crypt DES_crypt #define HAVE_CRYPT 1 #else #ifdef HAVE_CRYPT #include <unistd.h> #endif #endif #ifdef HAVE_SSL /* We use OpenSSL's MD5 routines for the a1hash password type */ #include <openssl/md5.h> #endif #define SQLITE_LU 1024 /* maximum length of username - should correspond to field length */ #define SQLITE_LR 256 /* maximum length of realm - should correspond to field length */ #define SQLITE_LP 256 /* maximum length of password - should correspond to field length */ enum sqlite3_pws_crypt { MPC_PLAIN, #ifdef HAVE_CRYPT MPC_CRYPT, #endif #ifdef HAVE_SSL MPC_A1HASH, #endif }; #ifdef HAVE_CRYPT static char salter[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; #endif typedef struct moddata_st { sqlite3 *db; int txn; sqlite3_stmt *user_exists_stmt; sqlite3_stmt *get_password_stmt; sqlite3_stmt *check_password_stmt; sqlite3_stmt *set_password_stmt; sqlite3_stmt *create_user_stmt; sqlite3_stmt *delete_user_stmt; enum sqlite3_pws_crypt password_type; } *moddata_t; #ifdef HAVE_SSL static void calc_a1hash(const char *username, const char *realm, const char *password, char *a1hash) { #define A1PPASS_LEN SQLITE_LU + 1 + SQLITE_LR + 1 + SQLITE_LP + 1 /* user:realm:password\0 */ char buf[A1PPASS_LEN]; unsigned char md5digest[MD5_DIGEST_LENGTH]; int i; snprintf(buf, A1PPASS_LEN, "%.*s:%.*s:%.*s", SQLITE_LU, username, SQLITE_LR, realm, SQLITE_LP, password); MD5((unsigned char*)buf, strlen(buf), md5digest); for(i=0; i<16; i++) { sprintf(a1hash+i*2, "%02hhx", md5digest[i]); } } #endif static sqlite3_stmt* _get_stmt(authreg_t ar, sqlite3 *db, sqlite3_stmt **stmt, const char *sql) { int res; if (*stmt == NULL) { res = sqlite3_prepare(db, sql, -1, stmt, 0); if (res != SQLITE_OK) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): %s", sqlite3_errmsg(db)); return NULL; } } return *stmt; } /** * @return 1 if the user exists, 0 if not */ static int _ar_sqlite_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { sqlite3_stmt *stmt; char *sql = "SELECT username FROM authreg WHERE username = ? AND realm = ?"; moddata_t data = (moddata_t) ar->private; int res, ret = 0; log_debug(ZONE, "sqlite (authreg): user exists"); stmt = _get_stmt(ar, data->db, &data->user_exists_stmt, sql); if (stmt == NULL) { return 0; } sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, realm, -1, SQLITE_STATIC); res = sqlite3_step(stmt); if (res == SQLITE_ROW) { log_debug(ZONE, "sqlite (authreg): user exists : yes"); ret = 1; } else { log_debug(ZONE, "sqlite (authreg): user exists : no"); } sqlite3_reset(stmt); return ret; } /** * @return 0 is password is populated, 1 if not */ static int _ar_sqlite_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { sqlite3_stmt *stmt; char *sql = "SELECT password FROM authreg WHERE username = ? and realm = ?"; moddata_t data = (moddata_t) ar->private; int res, ret=1; log_debug(ZONE, "sqlite (authreg): get password"); stmt = _get_stmt (ar, data->db, &data->get_password_stmt, sql); if (stmt == NULL) { return 1; } sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, realm, -1, SQLITE_STATIC); res = sqlite3_step(stmt); if (res == SQLITE_ROW) { strcpy(password, (char *) sqlite3_column_text(stmt, 0)); ret = 0; } sqlite3_reset(stmt); return ret; } /** * @return 0 if the given password matches the password stored in the database, !0 if not */ static int _ar_sqlite_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { char db_pw_value[257]; #ifdef HAVE_CRYPT char *crypted_pw; #endif #ifdef HAVE_SSL char a1hash_pw[33]; #endif moddata_t data = (moddata_t) ar->private; int ret=1; log_debug(ZONE, "sqlite (authreg): check password"); ret = _ar_sqlite_get_password (ar, sess, username, realm, db_pw_value); if (ret) return ret; switch (data->password_type) { case MPC_PLAIN: ret = (strcmp (password, db_pw_value) != 0); break; #ifdef HAVE_CRYPT case MPC_CRYPT: crypted_pw = crypt(password,db_pw_value); ret = (strcmp(crypted_pw, db_pw_value) != 0); break; #endif #ifdef HAVE_SSL case MPC_A1HASH: if (strchr(username, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Username cannot contain : with a1hash encryption type."); break; } if (strchr(realm, ':')) { ret = 1; log_write(ar->c2s->log, LOG_ERR, "Realm cannot contain : with a1hash encryption type."); break; } calc_a1hash(username, realm, password, a1hash_pw); ret = (strncmp(a1hash_pw, db_pw_value, 32) != 0); break; #endif default: /* should never happen */ ret = 1; log_write(ar->c2s->log, LOG_ERR, "Unknown encryption type which passed through config check."); break; } return ret; } /** * @return 0 if password is stored, 1 if not */ static int _ar_sqlite_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { sqlite3_stmt *stmt; moddata_t data = (moddata_t) ar->private; int res, ret = 0; char *sql = "UPDATE authreg SET password = ? WHERE username = ? AND realm = ?"; log_debug(ZONE, "sqlite (authreg): set password"); #ifdef HAVE_CRYPT if (data->password_type == MPC_CRYPT) { char salt[39] = "$6$rounds=50000$"; int i; srand(time(0)); for(i=0; i<22; i++) salt[16+i] = salter[rand()%64]; strcpy(password, crypt(password, salt)); } #endif #ifdef HAVE_SSL else if (data->password_type == MPC_A1HASH) { calc_a1hash(username, realm, password, password); } #endif stmt = _get_stmt(ar, data->db, &data->set_password_stmt, sql); if (stmt == NULL) { return 1; } sqlite3_bind_text(stmt, 1, password, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, realm, -1, SQLITE_STATIC); res = sqlite3_step(stmt); if (res != SQLITE_DONE) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): %s", sqlite3_errmsg (data->db)); ret = 1; } sqlite3_reset(stmt); return ret; } /** * @return 0 if user is created, 1 if not */ static int _ar_sqlite_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { sqlite3_stmt *stmt; moddata_t data = data = (moddata_t) ar->private; int res, ret = 0; char *sql = "INSERT INTO authreg ( username, realm ) VALUES ( ?, ? )"; log_debug(ZONE, "sqlite (authreg): create user"); stmt = _get_stmt(ar, data->db, &data->create_user_stmt, sql); if (stmt == NULL) { return 1; } sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, realm, -1, SQLITE_STATIC); res = sqlite3_step(stmt); if (res != SQLITE_DONE) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): %s", sqlite3_errmsg (data->db)); ret = 1; } sqlite3_reset(stmt); return ret; } /** * @return 0 if user is deleted, 1 if not */ static int _ar_sqlite_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) { sqlite3_stmt *stmt; moddata_t data = (moddata_t) ar->private; int res, ret = 0; char *sql = "DELETE FROM authreg WHERE username = ? AND realm = ?"; log_debug(ZONE, "sqlite (authreg): delete user"); stmt = _get_stmt(ar, data->db, &data->delete_user_stmt, sql); if (stmt == NULL) { return 1; } sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, realm, -1, SQLITE_STATIC); res = sqlite3_step(stmt); if (res != SQLITE_DONE) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): %s", sqlite3_errmsg (data->db)); ret = 1; } sqlite3_reset(stmt); return ret; } /** * @return does not return */ static void _ar_sqlite_free(authreg_t ar) { moddata_t data = (moddata_t) ar->private; log_debug(ZONE, "sqlite (authreg): free"); sqlite3_finalize(data->user_exists_stmt); sqlite3_finalize(data->get_password_stmt); sqlite3_finalize(data->check_password_stmt); sqlite3_finalize(data->set_password_stmt); sqlite3_finalize(data->create_user_stmt); sqlite3_finalize(data->delete_user_stmt); sqlite3_close(data->db); free(data); } DLLEXPORT int ar_init(authreg_t ar) { int ret; sqlite3 *db; moddata_t data; const char *busy_timeout; const char *dbname = config_get_one(ar->c2s->config, "authreg.sqlite.dbname", 0); log_debug(ZONE, "sqlite (authreg): start init"); if (dbname == NULL) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): invalid driver config."); return 1; } ret = sqlite3_open(dbname, &db); if (ret != SQLITE_OK) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): can't open database."); return 1; } data = (moddata_t) calloc(1, sizeof(struct moddata_st)); if (!data) { log_write(ar->c2s->log, LOG_ERR, "sqlite (authreg): memory error."); return 1; } data->db = db; if (config_get_one(ar->c2s->config, "authreg.sqlite.transactions", 0) != NULL) { data->txn = 1; } else { log_write(ar->c2s->log, LOG_WARNING, "sqlite (authreg): transactions disabled"); data->txn = 0; } busy_timeout = config_get_one(ar->c2s->config, "authreg.sqlite.busy-timeout", 0); if (busy_timeout != NULL) { sqlite3_busy_timeout(db, atoi(busy_timeout)); } /* get encryption type used in DB */ if (config_get_one(ar->c2s->config, "authreg.sqlite.password_type.plaintext", 0)) { data->password_type = MPC_PLAIN; #ifdef HAVE_CRYPT } else if (config_get_one(ar->c2s->config, "authreg.sqlite.password_type.crypt", 0)) { data->password_type = MPC_CRYPT; #endif #ifdef HAVE_SSL } else if (config_get_one(ar->c2s->config, "authreg.sqlite.password_type.a1hash", 0)) { data->password_type = MPC_A1HASH; #endif } else { data->password_type = MPC_PLAIN; } ar->private = data; ar->user_exists = _ar_sqlite_user_exists; ar->get_password = _ar_sqlite_get_password; ar->check_password = _ar_sqlite_check_password; ar->set_password = _ar_sqlite_set_password; ar->create_user = _ar_sqlite_create_user; ar->delete_user = _ar_sqlite_delete_user; ar->free = _ar_sqlite_free; log_debug(ZONE, "sqlite (authreg): finish init"); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/authreg_sspi.c�������������������������������������������������������0000664�0000000�0000000�00000035517�12614627753�0021117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2005 Adam Strzelecki * * 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, MA02111-1307USA */ /* this plugin uses SSPI for Windows authentication */ #include "c2s.h" #ifdef _WIN32 #define SECURITY_WIN32 #include <windows.h> #include <tchar.h> #include <stdio.h> #include <sspi.h> // Older versions of WinError.h does not have SEC_I_COMPLETE_NEEDED #define. // So, in such SDK environment setup, we will include issperr.h which has the // definition for SEC_I_COMPLETE_NEEDED. Include issperr.h only if // SEC_I_COMPLETE_NEEDED is not defined. #ifndef SEC_I_COMPLETE_NEEDED #include <issperr.h> #endif typedef struct _AUTH_SEQ { BOOL fInitialized; BOOL fHaveCredHandle; BOOL fHaveCtxtHandle; CredHandle hcred; struct _SecHandle hctxt; } AUTH_SEQ, *PAUTH_SEQ; // Function pointers ACCEPT_SECURITY_CONTEXT_FN _AcceptSecurityContext = NULL; ACQUIRE_CREDENTIALS_HANDLE_FN _AcquireCredentialsHandle = NULL; COMPLETE_AUTH_TOKEN_FN _CompleteAuthToken = NULL; DELETE_SECURITY_CONTEXT_FN _DeleteSecurityContext = NULL; FREE_CONTEXT_BUFFER_FN _FreeContextBuffer = NULL; FREE_CREDENTIALS_HANDLE_FN _FreeCredentialsHandle = NULL; INITIALIZE_SECURITY_CONTEXT_FN _InitializeSecurityContext = NULL; QUERY_SECURITY_PACKAGE_INFO_FN _QuerySecurityPackageInfo = NULL; /////////////////////////////////////////////////////////////////////////////// void UnloadSecurityDll(HMODULE hModule) { if (hModule) FreeLibrary(hModule); _AcceptSecurityContext = NULL; _AcquireCredentialsHandle = NULL; _CompleteAuthToken = NULL; _DeleteSecurityContext = NULL; _FreeContextBuffer = NULL; _FreeCredentialsHandle = NULL; _InitializeSecurityContext = NULL; _QuerySecurityPackageInfo = NULL; } /////////////////////////////////////////////////////////////////////////////// HMODULE LoadSecurityDll() { HMODULE hModule; BOOL fAllFunctionsLoaded = FALSE; TCHAR lpszDLL[MAX_PATH]; OSVERSIONINFO VerInfo; // // Find out which security DLL to use, depending on // whether we are on NT or Win95 or 2000 or XP or Windows Server 2003 // We have to use security.dll on Windows NT 4.0. // All other operating systems, we have to use Secur32.dll // VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (!GetVersionEx (&VerInfo)) // If this fails, something has gone wrong { return FALSE; } if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && VerInfo.dwMajorVersion == 4 && VerInfo.dwMinorVersion == 0) { lstrcpy (lpszDLL, _T("security.dll")); } else { lstrcpy (lpszDLL, _T("secur32.dll")); } hModule = LoadLibrary(lpszDLL); if (!hModule) return NULL; __try { _AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN) GetProcAddress(hModule, "AcceptSecurityContext"); if (!_AcceptSecurityContext) __leave; #ifdef UNICODE _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) GetProcAddress(hModule, "AcquireCredentialsHandleW"); #else _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) GetProcAddress(hModule, "AcquireCredentialsHandleA"); #endif if (!_AcquireCredentialsHandle) __leave; // CompleteAuthToken is not present on Windows 9x Secur32.dll // Do not check for the availablity of the function if it is NULL; _CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN) GetProcAddress(hModule, "CompleteAuthToken"); _DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN) GetProcAddress(hModule, "DeleteSecurityContext"); if (!_DeleteSecurityContext) __leave; _FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN) GetProcAddress(hModule, "FreeContextBuffer"); if (!_FreeContextBuffer) __leave; _FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN) GetProcAddress(hModule, "FreeCredentialsHandle"); if (!_FreeCredentialsHandle) __leave; #ifdef UNICODE _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) GetProcAddress(hModule, "InitializeSecurityContextW"); #else _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) GetProcAddress(hModule, "InitializeSecurityContextA"); #endif if (!_InitializeSecurityContext) __leave; #ifdef UNICODE _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) GetProcAddress(hModule, "QuerySecurityPackageInfoW"); #else _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) GetProcAddress(hModule, "QuerySecurityPackageInfoA"); #endif if (!_QuerySecurityPackageInfo) __leave; fAllFunctionsLoaded = TRUE; } __finally { if (!fAllFunctionsLoaded) { UnloadSecurityDll(hModule); hModule = NULL; } } return hModule; } /////////////////////////////////////////////////////////////////////////////// BOOL GenClientContext(authreg_t ar, PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) { /*++ Routine Description: Optionally takes an input buffer coming from the server and returns a buffer of information to send back to the server. Also returns an indication of whether or not the context is complete. Return Value: Returns TRUE if successful; otherwise FALSE. --*/ SECURITY_STATUS ss; TimeStamp tsExpiry; SecBufferDesc sbdOut; SecBuffer sbOut; SecBufferDesc sbdIn; SecBuffer sbIn; ULONG fContextAttr; if (!pAS->fInitialized) { ss = _AcquireCredentialsHandle(NULL, _T("NTLM"), SECPKG_CRED_OUTBOUND, NULL, pAuthIdentity, NULL, NULL, &pAS->hcred, &tsExpiry); if (ss < 0) { log_write(ar->c2s->log, LOG_ERR, "sspi: AcquireCredentialsHandle failed with %08X", ss); return FALSE; } pAS->fHaveCredHandle = TRUE; } // Prepare output buffer sbdOut.ulVersion = 0; sbdOut.cBuffers = 1; sbdOut.pBuffers = &sbOut; sbOut.cbBuffer = *pcbOut; sbOut.BufferType = SECBUFFER_TOKEN; sbOut.pvBuffer = pOut; // Prepare input buffer if (pAS->fInitialized) { sbdIn.ulVersion = 0; sbdIn.cBuffers = 1; sbdIn.pBuffers = &sbIn; sbIn.cbBuffer = cbIn; sbIn.BufferType = SECBUFFER_TOKEN; sbIn.pvBuffer = pIn; } ss = _InitializeSecurityContext(&pAS->hcred, pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0, SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL, 0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry); if (ss < 0) { // <winerror.h> log_write(ar->c2s->log, LOG_ERR, "sspi: InitializeSecurityContext failed with %08X", ss); return FALSE; } pAS->fHaveCtxtHandle = TRUE; // If necessary, complete token if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { if (_CompleteAuthToken) { ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); if (ss < 0) { log_write(ar->c2s->log, LOG_ERR, "sspi: CompleteAuthToken failed with %08X", ss); return FALSE; } } else { log_write(ar->c2s->log, LOG_ERR, "sspi: CompleteAuthToken not supported"); return FALSE; } } *pcbOut = sbOut.cbBuffer; if (!pAS->fInitialized) pAS->fInitialized = TRUE; *pfDone = !(ss == SEC_I_CONTINUE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE ); return TRUE; } /////////////////////////////////////////////////////////////////////////////// BOOL GenServerContext(authreg_t ar, PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) { /*++ Routine Description: Takes an input buffer coming from the client and returns a buffer to be sent to the client. Also returns an indication of whether or not the context is complete. Return Value: Returns TRUE if successful; otherwise FALSE. --*/ SECURITY_STATUS ss; TimeStamp tsExpiry; SecBufferDesc sbdOut; SecBuffer sbOut; SecBufferDesc sbdIn; SecBuffer sbIn; ULONG fContextAttr; if (!pAS->fInitialized) { ss = _AcquireCredentialsHandle(NULL, _T("NTLM"), SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred, &tsExpiry); if (ss < 0) { log_write(ar->c2s->log, LOG_ERR, "sspi: AcquireCredentialsHandle failed with %08X", ss); return FALSE; } pAS->fHaveCredHandle = TRUE; } // Prepare output buffer sbdOut.ulVersion = 0; sbdOut.cBuffers = 1; sbdOut.pBuffers = &sbOut; sbOut.cbBuffer = *pcbOut; sbOut.BufferType = SECBUFFER_TOKEN; sbOut.pvBuffer = pOut; // Prepare input buffer sbdIn.ulVersion = 0; sbdIn.cBuffers = 1; sbdIn.pBuffers = &sbIn; sbIn.cbBuffer = cbIn; sbIn.BufferType = SECBUFFER_TOKEN; sbIn.pvBuffer = pIn; ss = _AcceptSecurityContext(&pAS->hcred, pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, 0, SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry); if (ss < 0) { log_write(ar->c2s->log, LOG_ERR, "sspi: AcceptSecurityContext failed with %08X", ss); return FALSE; } pAS->fHaveCtxtHandle = TRUE; // If necessary, complete token if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { if (_CompleteAuthToken) { ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); if (ss < 0) { log_write(ar->c2s->log, LOG_ERR, "sspi: CompleteAuthToken failed with %08X", ss); return FALSE; } } else { log_write(ar->c2s->log, LOG_ERR, "sspi: CompleteAuthToken not supported"); return FALSE; } } *pcbOut = sbOut.cbBuffer; if (!pAS->fInitialized) pAS->fInitialized = TRUE; *pfDone = !(ss = SEC_I_CONTINUE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE); return TRUE; } /////////////////////////////////////////////////////////////////////////////// BOOL WINAPI SSPLogonUser(authreg_t ar, LPTSTR szDomain, LPTSTR szUser, LPTSTR szPassword) { AUTH_SEQ asServer = {0}; AUTH_SEQ asClient = {0}; BOOL fDone = FALSE; BOOL fResult = FALSE; DWORD cbOut = 0; DWORD cbIn = 0; DWORD cbMaxToken = 0; PVOID pClientBuf = NULL; PVOID pServerBuf = NULL; PSecPkgInfo pSPI = NULL; HMODULE hModule = NULL; SEC_WINNT_AUTH_IDENTITY ai; __try { hModule = LoadSecurityDll(); if (!hModule) __leave; // Get max token size _QuerySecurityPackageInfo(_T("NTLM"), &pSPI); cbMaxToken = pSPI->cbMaxToken; _FreeContextBuffer(pSPI); // Allocate buffers for client and server messages pClientBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken); pServerBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken); // Initialize auth identity structure ZeroMemory(&ai, sizeof(ai)); #if defined(UNICODE) || defined(_UNICODE) ai.Domain = szDomain; ai.DomainLength = lstrlen(szDomain); ai.User = szUser; ai.UserLength = lstrlen(szUser); ai.Password = szPassword; ai.PasswordLength = lstrlen(szPassword); ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; #else ai.Domain = (unsigned char *)szDomain; ai.DomainLength = lstrlen(szDomain); ai.User = (unsigned char *)szUser; ai.UserLength = lstrlen(szUser); ai.Password = (unsigned char *)szPassword; ai.PasswordLength = lstrlen(szPassword); ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; #endif // Prepare client message (negotiate) . cbOut = cbMaxToken; if (!GenClientContext(ar, &asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone)) __leave; // Prepare server message (challenge) . cbIn = cbOut; cbOut = cbMaxToken; if (!GenServerContext(ar, &asServer, pClientBuf, cbIn, pServerBuf, &cbOut, &fDone)) __leave; // Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED // in the case of bad szUser or szPassword. // Unexpected Result: Logon will succeed if you pass in a bad szUser and // the guest account is enabled in the specified domain. // Prepare client message (authenticate) . cbIn = cbOut; cbOut = cbMaxToken; if (!GenClientContext(ar, &asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut, &fDone)) __leave; // Prepare server message (authentication) . cbIn = cbOut; cbOut = cbMaxToken; if (!GenServerContext(ar, &asServer, pClientBuf, cbIn, pServerBuf, &cbOut, &fDone)) __leave; fResult = TRUE; } __finally { // Clean up resources if (asClient.fHaveCtxtHandle) _DeleteSecurityContext(&asClient.hctxt); if (asClient.fHaveCredHandle) _FreeCredentialsHandle(&asClient.hcred); if (asServer.fHaveCtxtHandle) _DeleteSecurityContext(&asServer.hctxt); if (asServer.fHaveCredHandle) _FreeCredentialsHandle(&asServer.hcred); if (hModule) UnloadSecurityDll(hModule); HeapFree(GetProcessHeap(), 0, pClientBuf); HeapFree(GetProcessHeap(), 0, pServerBuf); } return fResult; } /////////////////////////////////////////////////////////////////////////////// // Main jabber wrapper functions static int _ar_sspi_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm) { /* we can't check if a user exists, so we just assume we have them all the time */ return 1; } static int _ar_sspi_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[257]) { return !SSPLogonUser(ar, realm ? realm : "localhost", username, password); } /** start me up */ DLLEXPORT int ar_init(authreg_t ar) { ar->user_exists = _ar_sspi_user_exists; ar->check_password = _ar_sspi_check_password; return 0; } #else /* _WIN32 */ DLLEXPORT int ar_init(authreg_t ar) { log_write(ar->c2s->log, LOG_ERR, "sspi: module is not supported on non-Windows platforms"); return 1; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/object.c�������������������������������������������������������������0000664�0000000�0000000�00000017671�12614627753�0017671�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "storage.h" /** @file storage/object.c * @brief object sets * @author Robert Norris * $Date: 2005/06/02 04:48:24 $ * $Revision: 1.10 $ */ /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ union xhashv { void **val; os_field_t *osf_val; }; os_t os_new(void) { pool_t p; os_t os; p = pool_new(); os = (os_t) pmalloco(p, sizeof(struct os_st)); os->p = p; return os; } void os_free(os_t os) { pool_free(os->p); } int os_count(os_t os) { return os->count; } int os_iter_first(os_t os) { os->iter = os->head; if(os->iter == NULL) return 0; return 1; } int os_iter_next(os_t os) { if(os->iter == NULL) return 0; os->iter = os->iter->next; if(os->iter == NULL) return 0; return 1; } os_object_t os_iter_object(os_t os) { return os->iter; } os_object_t os_object_new(os_t os) { os_object_t o; log_debug(ZONE, "creating new object"); o = (os_object_t) pmalloco(os->p, sizeof(struct os_object_st)); o->os = os; o->hash = xhash_new(51); /* make sure that the hash gets freed when the os pool gets freed */ pool_cleanup(os->p, (pool_cleanup_t) xhash_free, (void *)(o->hash) ); /* insert at the end, we have to preserve order */ o->prev = os->tail; if(os->tail != NULL) os->tail->next = o; os->tail = o; if(os->head == NULL) os->head = o; os->count++; return o; } void os_object_free(os_object_t o) { log_debug(ZONE, "dropping object"); if(o->prev != NULL) o->prev->next = o->next; if(o->next != NULL) o->next->prev = o->prev; if(o->os->head == o) o->os->head = o->next; if(o->os->tail == o) o->os->tail = o->prev; if(o->os->iter == o) o->os->iter = o->next; o->os->count--; } /* wrappers for os_object_put to avoid breaking strict-aliasing rules in gcc3 */ void os_object_put_time(os_object_t o, const char *key, const time_t *val) { void *ptr = (void *) val; os_object_put(o, key, ptr, os_type_INTEGER); } void os_object_put(os_object_t o, const char *key, const void *val, os_type_t type) { os_field_t osf; nad_t nad; log_debug(ZONE, "adding field %s (val %x type %d) to object", key, val, type); osf = pmalloco(o->os->p, sizeof(struct os_field_st)); osf->key = pstrdup(o->os->p, key); switch(type) { case os_type_BOOLEAN: case os_type_INTEGER: osf->val = (void *) (intptr_t) (* (int *) val); break; case os_type_STRING: osf->val = (void *) pstrdup(o->os->p, (char *) val); break; case os_type_NAD: nad = nad_copy((nad_t) val); /* make sure that the nad gets freed when the os pool gets freed */ pool_cleanup(o->os->p, (pool_cleanup_t) nad_free, (void *) nad); osf->val = (void *) nad; break; case os_type_UNKNOWN: break; } osf->type = type; xhash_put(o->hash, osf->key, (void *) osf); } /* wrappers for os_object_get to avoid breaking strict-aliasing rules in gcc3 */ int os_object_get_nad(os_t os, os_object_t o, const char *key, nad_t *val) { void *ptr = (void *) val; int ret; ret = os_object_get(os, o, key, &ptr, os_type_NAD, NULL); *val = (nad_t) ptr; return ret; } int os_object_get_str(os_t os, os_object_t o, const char *key, char **val) { void *ptr = (void *) val; int ret; ret = os_object_get(os, o, key, &ptr, os_type_STRING, NULL); *val = (char *) ptr; return ret; } int os_object_get_int(os_t os, os_object_t o, const char *key, int *val) { void *ptr = (void *) val; int ret; ret = os_object_get(os, o, key, &ptr, os_type_INTEGER, NULL); *val = (int) (long) ptr; return ret; } int os_object_get_bool(os_t os, os_object_t o, const char *key, int *val) { void *ptr = (void *) val; int ret; ret = os_object_get(os, o, key, &ptr, os_type_INTEGER, NULL); *val = (int) (long) ptr; return ret; } int os_object_get_time(os_t os, os_object_t o, const char *key, time_t *val) { void *ptr = (void *) val; int ret; ret = os_object_get(os, o, key, &ptr, os_type_INTEGER, NULL); *val = (time_t) ptr; return ret; } int os_object_get(os_t os, os_object_t o, const char *key, void **val, os_type_t type, os_type_t *ot) { os_field_t osf; nad_t nad; /* Type complexity is to deal with string/NADs. If an object contains xml, it will only be parsed and returned as a NAD if type == os_type_NAD, otherwise if type == os_type_UNKNOWN it will be returned as string, unless it's already been converted to a NAD */ osf = (os_field_t) xhash_get(o->hash, key); if(osf == NULL) { *val = NULL; return 0; } if (ot != NULL) *ot = osf->type; if (type == os_type_UNKNOWN) type = osf->type; if (type == os_type_UNKNOWN) type = osf->type; switch(type) { case os_type_BOOLEAN: case os_type_INTEGER: * (int *) val = (int) (intptr_t) osf->val; break; case os_type_STRING: *val = osf->val; break; case os_type_NAD: /* check to see whether it's already a NAD */ if (osf->type == os_type_NAD) { *val = osf->val; } else { /* parse the string into a NAD */ nad = nad_parse(((char *) osf->val) + 3, strlen(osf->val) - 3); if(nad == NULL) { /* unparseable NAD */ log_debug(ZONE, "cell returned from storage for key %s has unparseable XML content (%lu bytes)", key, strlen(osf->val)-3); *val = NULL; return 0; } /* replace the string with a NAD */ osf->val = (void *) nad; pool_cleanup(os->p, (pool_cleanup_t) nad_free, (void *) nad); *val = osf->val; osf->type = os_type_NAD; } break; default: *val = NULL; } log_debug(ZONE, "got field %s (val %x type %d) to object", key, *val, type); return 1; } int os_object_iter_first(os_object_t o) { return xhash_iter_first(o->hash); } int os_object_iter_next(os_object_t o) { return xhash_iter_next(o->hash); } void os_object_iter_get(os_object_t o, char **key, void **val, os_type_t *type) { os_field_t osf; union xhashv xhv; int keylen; xhv.osf_val = &osf; xhash_iter_get(o->hash, (const char **) key, &keylen, xhv.val); if(*key == NULL) { *val = NULL; return; } *type = osf->type; switch(osf->type) { case os_type_BOOLEAN: case os_type_INTEGER: * (int *) val = (int) (intptr_t) osf->val; break; case os_type_STRING: case os_type_NAD: *val = osf->val; break; default: *val = NULL; } log_debug(ZONE, "got iter field %s (val %x type %d) to object", *key, *val, *type); } �����������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage.c������������������������������������������������������������0000664�0000000�0000000�00000035471�12614627753�0020065�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file storage/storage.c * @brief storage manager * @author Robert Norris * $Date: 2005/06/02 06:31:10 $ * $Revision: 1.21 $ */ #include "storage.h" #include <ctype.h> #ifdef _WIN32 #include <windows.h> #define LIBRARY_DIR "." #else #include <dlfcn.h> #endif /* _WIN32 */ storage_t storage_new(config_t config, log_t log) { storage_t st; int i; config_elem_t elem; char *type; st_ret_t ret; st = (storage_t) calloc(1, sizeof(struct storage_st)); st->config = config; st->log = log; st->drivers = xhash_new(101); st->types = xhash_new(101); /* register types declared in the config file */ elem = config_get(st->config, "storage.driver"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { type = j_attr((const char **) elem->attrs[i], "type"); ret = storage_add_type(st, elem->values[i], type); /* Initialisation of storage type failed */ if (ret != st_SUCCESS) { free(st); return NULL; } } } return st; } static void _st_driver_reaper(const char *driver, int driverlen, void *val, void *arg) { st_driver_t drv = (st_driver_t) val; (drv->free)(drv); free(drv); } void storage_free(storage_t st) { /* close down drivers */ xhash_walk(st->drivers, _st_driver_reaper, NULL); xhash_free(st->drivers); xhash_free(st->types); free(st); } st_ret_t storage_add_type(storage_t st, const char *driver, const char *type) { st_driver_t drv; st_driver_init_fn init_fn = NULL; char mod_fullpath[PATH_MAX]; const char *modules_path; st_ret_t ret; void *handle; /* startup, see if we've already registered this type */ if(type == NULL) { log_debug(ZONE, "adding arbitrary types to driver '%s'", driver); /* see if we already have one */ if(st->default_drv != NULL) { log_debug(ZONE, "we already have a default handler, ignoring this one"); return st_FAILED; } } else { log_debug(ZONE, "adding type '%s' to driver '%s'", type, driver); /* see if we already have one */ if(xhash_get(st->types, type) != NULL) { log_debug(ZONE, "we already have a handler for type '%s', ignoring this one", type); return st_FAILED; } } /* set modules path */ modules_path = config_get_one(st->config, "storage.path", 0); /* get the driver */ drv = xhash_get(st->drivers, driver); if(drv == NULL) { log_debug(ZONE, "driver not loaded, trying to init"); log_write(st->log, LOG_INFO, "loading '%s' storage module", driver); #ifndef _WIN32 if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", modules_path, driver); else snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", LIBRARY_DIR, driver); handle = dlopen(mod_fullpath, RTLD_LAZY); if (handle != NULL) init_fn = dlsym(handle, "st_init"); #else if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s\\storage_%s.dll", modules_path, driver); else snprintf(mod_fullpath, PATH_MAX, "storage_%s.dll", driver); handle = (void*) LoadLibrary(mod_fullpath); if (handle != NULL) init_fn = (st_driver_init_fn)GetProcAddress((HMODULE) handle, "st_init"); #endif if (handle != NULL && init_fn != NULL) { log_debug(ZONE, "preloaded module '%s' (not initialized yet)", driver); } else { #ifndef _WIN32 log_write(st->log, LOG_ERR, "failed loading storage module '%s' (%s)", driver, dlerror()); if (handle != NULL) dlclose(handle); #else log_write(st->log, LOG_ERR, "failed loading storage module '%s' (errcode: %x)", driver, GetLastError()); if (handle != NULL) FreeLibrary((HMODULE) handle); #endif return st_FAILED; } /* make a new driver structure */ drv = (st_driver_t) calloc(1, sizeof(struct st_driver_st)); drv->st = st; log_debug(ZONE, "calling driver initializer"); /* init */ if((init_fn)(drv) == st_FAILED) { log_write(st->log, LOG_NOTICE, "initialisation of storage driver '%s' failed", driver); free(drv); return st_FAILED; } /* add it to the drivers hash so we can find it later */ drv->name = pstrdup(xhash_pool(st->drivers), driver); xhash_put(st->drivers, drv->name, (void *) drv); log_write(st->log, LOG_NOTICE, "initialised storage driver '%s'", driver); } /* if its a default, set it up as such */ if(type == NULL) { st->default_drv = drv; return st_SUCCESS; } /* its a real type, so let the driver know */ if(type != NULL && (ret = (drv->add_type)(drv, type)) != st_SUCCESS) { log_debug(ZONE, "driver '%s' can't handle '%s' data", driver, type); return ret; } /* register the type */ xhash_put(st->types, pstrdup(xhash_pool(st->types), type), (void *) drv); return st_SUCCESS; } st_ret_t storage_put(storage_t st, const char *type, const char *owner, os_t os) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_put: type=%s owner=%s os=%X", type, owner, os); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return (drv->put)(drv, type, owner, os); } st_ret_t storage_get(storage_t st, const char *type, const char *owner, const char *filter, os_t *os) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_get: type=%s owner=%s filter=%s", type, owner, filter); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return (drv->get)(drv, type, owner, filter, os); } st_ret_t storage_get_custom_sql(storage_t st, const char* request, os_t* os, const char *type /*= 0*/) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_get_custom_sql: query='%s'", request); if (type) { /* find the handler for this type */ drv = xhash_get(st->types, type); } else { /* find the handler for this type */ drv = xhash_get(st->types, "custom_sql_query"); } if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, "custom_sql_query"); if(ret != st_SUCCESS) return ret; } if (drv->get_custom_sql) { return (drv->get_custom_sql)(drv, request, os); } else { return st_NOTIMPL; } } st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_count: type=%s owner=%s filter=%s", type, owner, filter); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return ((drv->count != NULL) ? (drv->count)(drv, type, owner, filter, count) : st_NOTIMPL); } st_ret_t storage_delete(storage_t st, const char *type, const char *owner, const char *filter) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_zap: type=%s owner=%s filter=%s", type, owner, filter); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return (drv->delete)(drv, type, owner, filter); } st_ret_t storage_replace(storage_t st, const char *type, const char *owner, const char *filter, os_t os) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_replace: type=%s owner=%s filter=%s os=%X", type, owner, filter, os); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return (drv->replace)(drv, type, owner, filter, os); } static st_filter_t _storage_filter(pool_t p, const char *f, int len) { char *c, *key, *val, *sub; int vallen; st_filter_t res, sf; if(f[0] != '(' && f[len] != ')') return NULL; /* key/value pair */ /* if value is numeric, then represented as is. */ /* if value is string, it is preceded by length: e.g. "key=5:abcde" */ /* (needed to pass values which include a closing bracket ')', e.g. in resourcenames */ if(isalpha(f[1])) { key = strdup(f+1); c = strchr(key, '='); if(c == NULL) { free(key); return NULL; } *c = '\0'; c++; val = c; /* decide whether number or string by checking for ':' before ')' */ while (*c != ':' && *c != ')' && *c) c++; if (!*c) { free(key); return NULL; } if (*c == ':') { /* string */ *c = '\0'; vallen = atoi(val); c++; val = c; c += vallen; } *c = '\0'; log_debug(ZONE, "extracted key %s val %s", key, val); res = pmalloco(p, sizeof(struct st_filter_st)); res->p = p; res->type = st_filter_type_PAIR; res->key = pstrdup(p, key); res->val = pstrdup(p, val); free(key); return res; } /* operator */ if(f[1] != '&' && f[1] != '|' && f[1] != '!') return NULL; res = pmalloco(p, sizeof(struct st_filter_st)); res->p = p; switch(f[1]) { case '&': res->type = st_filter_type_AND; break; case '|': res->type = st_filter_type_OR; break; case '!': res->type = st_filter_type_NOT; break; } /* remove const for now, we will not change the string */ c = (char *) &f[2]; while(*c == '(') { sub = c; c = strchr(sub, ')'); c++; sf = _storage_filter(p, (const char *) sub, c - sub); sf->next = res->sub; res->sub = sf; } return res; } st_filter_t storage_filter(const char *filter) { pool_t p; st_filter_t f; if(filter == NULL) return NULL; p = pool_new(); f = _storage_filter(p, filter, strlen(filter)); if(f == NULL) pool_free(p); return f; } static int _storage_match(st_filter_t f, os_object_t o, os_t os) { void *val; os_type_t ot; st_filter_t scan; switch(f->type) { case st_filter_type_PAIR: if(!os_object_get(os, o, f->key, &val, os_type_UNKNOWN, &ot)) return 0; switch(ot) { case os_type_BOOLEAN: if((atoi(f->val) != 0) == (((int) (long) val) != 0)) return 1; return 0; case os_type_INTEGER: if(atoi(f->val) == (int) (long) val) return 1; return 0; case os_type_STRING: if(strcmp(f->val, val) == 0) return 1; return 0; case os_type_NAD: /* !!! this is hard, but probably not needed. if you need it, you implement it ;) */ return 1; case os_type_UNKNOWN: return 0; } return 0; case st_filter_type_AND: for(scan = f->sub; scan != NULL; scan = scan->next) if(!_storage_match(scan, o, os)) return 0; return 1; case st_filter_type_OR: for(scan = f->sub; scan != NULL; scan = scan->next) if(_storage_match(scan, o, os)) return 1; return 0; case st_filter_type_NOT: if(_storage_match(f->sub, o, os)) return 0; return 1; } return 0; } int storage_match(st_filter_t filter, os_object_t o, os_t os) { if(filter == NULL) return 1; return _storage_match(filter, o, os); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage.h������������������������������������������������������������0000664�0000000�0000000�00000023374�12614627753�0020071�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * This program is free software; you can redistribute it and/or drvify * 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, MA02111-1307USA */ /** @file storage/storage.h * @brief data structures and prototypes for the storage manager * @author Eugene Agafonov * $Date: $ * $Revision: $ */ #ifndef _STORAGE_H_ #define _STORAGE_H_ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <util/pool.h> #include <util/xhash.h> #include <util/nad.h> #include <util/util.h> #ifdef _WIN32 #ifdef _USRDLL #define DLLEXPORT __declspec(dllexport) #define ST_API __declspec(dllimport) #else #define DLLEXPORT __declspec(dllimport) #define ST_API __declspec(dllexport) #endif #else #define DLLEXPORT #define ST_API #endif #ifdef __cplusplus extern "C" { #endif /* Forward declarations */ typedef struct storage_st *storage_t; /* object sets */ /** object types */ typedef enum { os_type_BOOLEAN, /**< boolean (0 or 1) */ os_type_INTEGER, /**< integer */ os_type_STRING, /**< string */ os_type_NAD, /**< XML */ os_type_UNKNOWN /**< unknown */ } os_type_t; /** a single tuple (value) within an object */ typedef struct os_field_st { char *key; /**< field name */ void *val; /**< field value */ os_type_t type; /**< field type */ } *os_field_t; typedef struct os_st *os_t; typedef struct os_object_st *os_object_t; /** object set (ie group of several objects) */ struct os_st { pool_t p; /**< pool the objects are allocated from */ os_object_t head; /**< first object in the list */ os_object_t tail; /**< last object in the list */ int count; /**< number of objects in this set */ os_object_t iter; /**< pointer for iteration */ }; /** an object */ struct os_object_st { /** object set this object is part of */ os_t os; /** fields (key is field name) */ xht hash; os_object_t next; /**< next object in the list */ os_object_t prev; /**< previous object in the list */ }; /** create a new object set */ ST_API os_t os_new(void); /** free an object set */ ST_API void os_free(os_t os); /** number of objects in a set */ ST_API int os_count(os_t os); /** set iterator to first object (1 = exists, 0 = doesn't exist) */ ST_API int os_iter_first(os_t os); /** set iterator to next object (1 = exists, 0 = doesn't exist) */ ST_API int os_iter_next(os_t os); /** get the object currently under the iterator */ ST_API os_object_t os_iter_object(os_t os); /** create a new object in this set */ ST_API os_object_t os_object_new(os_t os); /** free an object (remove it from its set) */ ST_API void os_object_free(os_object_t o); /** add a field to the object */ ST_API void os_object_put(os_object_t o, const char *key, const void *val, os_type_t type); /** get a field from the object of type type (result in val), ret 0 == not found */ ST_API int os_object_get(os_t os, os_object_t o, const char *key, void **val, os_type_t type, os_type_t *ot); /** wrappers for os_object_get to avoid breaking strict-aliasing rules in gcc3 */ ST_API int os_object_get_nad(os_t os, os_object_t o, const char *key, nad_t *val); ST_API int os_object_get_str(os_t os, os_object_t o, const char *key, char **val); ST_API int os_object_get_int(os_t os, os_object_t o, const char *key, int *val); ST_API int os_object_get_bool(os_t os, os_object_t o, const char *key, int *val); ST_API int os_object_get_time(os_t os, os_object_t o, const char *key, time_t *val); /** wrappers for os_object_put to avoid breaking strict-aliasing rules in gcc3 */ ST_API void os_object_put_time(os_object_t o, const char *key, const time_t *val); /** set field iterator to first field (1 = exists, 0 = doesn't exist) */ ST_API int os_object_iter_first(os_object_t o); /** set field iterator to next field (1 = exists, 0 = doesn't exist) */ ST_API int os_object_iter_next(os_object_t o); /** extract field values from field currently under the iterator */ ST_API void os_object_iter_get(os_object_t o, char **key, void **val, os_type_t *type); /* storage manager */ /** storage driver return values */ typedef enum { st_SUCCESS, /**< call completed successful */ st_FAILED, /**< call failed (driver internal error) */ st_NOTFOUND, /**< no matching objects were found */ st_NOTIMPL /**< call not implemented */ } st_ret_t; typedef struct st_driver_st *st_driver_t; /** storage manager data */ struct storage_st { // sm_t sm; /**< sm context */ config_t config; /**< config */ log_t log; /**< log context */ xht drivers; /**< pointers to drivers (key is driver name) */ xht types; /**< pointers to drivers (key is type name) */ st_driver_t default_drv; /**< default driver (used when there is no module explicitly registered for a type) */ }; /** data for a single storage driver */ struct st_driver_st { storage_t st; /**< storage manager context */ char *name; /**< name of driver */ #ifdef __cplusplus void *_private; /**< driver private data */ #else void *private; /**< driver private data */ #endif /** called to find out if this driver can handle a particular type */ st_ret_t (*add_type)(st_driver_t drv, const char *type); /** put handler */ st_ret_t (*put)(st_driver_t drv, const char *type, const char *owner, os_t os); /** get handler */ st_ret_t (*get)(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os); /** get custom SQL request */ st_ret_t (*get_custom_sql)(st_driver_t drv, const char *request, os_t *os); /** count handler */ st_ret_t (*count)(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count); /** delete handler */ #ifdef __cplusplus st_ret_t (*_delete)(st_driver_t drv, const char *type, const char *owner, const char *filter); #else st_ret_t (*delete)(st_driver_t drv, const char *type, const char *owner, const char *filter); #endif /** replace handler */ st_ret_t (*replace)(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os); /** called when driver is freed */ void (*free)(st_driver_t drv); }; /** allocate a storage manager instance */ ST_API storage_t storage_new(config_t config, log_t log); /** free a storage manager instance */ ST_API void storage_free(storage_t st); /** associate this data type with this driver */ ST_API st_ret_t storage_add_type(storage_t st, const char *driver, const char *type); /** store objects in this set */ ST_API st_ret_t storage_put(storage_t st, const char *type, const char *owner, os_t os); /** get objects matching this filter */ ST_API st_ret_t storage_get(storage_t st, const char *type, const char *owner, const char *filter, os_t *os); /** get objects matching custom SQL query */ ST_API st_ret_t storage_get_custom_sql(storage_t st, const char *request, os_t *os, const char *type); /** count objects matching this filter */ ST_API st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count); /** delete objects matching this filter */ ST_API st_ret_t storage_delete(storage_t st, const char *type, const char *owner, const char *filter); /** replace objects matching this filter with objects in this set (atomic delete + get) */ ST_API st_ret_t storage_replace(storage_t st, const char *type, const char *owner, const char *filter, os_t os); /** type for the driver init function */ typedef st_ret_t (*st_driver_init_fn)(st_driver_t); /** storage filter types */ typedef enum { st_filter_type_PAIR, /**< key=value pair */ st_filter_type_AND, /**< and operator */ st_filter_type_OR, /**< or operator */ st_filter_type_NOT /**< not operator */ } st_filter_type_t; typedef struct st_filter_st *st_filter_t; /** filter abstraction */ struct st_filter_st { pool_t p; /**< pool that filter is allocated from */ st_filter_type_t type; /**< type of this filter */ char *key; /**< key for PAIR filters */ char *val; /**< value for PAIR filters */ st_filter_t sub; /**< sub-filter for operator filters */ st_filter_t next; /**< next filter in a group */ }; /** create a filter abstraction from a LDAP-like filter string */ ST_API st_filter_t storage_filter(const char *filter); /** see if the object matches the filter */ ST_API int storage_match(st_filter_t filter, os_object_t o, os_t os); #ifdef __cplusplus } // extern "C" #endif #endif // _STORAGE_H_ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_db.c���������������������������������������������������������0000664�0000000�0000000�00000040232�12614627753�0020521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file sm/storage_db.c * @brief berkeley db storage module * @author Robert Norris * $Date: 2005/06/02 04:48:25 $ * $Revision: 1.26 $ */ /* * !!! we must catch DB_RUNRECOVERY and call _st_db_panic(). I would argue that * Berkeley should do this for all cases, not just for the process that * caused the fault, but I'm not sure they see it that way. (I have asked, * just waiting for a reply) * * Sleepycat SR#7019 resolved this. There is an unreleased patch available * (I have a copy) that will be in 4.2 (due in June). */ #include "storage.h" #include <db.h> /** internal structure, holds our data */ typedef struct drvdata_st { DB_ENV *env; const char *path; int sync; xht dbs; xht filters; } *drvdata_t; /** internal structure, holds a single db handle */ typedef struct dbdata_st { drvdata_t data; DB *db; } *dbdata_t; /* union for strict alias rules in gcc3 */ union xhashv { void **val; dbdata_t *dbd_val; }; static st_ret_t _st_db_add_type(st_driver_t drv, const char *type) { drvdata_t data = (drvdata_t) drv->private; dbdata_t dbd; int err; dbd = (dbdata_t) calloc(1, sizeof(struct dbdata_st)); dbd->data = data; if((err = db_create(&(dbd->db), data->env, 0)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't create db handle: %s", db_strerror(err)); free(dbd); return st_FAILED; } if((err = dbd->db->set_flags(dbd->db, DB_DUP)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't set database for duplicate storage: %s", db_strerror(err)); dbd->db->close(dbd->db, 0); free(dbd); return st_FAILED; } if((err = dbd->db->open(dbd->db, NULL, "sm.db", type, DB_HASH, DB_AUTO_COMMIT | DB_CREATE, 0)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't open storage db: %s", db_strerror(err)); dbd->db->close(dbd->db, 0); free(dbd); return st_FAILED; } xhash_put(data->dbs, type, dbd); return st_SUCCESS; } /** make a new cursor (optionally wrapped in a txn) */ static st_ret_t _st_db_cursor_new(st_driver_t drv, dbdata_t dbd, DBC **cursor, DB_TXN **txnid) { int err; if(txnid != NULL) if((err = dbd->data->env->txn_begin(dbd->data->env, NULL, txnid, DB_TXN_SYNC)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't begin new transaction: %s", db_strerror(err)); return st_FAILED; } if(txnid == NULL) err = dbd->db->cursor(dbd->db, NULL, cursor, 0); else err = dbd->db->cursor(dbd->db, *txnid, cursor, 0); if(err != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't create cursor: %s", db_strerror(err)); if(txnid != NULL) (*txnid)->abort(*txnid); return st_FAILED; } return st_SUCCESS; } /** close down a cursor */ static st_ret_t _st_db_cursor_free(st_driver_t drv, dbdata_t dbd, DBC *cursor, DB_TXN *txnid) { int err; if((err = cursor->c_close(cursor)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't close cursor: %s", db_strerror(err)); if(txnid != NULL) txnid->abort(txnid); return st_FAILED; } if(txnid != NULL) if((err = txnid->commit(txnid, DB_TXN_SYNC)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't commit transaction: %s", db_strerror(err)); return st_FAILED; } return st_SUCCESS; } static void _st_db_object_serialise(os_object_t o, char **buf, int *len) { char *key, *xmlstr; const char *xml; void *val; os_type_t ot; int cur = 0, xlen; log_debug(ZONE, "serialising object"); *buf = NULL; *len = 0; if(os_object_iter_first(o)) do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(void *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get(o, &key, &val, &ot); log_debug(ZONE, "serialising key %s", key); ser_string_set(key, &cur, buf, len); ser_int_set(ot, &cur, buf, len); switch(ot) { case os_type_BOOLEAN: ser_int_set(((int)val) != 0, &cur, buf, len); break; case os_type_INTEGER: ser_int_set((int)val, &cur, buf, len); break; case os_type_STRING: ser_string_set((char *) val, &cur, buf, len); break; case os_type_NAD: nad_print((nad_t) val, 0, &xml, &xlen); xmlstr = (char *) malloc(sizeof(char) * (xlen + 1)); sprintf(xmlstr, "%.*s", xlen, xml); ser_string_set(xmlstr, &cur, buf, len); free(xmlstr); break; case os_type_UNKNOWN: break; } } while(os_object_iter_next(o)); *len = cur; } static os_object_t _st_db_object_deserialise(st_driver_t drv, os_t os, const char *buf, int len) { os_object_t o; int cur; char *key, *sval; int ot; int ival; nad_t nad; log_debug(ZONE, "deserialising object"); o = os_object_new(os); cur = 0; while(cur < len) { if(ser_string_get(&key, &cur, buf, len) != 0 || ser_int_get(&ot, &cur, buf, len) != 0) { log_debug(ZONE, "ran off the end of the buffer"); return o; } log_debug(ZONE, "deserialising key %s", key); switch((os_type_t) ot) { case os_type_BOOLEAN: ser_int_get(&ival, &cur, buf, len); ival = (ival != 0); os_object_put(o, key, &ival, os_type_BOOLEAN); break; case os_type_INTEGER: ser_int_get(&ival, &cur, buf, len); os_object_put(o, key, &ival, os_type_INTEGER); break; case os_type_STRING: ser_string_get(&sval, &cur, buf, len); os_object_put(o, key, sval, os_type_STRING); free(sval); break; case os_type_NAD: ser_string_get(&sval, &cur, buf, len); nad = nad_parse(sval, strlen(sval)); free(sval); if(nad == NULL) { log_write(drv->st->log, LOG_ERR, "db: unable to parse stored XML - database corruption?"); return NULL; } os_object_put(o, key, nad, os_type_NAD); nad_free(nad); break; case os_type_UNKNOWN: break; } free(key); } return o; } static st_ret_t _st_db_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os, dbdata_t dbd, DBC *c, DB_TXN *t) { DBT key, val; os_object_t o; char *buf; int len, err; memset(&key, 0, sizeof(DBT)); memset(&val, 0, sizeof(DBT)); key.data = (char *) owner; key.size = strlen(owner); if(os_iter_first(os)) do { o = os_iter_object(os); _st_db_object_serialise(o, &buf, &len); val.data = buf; val.size = len; if((err = c->c_put(c, &key, &val, DB_KEYLAST)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't store value for type %s owner %s in storage db: %s", type, owner, db_strerror(err)); free(buf); return st_FAILED; } free(buf); } while(os_iter_next(os)); return st_SUCCESS; } static st_ret_t _st_db_put(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; dbdata_t dbd = xhash_get(data->dbs, type); DBC *c; DB_TXN *t; st_ret_t ret; if(os_count(os) == 0) return st_SUCCESS; ret = _st_db_cursor_new(drv, dbd, &c, &t); if(ret != st_SUCCESS) return ret; ret = _st_db_put_guts(drv, type, owner, os, dbd, c, t); if(ret != st_SUCCESS) { t->abort(t); _st_db_cursor_free(drv, dbd, c, NULL); return st_FAILED; } return _st_db_cursor_free(drv, dbd, c, t); } static st_ret_t _st_db_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; dbdata_t dbd = xhash_get(data->dbs, type); DBC *c; DB_TXN *t; st_ret_t ret; DBT key, val; st_filter_t f; int err; os_object_t o; char *cfilter; ret = _st_db_cursor_new(drv, dbd, &c, &t); if(ret != st_SUCCESS) return ret; f = NULL; if(filter != NULL) { f = xhash_get(data->filters, filter); if(f == NULL) { f = storage_filter(filter); cfilter = pstrdup(xhash_pool(data->filters), filter); xhash_put(data->filters, cfilter, (void *) f); pool_cleanup(xhash_pool(data->filters), (pool_cleanup_t) pool_free, f->p); } } memset(&key, 0, sizeof(DBT)); memset(&val, 0, sizeof(DBT)); key.data = (char *) owner; key.size = strlen(owner); *os = os_new(); err = c->c_get(c, &key, &val, DB_SET); while(err == 0) { o = _st_db_object_deserialise(drv, *os, val.data, val.size); if(o != NULL && !storage_match(f, o, *os)) os_object_free(o); err = c->c_get(c, &key, &val, DB_NEXT_DUP); } if(err != 0 && err != DB_NOTFOUND) { log_write(drv->st->log, LOG_ERR, "db: couldn't move cursor for type %s owner %s in storage db: %s", type, owner, db_strerror(err)); t->abort(t); _st_db_cursor_free(drv, dbd, c, NULL); os_free(*os); *os = NULL; return st_FAILED; } ret = _st_db_cursor_free(drv, dbd, c, t); if(ret != st_SUCCESS) { os_free(*os); *os = NULL; return ret; } if(os_count(*os) == 0) { os_free(*os); *os = NULL; return st_NOTFOUND; } return st_SUCCESS; } static st_ret_t _st_db_delete_guts(st_driver_t drv, const char *type, const char *owner, const char *filter, dbdata_t dbd, DBC *c, DB_TXN *t) { drvdata_t data = (drvdata_t) drv->private; DBT key, val; st_filter_t f; int err; os_t os; os_object_t o; char *cfilter; f = NULL; if(filter != NULL) { f = xhash_get(data->filters, filter); if(f == NULL) { f = storage_filter(filter); cfilter = pstrdup(xhash_pool(data->filters), filter); xhash_put(data->filters, cfilter, (void *) f); pool_cleanup(xhash_pool(data->filters), (pool_cleanup_t) pool_free, f->p); } } memset(&key, 0, sizeof(DBT)); memset(&val, 0, sizeof(DBT)); key.data = (char *) owner; key.size = strlen(owner); os = os_new(); err = c->c_get(c, &key, &val, DB_SET); while(err == 0) { o = _st_db_object_deserialise(drv, os, val.data, val.size); if(o != NULL && storage_match(f, o, os)) err = c->c_del(c, 0); if(err == 0) err = c->c_get(c, &key, &val, DB_NEXT_DUP); } os_free(os); if(err != 0 && err != DB_NOTFOUND) { log_write(drv->st->log, LOG_ERR, "db: couldn't move cursor for type %s owner %s in storage db: %s", type, owner, db_strerror(err)); return st_FAILED; } return st_SUCCESS; } static st_ret_t _st_db_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; dbdata_t dbd = xhash_get(data->dbs, type); DBC *c; DB_TXN *t; st_ret_t ret; ret = _st_db_cursor_new(drv, dbd, &c, &t); if(ret != st_SUCCESS) return ret; ret = _st_db_delete_guts(drv, type, owner, filter, dbd, c, t); if(ret != st_SUCCESS) { t->abort(t); _st_db_cursor_free(drv, dbd, c, NULL); return st_FAILED; } return _st_db_cursor_free(drv, dbd, c, t); } static st_ret_t _st_db_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { drvdata_t data = (drvdata_t) drv->private; dbdata_t dbd = xhash_get(data->dbs, type); DBC *c; DB_TXN *t; st_ret_t ret; ret = _st_db_cursor_new(drv, dbd, &c, &t); if(ret != st_SUCCESS) return ret; ret = _st_db_delete_guts(drv, type, owner, filter, dbd, c, t); if(ret != st_SUCCESS) { t->abort(t); _st_db_cursor_free(drv, dbd, c, NULL); return st_FAILED; } if(os_count(os) == 0) return _st_db_cursor_free(drv, dbd, c, t); ret = _st_db_put_guts(drv, type, owner, os, dbd, c, t); if(ret != st_SUCCESS) { t->abort(t); _st_db_cursor_free(drv, dbd, c, NULL); return st_FAILED; } return _st_db_cursor_free(drv, dbd, c, t); } static void _st_db_free(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; const char *key; int keylen; dbdata_t dbd; DB_ENV *env; union xhashv xhv; xhv.dbd_val = &dbd; if(xhash_iter_first(data->dbs)) do { xhash_iter_get(data->dbs, &key, &keylen, xhv.val); log_debug(ZONE, "closing %.*s db", keylen, key); dbd->db->close(dbd->db, 0); free(dbd); } while(xhash_iter_next(data->dbs)); xhash_free(data->dbs); xhash_free(data->filters); data->env->close(data->env, 0); /* remove db environment files if no longer in use */ if (db_env_create(&env, 0) == 0) env->remove(env, data->path, 0); free(data); } /** panic function */ static void _st_db_panic(DB_ENV *env, int errval) { log_t log = (log_t) env->app_private; log_write(log, LOG_CRIT, "db: corruption detected! close all jabberd processes and run db_recover"); exit(2); } st_ret_t st_init(st_driver_t drv) { const char *path; int err; DB_ENV *env; drvdata_t data; path = config_get_one(drv->st->config, "storage.db.path", 0); if(path == NULL) { log_write(drv->st->log, LOG_ERR, "db: no path specified in config file"); return st_FAILED; } if((err = db_env_create(&env, 0)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't create environment: %s", db_strerror(err)); return st_FAILED; } if((err = env->set_paniccall(env, _st_db_panic)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't set panic call: %s", db_strerror(err)); return st_FAILED; } /* store the log context in case we panic */ env->app_private = drv->st->log; if((err = env->open(env, path, DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN | DB_CREATE | DB_RECOVER, 0)) != 0) { log_write(drv->st->log, LOG_ERR, "db: couldn't open environment: %s", db_strerror(err)); env->close(env, 0); return st_FAILED; } data = (drvdata_t) calloc(1, sizeof(struct drvdata_st)); data->env = env; data->path = path; if(config_get_one(drv->st->config, "storage.db.sync", 0) != NULL) data->sync = 1; data->dbs = xhash_new(101); data->filters = xhash_new(17); drv->private = (void *) data; drv->add_type = _st_db_add_type; drv->put = _st_db_put; drv->get = _st_db_get; drv->replace = _st_db_replace; drv->delete = _st_db_delete; drv->free = _st_db_free; return st_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_fs.c���������������������������������������������������������0000664�0000000�0000000�00000036203�12614627753�0020547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file sm/storage_fs.c * @brief filesystem storage module * @author Robert Norris * $Date: 2005/06/02 04:48:25 $ * $Revision: 1.15 $ */ /* * WARNING: this uses lots of static buffers, and doesn't do all the bounds * checking that it should. it should not be used for anything other than * testing * * !!! fix everything that makes this a problem */ #include "storage.h" #include <ctype.h> #ifdef HAVE_DIRENT_H # include <dirent.h> # define NAMELEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMELEN(dirent) (dirent)->d_namelen # ifdef HAVE_SYS_NDIR_H # include <sys/ndir.h> # endif # ifdef HAVE_SYS_DIR_H # include <sys/dir.h> # endif # ifdef HAVE_NDIR_H # include <ndir.h> # endif #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #define STORAGE_FS_READ_BLOCKSIZE 8192 /** internal structure, holds our data */ typedef struct drvdata_st { const char *path; } *drvdata_t; static st_ret_t _st_fs_add_type(st_driver_t drv, const char *type) { drvdata_t data = (drvdata_t) drv->private; char path[1024]; struct stat sbuf; int ret; snprintf(path, 1024, "%s/%s", data->path, type); ret = stat(path, &sbuf); if(ret < 0) { if(errno != ENOENT) { log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } log_debug(ZONE, "creating new type dir '%s'", path); ret = mkdir(path, 0755); if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't create directory '%s': %s", path, strerror(errno)); return st_FAILED; } } return st_SUCCESS; } static st_ret_t _st_fs_put(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; char path[1024]; struct stat sbuf; int ret; int file; FILE *f; os_object_t o; char *key; void *val = NULL; os_type_t ot; const char *xml; int len; if(os_count(os) == 0) return st_SUCCESS; snprintf(path, 1024, "%s/%s", data->path, type); ret = stat(path, &sbuf); if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } snprintf(path, 1024, "%s/%s/%s", data->path, type, owner); ret = stat(path, &sbuf); if(ret < 0) { if(errno != ENOENT) { log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } log_debug(ZONE, "creating new collection dir '%s'", path); ret = mkdir(path, 0755); if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't create directory '%s': %s", path, strerror(errno)); return st_FAILED; } } file = -1; if(os_iter_first(os)) do { for(file++; file < 999999; file++) { snprintf(path, 1024, "%s/%s/%s/%d", data->path, type, owner, file); ret = stat(path, &sbuf); if(ret < 0 && errno == ENOENT) break; if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } } log_debug(ZONE, "will store object to %s", path); f = fopen(path, "w"); if(f == NULL) { log_write(drv->st->log, LOG_ERR, "fs: couldn't open '%s' for writing: %s", path, strerror(errno)); return st_FAILED; } o = os_iter_object(os); if(os_object_iter_first(o)) do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(void *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get(o, &key, &val, &ot); log_debug(ZONE, "writing field %s type %d", key, ot); switch(ot) { case os_type_BOOLEAN: fprintf(f, "%s %d %d\n", key, ot, ((int)val != 0) ? 1 : 0); break; case os_type_INTEGER: fprintf(f, "%s %d %d\n", key, ot, (int) val); break; case os_type_STRING: fprintf(f, "%s %d %s\n", key, ot, (char *) val); break; case os_type_NAD: nad_print((nad_t) val, 0, &xml, &len); fprintf(f, "%s %d %.*s\n", key, ot, len, xml); break; case os_type_UNKNOWN: break; } } while(os_object_iter_next(o)); fclose(f); } while(os_iter_next(os)); return st_SUCCESS; } static st_ret_t _st_fs_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; char path[1024], file[1024]; struct stat sbuf; int ret; DIR *dir; struct dirent *dirent; FILE *f; char buf[STORAGE_FS_READ_BLOCKSIZE], *otc, *val, *c; os_object_t o; os_type_t ot; int i, size; nad_t nad; st_filter_t sf; snprintf(path, 1024, "%s/%s/%s", data->path, type, owner); ret = stat(path, &sbuf); if(ret < 0) { if(errno == ENOENT) return st_NOTFOUND; log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } dir = opendir(path); if(dir == NULL) { log_write(drv->st->log, LOG_ERR, "fs: couldn't open directory '%s': %s", path, strerror(errno)); return st_FAILED; } *os = os_new(); errno = 0; while((dirent = readdir(dir)) != NULL) { if(!(isdigit(dirent->d_name[0]))) continue; snprintf(file, 1024, "%s/%s", path, dirent->d_name); f = fopen(file, "r"); if(f == NULL) { log_write(drv->st->log, LOG_ERR, "fs: couldn't open '%s' for reading: %s", path, strerror(errno)); os_free(*os); *os = NULL; *os = NULL; closedir(dir); return st_FAILED; } o = os_object_new(*os); while(fgets(buf, STORAGE_FS_READ_BLOCKSIZE, f) != NULL) { size = strlen(buf); otc = strchr(buf, ' '); *otc = '\0'; otc++; val = strchr(otc, ' '); *val = '\0'; val++; ot = (os_type_t) atoi(otc); switch(ot) { case os_type_BOOLEAN: case os_type_INTEGER: i = atoi(val); os_object_put(o, buf, &i, ot); break; case os_type_STRING: c = strchr(val, '\n'); if(c != NULL) *c = '\0'; os_object_put(o, buf, val, ot); break; case os_type_NAD: nad = nad_parse(val, 0); if(nad == NULL) { while(fgets(buf + size, STORAGE_FS_READ_BLOCKSIZE - size, f) != NULL && nad == NULL && size < STORAGE_FS_READ_BLOCKSIZE) { size += strlen(buf + size); nad = nad_parse(val, 0); } } if(nad == NULL) { log_write(drv->st->log, LOG_ERR, "fs: unable to parse stored XML; type=%s, owner=%s", type, owner); os_free(*os); *os = NULL; fclose(f); closedir(dir); return st_FAILED; } os_object_put(o, buf, nad, ot); nad_free(nad); break; case os_type_UNKNOWN: break; } } if(!feof(f)) { log_write(drv->st->log, LOG_ERR, "fs: couldn't read from '%s': %s", path, strerror(errno)); os_free(*os); *os = NULL; fclose(f); closedir(dir); return st_FAILED; } fclose(f); errno = 0; } if(errno != 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't read from directory '%s': %s", path, strerror(errno)); closedir(dir); os_free(*os); *os = NULL; return st_FAILED; } closedir(dir); sf = storage_filter(filter); if(os_iter_first(*os)) do { o = os_iter_object(*os); if(!storage_match(sf, o, *os)) os_object_free(o); } while(os_iter_next(*os)); if(sf != NULL) pool_free(sf->p); return st_SUCCESS; } static st_ret_t _st_fs_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char path[1024], file[1024]; struct stat sbuf; int ret; DIR *dir; os_t os; struct dirent *dirent; FILE *f; char buf[STORAGE_FS_READ_BLOCKSIZE], *otc, *val, *c; os_object_t o; os_type_t ot; int i, size; nad_t nad; st_filter_t sf; snprintf(path, 1024, "%s/%s/%s", data->path, type, owner); ret = stat(path, &sbuf); if(ret < 0) { if(errno == ENOENT) return st_NOTFOUND; log_write(drv->st->log, LOG_ERR, "fs: couldn't stat '%s': %s", path, strerror(errno)); return st_FAILED; } dir = opendir(path); if(dir == NULL) { log_write(drv->st->log, LOG_ERR, "fs: couldn't open directory '%s': %s", path, strerror(errno)); return st_FAILED; } os = os_new(); sf = storage_filter(filter); errno = 0; while((dirent = readdir(dir)) != NULL) { if(!(isdigit(dirent->d_name[0]))) continue; snprintf(file, 1024, "%s/%s", path, dirent->d_name); f = fopen(file, "r"); if(f == NULL) { log_write(drv->st->log, LOG_ERR, "fs: couldn't open '%s' for reading: %s", path, strerror(errno)); os_free(os); closedir(dir); return st_FAILED; } o = os_object_new(os); while(fgets(buf, STORAGE_FS_READ_BLOCKSIZE, f) != NULL) { size = strlen(buf); otc = strchr(buf, ' '); *otc = '\0'; otc++; val = strchr(otc, ' '); *val = '\0'; val++; ot = (os_type_t) atoi(otc); switch(ot) { case os_type_BOOLEAN: case os_type_INTEGER: i = atoi(val); os_object_put(o, buf, &i, ot); break; case os_type_STRING: c = strchr(val, '\n'); if(c != NULL) *c = '\0'; os_object_put(o, buf, val, ot); break; case os_type_NAD: nad = nad_parse(val, 0); if(nad == NULL) { while(fgets(buf + size, STORAGE_FS_READ_BLOCKSIZE - size, f) != NULL && nad == NULL && size < STORAGE_FS_READ_BLOCKSIZE) { size += strlen(buf + size); nad = nad_parse(val, 0); } } if(nad == NULL) log_write(drv->st->log, LOG_ERR, "fs: unable to parse stored XML; type=%s, owner=%s", type, owner); else { os_object_put(o, buf, nad, ot); nad_free(nad); } break; case os_type_UNKNOWN: break; } } if(!feof(f)) { log_write(drv->st->log, LOG_ERR, "fs: couldn't read from '%s': %s", path, strerror(errno)); os_free(os); fclose(f); closedir(dir); return st_FAILED; } fclose(f); if(storage_match(sf, o, os)) { ret = unlink(file); if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't unlink '%s': %s", path, strerror(errno)); if(sf != NULL) pool_free(sf->p); os_free(os); closedir(dir); return st_FAILED; } } errno = 0; } if(errno != 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't read from directory '%s': %s", path, strerror(errno)); closedir(dir); os_free(os); return st_FAILED; } if(sf != NULL) pool_free(sf->p); os_free(os); closedir(dir); return st_SUCCESS; } static st_ret_t _st_fs_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { st_ret_t ret; ret = _st_fs_delete(drv, type, owner, filter); if(ret == st_SUCCESS || ret == st_NOTFOUND) ret = _st_fs_put(drv, type, owner, os); return ret; } static void _st_fs_free(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; free(data); } st_ret_t st_init(st_driver_t drv) { const char *path; struct stat sbuf; int ret; drvdata_t data; path = config_get_one(drv->st->config, "storage.fs.path", 0); if(path == NULL) { log_write(drv->st->log, LOG_ERR, "fs: no path specified in config file"); return st_FAILED; } ret = stat(path, &sbuf); if(ret < 0) { log_write(drv->st->log, LOG_ERR, "fs: couldn't stat path '%s': %s", path, strerror(errno)); return st_FAILED; } data = (drvdata_t) calloc(1, sizeof(struct drvdata_st)); data->path = path; drv->private = (void *) data; drv->add_type = _st_fs_add_type; drv->put = _st_fs_put; drv->get = _st_fs_get; drv->delete = _st_fs_delete; drv->replace = _st_fs_replace; drv->free = _st_fs_free; log_write(drv->st->log, LOG_WARNING, "fs: the filesystem storage driver should only be used for testing!"); return st_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_ldapvcard.c��������������������������������������������������0000664�0000000�0000000�00000061111�12614627753�0022073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* * Written by Nikita Smirnov in 2004 * on basis of authreg_ldap.c and storage_fs.c */ #include "storage.h" #ifdef STORAGE_LDAP #define LDAP_DEPRECATED 1 #include <ldap.h> #include <time.h> #include <regex.h> #define LDAPVCARD_SRVTYPE_LDAP 1 #define LDAPVCARD_SRVTYPE_AD 2 #define LDAPVCARD_SEARCH_MAX_RETRIES 1 extern int _ldap_get_lderrno(LDAP *ld); /** internal structure, holds our data */ typedef struct drvdata_st { LDAP *ld; const char *uri; const char *realm; // server id to be appended to uid const char *binddn; const char *bindpw; const char *basedn; const char *objectclass; // objectclass of jabber users const char *uidattr; // search attribute for users const char *validattr; // search attribute for valid const char *pwattr; // attribute which holds password const char *groupattr; // attribute with group name for published-roster in jabberuser entry const char *groupattr_regex; // regex to create a new group attribute based on groupattr const char *publishedattr; // can we publish it? const char *groupsdn; // base dn for group names search const char *groupsoc; // objectclass for group names search const char *groupsidattr; // search attribute for group names const char *groupnameattr; // attribute with text group name int srvtype; int mappedgroups; #ifndef NO_SM_CACHE os_t cache; time_t cache_time; time_t cache_ttl; #endif } *drvdata_t; typedef struct { char *ldapentry, *vcardentry; os_type_t ot; } ldapvcard_entry_st; ldapvcard_entry_st ldapvcard_entry[] = { {"displayName","fn",os_type_STRING}, {"cn","nickname",os_type_STRING}, {"labeledURI","url",os_type_STRING}, {"telephoneNumber","tel",os_type_STRING}, {"mail","email",os_type_STRING}, {"title","title",os_type_STRING}, {"role","role",os_type_STRING}, {"dateOfBirth","bday",os_type_UNKNOWN}, /* fake type. TODO: os_type_DATE? */ // {"birthDate","bday",os_type_UNKNOWN}, /* http://tools.ietf.org/html/draft-gryphon-ldap-schema-vcard4-00 */ {"description","desc",os_type_STRING}, {"givenName","n-given",os_type_STRING}, {"jpegPhoto","photo-binval",os_type_STRING}, {"sn","n-family",os_type_STRING}, {"initials","n-middle",os_type_STRING}, {"st","adr-street",os_type_STRING}, {"zip","adr-extadd",os_type_STRING}, {"l","adr-locality",os_type_STRING}, // {"","adr-region",os_type_STRING}, {"postalCode","adr-pcode",os_type_STRING}, {"c","adr-country",os_type_STRING}, {"o","org-orgname",os_type_STRING}, {"ou","org-orgunit",os_type_STRING}, {NULL,NULL,0} }; static int processregex(char *src, const char *regex, int patterngroups, int wantedgroup, char *dest, size_t dest_size, st_driver_t drv) { regex_t preg; regmatch_t pmatch[patterngroups]; //log_debug(ZONE,"processregex: src='%s' regex='%s'", src, regex); if (regcomp(&preg, regex, REG_ICASE|REG_EXTENDED) !=0) { log_write(drv->st->log, LOG_ERR, "ldapvcard: regex compile failed on '%s'", regex); return -1; } if (regexec(&preg, src, patterngroups, pmatch, 0) !=0) { log_write(drv->st->log, LOG_ERR, "ldapvcard: regexec failed"); return -2; } regfree(&preg); int len = pmatch[wantedgroup].rm_eo-pmatch[wantedgroup].rm_so>dest_size?dest_size:pmatch[wantedgroup].rm_eo-pmatch[wantedgroup].rm_so; memcpy(dest, src+pmatch[wantedgroup].rm_so, len); dest[len<dest_size?len:dest_size]='\0'; //log_debug(ZONE,"processregex: dest='%s'", dest); return 0; } #ifndef NO_SM_CACHE void os_copy(os_t src, os_t dst) { os_object_t o,dsto; char *key; void *val, *cval; os_type_t ot; if(os_iter_first(src)) { do { //log_write(log, LOG_ERR, "reading object"); o = os_iter_object(src); dsto = os_object_new(dst); if( os_object_iter_first(o)) { do { os_object_iter_get(o,&key,&val,&ot); switch(ot) { case os_type_BOOLEAN: case os_type_INTEGER: cval = &val; break; default: cval = val; } os_object_put(dsto,key,cval,ot); //log_write(log, LOG_ERR, "wrote."); } while(os_object_iter_next(o)); } } while(os_iter_next(src)); } else { // ! os_iter_first(src) log_debug(ZONE,"os_copy: cannot read source object"); } } #endif /** utility function to get ld_errno */ static int _st_ldapvcard_get_lderrno(LDAP *ld) { int ld_errno; ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno); return ld_errno; } /** entry-point function for following referrals, required in some cases by Active Directory */ static int rebindProc(LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *mdata) { drvdata_t data = mdata; data->ld = ld; if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw)) { log_debug(ZONE, "ldapvcard: bind failed (to %s): %s", url, ldap_err2string(_ldap_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return LDAP_INAPPROPRIATE_AUTH; } return LDAP_SUCCESS; } /** connect to the ldap host */ static int _st_ldapvcard_connect(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; int ldapversion = LDAP_VERSION3; int rc; if(data->ld != NULL) ldap_unbind_s(data->ld); rc = ldap_initialize( &(data->ld), data->uri); if( rc != LDAP_SUCCESS ) { log_write(drv->st->log, LOG_ERR, "ldapvcard: ldap_initialize failed (uri=%s): %s", data->uri, ldap_err2string(rc)); return 1; } if (ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_SUCCESS) { log_write(drv->st->log, LOG_ERR, "ldapvcard: couldn't set v3 protocol"); return 1; } if (ldap_set_option(data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS) { log_write(drv->st->log, LOG_ERR, "ldapvcard: couldn't set LDAP_OPT_REFERRALS"); } return 0; } /** unbind and clear variables */ static int _st_ldapvcard_unbind(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; ldap_unbind_s(data->ld); data->ld = NULL; return 0; } /** connect to ldap and bind as data->binddn */ static int _st_ldapvcard_connect_bind(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; if(data->ld != NULL ) { return 0; } if( _st_ldapvcard_connect(drv) ) { return 1; } if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw)) { log_write(drv->st->log, LOG_ERR, "ldapvcard: bind as %s failed: %s", data->binddn, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); return 1; } return 0; } static st_ret_t _st_ldapvcard_add_type(st_driver_t drv, const char *type) { drvdata_t data = (drvdata_t) drv->private; if( strncmp(type,"vcard",6) && strncmp(type,"published-roster",17) && strncmp(type,"published-roster-groups",24) ) { log_write(drv->st->log, LOG_ERR, "ldapvcard: only vcard,published-roster,published-roster-groups types supperted for now"); return st_FAILED; } else { if( !strncmp(type,"published-roster-groups",24) ) { if( !data->mappedgroups ) { log_write(drv->st->log, LOG_ERR, "ldapvcard: published-roster-groups is not enabled by map-groups config option in ldapvcard section"); return st_FAILED; } } return st_SUCCESS; } return st_SUCCESS; } static st_ret_t _st_ldapvcard_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; os_object_t o; char validfilter[256], ldapfilter[1024], **vals; char *attrs_vcard[sizeof(ldapvcard_entry)/sizeof(ldapvcard_entry_st)]; const char *attrs_pr[] = { data->uidattr, data->groupattr, "sn", "displayName", "initials", NULL }; const char *attrs_prg[] = { data->groupnameattr, NULL }; LDAPMessage *result, *entry; ldapvcard_entry_st le; int i,ival; int tried = 0; char jid[2048], group[1024], name[2048]; // name is sn[1024] + ' ' + initials[1024] if( _st_ldapvcard_connect_bind(drv) ) { return st_FAILED; } if( strncmp(type,"vcard",6) == 0 ) { // prepare need attributes i = 0; do { le = ldapvcard_entry[i]; attrs_vcard[i++] = le.ldapentry; } while ( le.ldapentry != NULL ); snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=%s))", data->objectclass, data->uidattr, owner); log_debug(ZONE, "search filter: %s", ldapfilter); if(ldap_set_rebind_proc(data->ld, &rebindProc, data)) { log_write(drv->st->log, LOG_ERR, "ldap: set_rebind_proc failed: %s", ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); ldap_unbind_s(data->ld); data->ld = NULL; return st_FAILED; } if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, attrs_vcard, 0, &result)) { log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); return st_FAILED; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return st_FAILED; } *os = os_new(); o = os_object_new(*os); i = 0; le = ldapvcard_entry[i]; while( le.ldapentry != NULL ) { if ( (strlen(le.ldapentry) == 9) && (!strncmp("jpegPhoto",le.ldapentry,9))) { struct berval **valphoto=(struct berval **)ldap_get_values_len(data->ld,entry,le.ldapentry); if ( ldap_count_values_len(valphoto) > 0 ) { char *VALJPG = b64_encode(valphoto[0]->bv_val, valphoto[0]->bv_len); os_object_put(o, "photo-binval", VALJPG, os_type_STRING); if( !strncmp(VALJPG, "/9j/4", 5) ) { os_object_put(o, "photo-type", "image/jpeg", os_type_STRING); } else if( !strncmp(VALJPG, "iVBOR", 5) ) { os_object_put(o, "photo-type", "image/png", os_type_STRING); } else if( !strncmp(VALJPG, "R0lGO", 5) ) { os_object_put(o, "photo-type", "image/gif", os_type_STRING); } else { log_write(drv->st->log, LOG_ERR, "ldap: unknown photo fprmat photo %s", VALJPG); os_object_put(o, "photo-type", "image/jpeg", os_type_STRING); } free(VALJPG); } ldap_value_free_len(valphoto); } else { vals=(char **)ldap_get_values(data->ld,entry,le.ldapentry); if( ldap_count_values(vals) > 0 ) { switch(le.ot) { case os_type_BOOLEAN: case os_type_INTEGER: ival=atoi(vals[0]); os_object_put(o, le.vcardentry, &ival, le.ot); break; case os_type_STRING: os_object_put(o, le.vcardentry, vals[0], le.ot); break; case os_type_UNKNOWN: /* TODO: os_type_DATE? */ if( strlen(vals[0])==15 && vals[0][14]=='Z' ) { /* YYYYMMDDHHmmssZ */ /* convert generalizedTime to ISO-8601 date */ vals[0][10]='\0'; vals[0][9]=vals[0][7]; vals[0][8]=vals[0][6]; vals[0][7]='-'; vals[0][6]=vals[0][5]; vals[0][5]=vals[0][4]; vals[0][4]='-'; os_object_put(o, le.vcardentry, vals[0], os_type_STRING); } break; case os_type_NAD: log_write(drv->st->log, LOG_ERR, "ldapvcard: got unsupported os_type_NAD"); break; } } ldap_value_free(vals); } le = ldapvcard_entry[++i]; } ldap_msgfree(result); } else if( strncmp(type,"published-roster",17) == 0 ) { #ifndef NO_SM_CACHE if( data->cache_ttl && data->cache && (time(NULL) - data->cache_time < data->cache_ttl) ) { *os = os_new(); os_copy(data->cache, *os); } else { #endif validfilter[0] = '\0'; if( data->srvtype == LDAPVCARD_SRVTYPE_AD ) { if( data->validattr ) { snprintf(validfilter, 256, "(%s=TRUE)(%s=TRUE)", data->publishedattr, data->validattr); } else { snprintf(validfilter, 256, "(%s=TRUE)", data->publishedattr); } } else { if( data->validattr ) { snprintf(validfilter, 256, "(&(%s=*)(!(%s=0)))(%s=1)", data->publishedattr, data->publishedattr, data->validattr); } else { snprintf(validfilter, 256, "(&(%s=*)(!(%s=0)))", data->publishedattr, data->publishedattr); } } snprintf(ldapfilter, 1024, "(&%s(objectClass=%s)(%s=*))", validfilter, data->objectclass, data->uidattr); log_debug(ZONE, "search filter: %s", ldapfilter); retry_pubrost: if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, (char**)attrs_pr, 0, &result)) { if( tried++ < LDAPVCARD_SEARCH_MAX_RETRIES ) { log_debug(ZONE, "ldapvcard: search fail, will retry; %s: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); if( _st_ldapvcard_connect_bind(drv) == 0 ) { goto retry_pubrost; } else { return st_FAILED; } } log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); return st_FAILED; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return st_FAILED; } *os = os_new(); do { vals = (char **)ldap_get_values(data->ld,entry,data->groupattr); if( ldap_count_values(vals) <= 0 ) { ldap_value_free(vals); continue; } if (data->groupattr_regex == NULL || processregex(vals[0],data->groupattr_regex,2,1,group,sizeof(group),drv) !=0) { // if there is no regex defined or processing the regex failed - take value as is strncpy(group,vals[0],sizeof(group)-1); } group[sizeof(group)-1]='\0'; ldap_value_free(vals); vals = (char **)ldap_get_values(data->ld,entry,data->uidattr); if( ldap_count_values(vals) <= 0 ) { ldap_value_free(vals); continue; } if( data->realm == NULL ) { strncpy(jid,vals[0],sizeof(jid)-1); jid[sizeof(jid)-1]='\0'; } else { snprintf(jid, 2048, "%s@%s", vals[0], data->realm); } ldap_value_free(vals); vals = (char **)ldap_get_values(data->ld,entry,"displayName"); if( ldap_count_values(vals) <= 0 ) { ldap_value_free(vals); vals = (char **)ldap_get_values(data->ld,entry,"cn"); if( ldap_count_values(vals) <= 0 ) { strncpy(name,jid,sizeof(name)-1); name[sizeof(name)-1]='\0'; } else { strncpy(name,vals[0],sizeof(name)-1); name[sizeof(name)-1]='\0'; } } else { strncpy(name,vals[0],1023); name[1023]='\0'; } ldap_value_free(vals); o = os_object_new(*os); os_object_put(o,"jid",jid,os_type_STRING); os_object_put(o,"group",group,os_type_STRING); os_object_put(o,"name",name,os_type_STRING); ival=1; os_object_put(o,"to",&ival,os_type_BOOLEAN); os_object_put(o,"from",&ival,os_type_BOOLEAN); ival=0; os_object_put(o,"ask",&ival,os_type_INTEGER); } while( (entry = ldap_next_entry(data->ld, entry)) ); ldap_msgfree(result); #ifndef NO_SM_CACHE if( data->cache_ttl ) { if( data->cache ) { os_free(data->cache); } data->cache = os_new(); os_copy(*os, data->cache); data->cache_time = time(NULL); } #endif #ifndef NO_SM_CACHE } // if !cached #endif } else if( strncmp(type,"published-roster-groups",24) == 0 ) { snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=%s))", data->groupsoc, data->groupsidattr, owner); log_debug(ZONE, "search filter: %s", ldapfilter); retry_pubrostgr: if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, (char**)attrs_prg, 0, &result)) { if( tried++ < LDAPVCARD_SEARCH_MAX_RETRIES ) { log_debug(ZONE, "ldapvcard: search fail, will retry; %s: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); if( _st_ldapvcard_connect_bind(drv) == 0 ) { goto retry_pubrostgr; } else { return st_FAILED; } } log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld))); _st_ldapvcard_unbind(drv); return st_FAILED; } entry = ldap_first_entry(data->ld, result); if(entry == NULL) { ldap_msgfree(result); return st_FAILED; } *os = os_new(); // use only the first found entry and the first found attribute value vals = (char **)ldap_get_values(data->ld,entry,data->groupnameattr); if( ldap_count_values(vals) <= 0 ) { ldap_value_free(vals); ldap_msgfree(result); return st_FAILED; } strncpy(group,vals[0],sizeof(group)-1); group[sizeof(group)-1]='\0'; ldap_value_free(vals); ldap_msgfree(result); o = os_object_new(*os); os_object_put(o,"groupname",group,os_type_STRING); } else { log_write(drv->st->log, LOG_ERR, "ldapvcard: unknown storage type: '%s'", type); return st_FAILED; } return st_SUCCESS; } static st_ret_t _st_ldapvcard_put(st_driver_t drv, const char *type, const char *owner, os_t os) { return st_FAILED; } static st_ret_t _st_ldapvcard_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { return st_SUCCESS; } static st_ret_t _st_ldapvcard_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { return st_FAILED; } static void _st_ldapvcard_free(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; if( data->ld ) { _st_ldapvcard_unbind(drv); } free(data); } DLLEXPORT st_ret_t st_init(st_driver_t drv) { drvdata_t data; const char *uri, *realm, *basedn, *srvtype_s; int srvtype_i; log_write(drv->st->log, LOG_NOTICE, "ldapvcard: initializing"); uri = config_get_one(drv->st->config, "storage.ldapvcard.uri", 0); if(uri == NULL) { log_write(drv->st->log, LOG_ERR, "ldapvcard: no uri specified in config file"); return st_FAILED; } realm = config_get_one(drv->st->config, "storage.ldapvcard.realm", 0); if(realm != NULL) { log_write(drv->st->log, LOG_NOTICE, "ldapvcard: defined realm %s", realm); } basedn = config_get_one(drv->st->config, "storage.ldapvcard.basedn", 0); if(basedn == NULL) { log_write(drv->st->log, LOG_ERR, "ldapvcard: no basedn specified in config file"); return st_FAILED; } srvtype_s = config_get_one(drv->st->config, "storage.ldapvcard.type", 0); if( srvtype_s == NULL ) { srvtype_i = LDAPVCARD_SRVTYPE_LDAP; } else if( !strcmp(srvtype_s, "ldap") ) { srvtype_i = LDAPVCARD_SRVTYPE_LDAP; } else if( !strcmp(srvtype_s, "ad") ) { srvtype_i = LDAPVCARD_SRVTYPE_AD; } else { log_write(drv->st->log, LOG_ERR, "ldapvcard: unknown server type: %s", srvtype_s); return 1; } data = (drvdata_t) calloc(1, sizeof(struct drvdata_st)); drv->private = (void *) data; data->uri = uri; data->realm = realm; data->basedn = basedn; data->srvtype = srvtype_i; data->binddn = config_get_one(drv->st->config, "storage.ldapvcard.binddn", 0); if(data->binddn != NULL) data->bindpw = config_get_one(drv->st->config, "storage.ldapvcard.bindpw", 0); data->uidattr = config_get_one(drv->st->config, "storage.ldapvcard.uidattr", 0); if(data->uidattr == NULL) data->uidattr = "uid"; data->validattr = config_get_one(drv->st->config, "storage.ldapvcard.validattr", 0); data->groupattr = config_get_one(drv->st->config, "storage.ldapvcard.groupattr", 0); if(data->groupattr == NULL) data->groupattr = "jabberPublishedGroup"; data->groupattr_regex = config_get_one(drv->st->config, "storage.ldapvcard.groupattr_regex", 0); data->publishedattr = config_get_one(drv->st->config, "storage.ldapvcard.publishedattr", 0); if(data->publishedattr == NULL) data->publishedattr = "jabberPublishedItem"; #ifndef NO_SM_CACHE data->cache_ttl = j_atoi(config_get_one(drv->st->config, "storage.ldapvcard.publishedcachettl", 0), 0); data->cache = NULL; data->cache_time = 0; #endif data->objectclass = config_get_one(drv->st->config, "storage.ldapvcard.objectclass", 0); if(data->objectclass == NULL) data->objectclass = "jabberUser"; data->mappedgroups = j_atoi(config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.map-groups", 0), 0); if( data->mappedgroups ) { data->groupsdn = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.basedn", 0); if(data->groupsdn == NULL) { log_write(drv->st->log, LOG_ERR, "ldapvcard: no basedn for mapped-groups specified in config file"); return st_FAILED; } data->groupsoc = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.objectclass", 0); if(data->groupsoc == NULL) data->groupsoc = "jabberGroup"; data->groupsidattr = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.idattr", 0); if(data->groupsidattr == NULL) data->groupsidattr = "cn"; data->groupnameattr = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.nameattr", 0); if(data->groupnameattr == NULL) data->groupnameattr = "description"; } drv->add_type = _st_ldapvcard_add_type; drv->put = _st_ldapvcard_put; drv->get = _st_ldapvcard_get; drv->delete = _st_ldapvcard_delete; drv->replace = _st_ldapvcard_replace; drv->free = _st_ldapvcard_free; return st_SUCCESS; } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_mysql.c������������������������������������������������������0000664�0000000�0000000�00000047354�12614627753�0021315�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file sm/storage_mysql.c * @brief mysql storage module * @author Robert Norris * $Date: 2005/06/22 20:31:22 $ * $Revision: 1.22 $ */ #include "storage.h" #include <mysql.h> /** internal structure, holds our data */ typedef struct drvdata_st { MYSQL *conn; const char *prefix; int txn; } *drvdata_t; #define FALLBACK_BLOCKSIZE (4096) /** internal: do and return the math and ensure it gets realloc'd */ static size_t _st_mysql_realloc(char **oblocks, size_t len) { void *nblocks; size_t nlen; static size_t block_size = 0; if (block_size == 0) { #ifdef HAVE_GETPAGESIZE block_size = getpagesize(); #elif defined(_SC_PAGESIZE) block_size = sysconf(_SC_PAGESIZE); #elif defined(_SC_PAGE_SIZE) block_size = sysconf(_SC_PAGE_SIZE); #else block_size = FALLBACK_BLOCKSIZE; #endif } /* round up to standard block sizes */ nlen = (((len-1)/block_size)+1)*block_size; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define MYSQL_SAFE(blocks, size, len) if((unsigned int)(size) >= (unsigned int)(len)) len = _st_mysql_realloc(&(blocks),(size + 1)); static void _st_mysql_convert_filter_recursive(st_driver_t drv, st_filter_t f, char **buf, int *buflen, int *nbuf) { drvdata_t data = (drvdata_t) drv->private; st_filter_t scan; char *cval; int vlen; switch(f->type) { case st_filter_type_PAIR: /* do sql escape processing of f->val */ cval = (char *) malloc(sizeof(char) * ((strlen((char *) f->val) * 2) + 1)); vlen = mysql_real_escape_string(data->conn, cval, (char *) f->val, strlen((char *) f->val)); MYSQL_SAFE((*buf), *buflen + 12 + strlen(f->key) + vlen, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( `%s` = \'%s\' ) ", f->key, cval); free(cval); break; case st_filter_type_AND: MYSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_mysql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { MYSQL_SAFE((*buf), *buflen + 4, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "AND "); } } MYSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_OR: MYSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_mysql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { MYSQL_SAFE((*buf), *buflen + 3, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "OR "); } } MYSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_NOT: MYSQL_SAFE((*buf), *buflen + 6, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( NOT "); _st_mysql_convert_filter_recursive(drv, f->sub, buf, buflen, nbuf); MYSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; } } static char *_st_mysql_convert_filter(st_driver_t drv, const char *owner, const char *filter) { char *buf = NULL; int buflen = 0, nbuf = 0; st_filter_t f; MYSQL_SAFE(buf, 23 + strlen(owner), buflen); nbuf = sprintf(buf, "`collection-owner` = '%s'", owner); f = storage_filter(filter); if(f == NULL) return buf; MYSQL_SAFE(buf, buflen + 5, buflen); nbuf += sprintf(&buf[nbuf], " AND "); _st_mysql_convert_filter_recursive(drv, f, &buf, &buflen, &nbuf); pool_free(f->p); return buf; } static st_ret_t _st_mysql_add_type(st_driver_t drv, const char *type) { return st_SUCCESS; } static st_ret_t _st_mysql_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; char *left = NULL, *right = NULL; int lleft = 0, lright = 0, nleft, nright; os_object_t o; char *key, *cval = NULL; void *val; os_type_t ot; const char *xml; int xlen; char tbuf[128]; if(os_count(os) == 0) return st_SUCCESS; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } if(os_iter_first(os)) do { MYSQL_SAFE(left, strlen(type) + 35, lleft); nleft = sprintf(left, "INSERT INTO `%s` ( `collection-owner`", type); MYSQL_SAFE(right, strlen(owner) + 14, lright); nright = sprintf(right, " ) VALUES ( '%s'", owner); o = os_iter_object(os); if(os_object_iter_first(o)) do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(void *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get(o, &key, &val, &ot); switch(ot) { case os_type_BOOLEAN: cval = ((int)val != 0) ? strdup("1") : strdup("0"); break; case os_type_INTEGER: cval = (char *) malloc(sizeof(char) * 20); sprintf(cval, "%d", (int) val); break; case os_type_STRING: cval = (char *) malloc(sizeof(char) * ((strlen((char *) val) * 2) + 1)); mysql_real_escape_string(data->conn, cval, (char *) val, strlen((char *) val)); break; case os_type_NAD: nad_print((nad_t) val, 0, &xml, &xlen); cval = (char *) malloc(sizeof(char) * ((xlen * 2) + 4)); mysql_real_escape_string(data->conn, &cval[3], xml, xlen); strncpy(cval, "NAD", 3); break; case os_type_UNKNOWN: break; } log_debug(ZONE, "key %s val %s", key, cval); MYSQL_SAFE(left, lleft + strlen(key) + 4, lleft); nleft += sprintf(&left[nleft], ", `%s`", key); MYSQL_SAFE(right, lright + strlen(cval) + 4, lright); nright += sprintf(&right[nright], ", '%s'", cval); free(cval); } while(os_object_iter_next(o)); MYSQL_SAFE(left, lleft + strlen(right) + 2, lleft); sprintf(&left[nleft], "%s )", right); log_debug(ZONE, "prepared sql: %s", left); if(mysql_query(data->conn, left) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql insert failed: %s", mysql_error(data->conn)); free(left); free(right); return st_FAILED; } } while(os_iter_next(os)); free(left); free(right); return st_SUCCESS; } static st_ret_t _st_mysql_put(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; if(os_count(os) == 0) return st_SUCCESS; if(mysql_ping(data->conn) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database lost"); return st_FAILED; } if(data->txn) { if(mysql_query(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction setup failed: %s", mysql_error(data->conn)); return st_FAILED; } if(mysql_query(data->conn, "BEGIN") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction begin failed: %s", mysql_error(data->conn)); return st_FAILED; } } if(_st_mysql_put_guts(drv, type, owner, os) != st_SUCCESS) { if(data->txn) mysql_query(data->conn, "ROLLBACK"); return st_FAILED; } if(data->txn) if(mysql_query(data->conn, "COMMIT") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction commit failed: %s", mysql_error(data->conn)); mysql_query(data->conn, "ROLLBACK"); return st_FAILED; } return st_SUCCESS; } static st_ret_t _st_mysql_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; MYSQL_RES *res; int ntuples, nfields, i, j; MYSQL_FIELD *fields; MYSQL_ROW tuple; os_object_t o; char *val; os_type_t ot; int ival; char tbuf[128]; if(mysql_ping(data->conn) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database lost"); return st_FAILED; } if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_mysql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); MYSQL_SAFE(buf, strlen(type) + strlen(cond) + 50, buflen); sprintf(buf, "SELECT * FROM `%s` WHERE %s ORDER BY `object-sequence`", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); if(mysql_query(data->conn, buf) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql select failed: %s", mysql_error(data->conn)); free(buf); return st_FAILED; } free(buf); res = mysql_store_result(data->conn); if(res == NULL) { log_write(drv->st->log, LOG_ERR, "mysql: sql result retrieval failed: %s", mysql_error(data->conn)); return st_FAILED; } ntuples = mysql_num_rows(res); if(ntuples == 0) { mysql_free_result(res); return st_NOTFOUND; } log_debug(ZONE, "%d tuples returned", ntuples); nfields = mysql_num_fields(res); if(nfields == 0) { log_debug(ZONE, "weird, tuples were returned but no fields *shrug*"); mysql_free_result(res); return st_NOTFOUND; } fields = mysql_fetch_fields(res); *os = os_new(); for(i = 0; i < ntuples; i++) { o = os_object_new(*os); if((tuple = mysql_fetch_row(res)) == NULL) break; for(j = 0; j < nfields; j++) { if(strcmp(fields[j].name, "collection-owner") == 0) continue; if(tuple[j] == NULL) continue; // mysql_fetch_lengths(res); // TODO check if mysql_fetch_lengths must be called. switch(fields[j].type) { case FIELD_TYPE_TINY: /* tinyint */ ot = os_type_BOOLEAN; break; case FIELD_TYPE_LONG: /* integer */ ot = os_type_INTEGER; break; case FIELD_TYPE_BLOB: /* text */ case FIELD_TYPE_VAR_STRING: /* varchar */ ot = os_type_STRING; break; default: log_debug(ZONE, "unknown field type %d, ignoring it", fields[j].type); continue; } val = tuple[j]; switch(ot) { case os_type_BOOLEAN: ival = (val[0] == '0') ? 0 : 1; os_object_put(o, fields[j].name, &ival, ot); break; case os_type_INTEGER: ival = atoi(val); os_object_put(o, fields[j].name, &ival, ot); break; case os_type_STRING: os_object_put(o, fields[j].name, val, os_type_STRING); break; case os_type_NAD: case os_type_UNKNOWN: break; } } } mysql_free_result(res); return st_SUCCESS; } static st_ret_t _st_mysql_count(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; MYSQL_RES *res; int ntuples, nfields; MYSQL_ROW tuple; char tbuf[128]; if(mysql_ping(data->conn) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database lost"); return st_FAILED; } if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_mysql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); MYSQL_SAFE(buf, strlen(type) + strlen(cond) + 31, buflen); sprintf(buf, "SELECT COUNT(*) FROM `%s` WHERE %s", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); if(mysql_query(data->conn, buf) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql select failed: %s", mysql_error(data->conn)); free(buf); return st_FAILED; } free(buf); res = mysql_store_result(data->conn); if(res == NULL) { log_write(drv->st->log, LOG_ERR, "mysql: sql result retrieval failed: %s", mysql_error(data->conn)); return st_FAILED; } ntuples = mysql_num_rows(res); if(ntuples == 0) { mysql_free_result(res); return st_NOTFOUND; } log_debug(ZONE, "%d tuples returned", ntuples); nfields = mysql_num_fields(res); if(nfields == 0) { log_debug(ZONE, "weird, tuples were returned but no fields *shrug*"); mysql_free_result(res); return st_NOTFOUND; } if((tuple = mysql_fetch_row(res)) == NULL) return st_NOTFOUND; if (count!=NULL) *count = atoi(tuple[0]); mysql_free_result(res); return st_SUCCESS; } static st_ret_t _st_mysql_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; char tbuf[128]; if(mysql_ping(data->conn) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database lost"); return st_FAILED; } if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_mysql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); MYSQL_SAFE(buf, strlen(type) + strlen(cond) + 21, buflen); sprintf(buf, "DELETE FROM `%s` WHERE %s", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); if(mysql_query(data->conn, buf) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql delete failed: %s", mysql_error(data->conn)); free(buf); return st_FAILED; } free(buf); return st_SUCCESS; } static st_ret_t _st_mysql_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { drvdata_t data = (drvdata_t) drv->private; if(mysql_ping(data->conn) != 0) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database lost"); return st_FAILED; } if(data->txn) { if(mysql_query(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction setup failed: %s", mysql_error(data->conn)); return st_FAILED; } if(mysql_query(data->conn, "BEGIN") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction begin failed: %s", mysql_error(data->conn)); return st_FAILED; } } if(_st_mysql_delete(drv, type, owner, filter) == st_FAILED) { if(data->txn) mysql_query(data->conn, "ROLLBACK"); return st_FAILED; } if(_st_mysql_put_guts(drv, type, owner, os) == st_FAILED) { if(data->txn) mysql_query(data->conn, "ROLLBACK"); return st_FAILED; } if(data->txn) if(mysql_query(data->conn, "COMMIT") != 0) { log_write(drv->st->log, LOG_ERR, "mysql: sql transaction commit failed: %s", mysql_error(data->conn)); mysql_query(data->conn, "ROLLBACK"); return st_FAILED; } return st_SUCCESS; } static void _st_mysql_free(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; mysql_close(data->conn); free(data); } DLLEXPORT st_ret_t st_init(st_driver_t drv) { const char *host, *port, *dbname, *user, *pass; MYSQL *conn; drvdata_t data; host = config_get_one(drv->st->config, "storage.mysql.host", 0); port = config_get_one(drv->st->config, "storage.mysql.port", 0); dbname = config_get_one(drv->st->config, "storage.mysql.dbname", 0); user = config_get_one(drv->st->config, "storage.mysql.user", 0); pass = config_get_one(drv->st->config, "storage.mysql.pass", 0); if(host == NULL || port == NULL || dbname == NULL || user == NULL || pass == NULL) { log_write(drv->st->log, LOG_ERR, "mysql: invalid driver config"); return st_FAILED; } conn = mysql_init(NULL); if(conn == NULL) { log_write(drv->st->log, LOG_ERR, "mysql: unable to allocate database connection state"); return st_FAILED; } mysql_options(conn, MYSQL_READ_DEFAULT_GROUP, "jabberd"); mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8"); /* connect with CLIENT_INTERACTIVE to get a (possibly) higher timeout value than default */ if(mysql_real_connect(conn, host, user, pass, dbname, atoi(port), NULL, CLIENT_INTERACTIVE) == NULL) { log_write(drv->st->log, LOG_ERR, "mysql: connection to database failed: %s", mysql_error(conn)); mysql_close(conn); return st_FAILED; } /* Set reconnect flag to 1 (set to 0 by default from mysql 5 on) */ conn->reconnect = 1; data = (drvdata_t) calloc(1, sizeof(struct drvdata_st)); data->conn = conn; if(config_get_one(drv->st->config, "storage.mysql.transactions", 0) != NULL) data->txn = 1; else log_write(drv->st->log, LOG_WARNING, "mysql: transactions disabled"); data->prefix = config_get_one(drv->st->config, "storage.mysql.prefix", 0); drv->private = (void *) data; drv->add_type = _st_mysql_add_type; drv->put = _st_mysql_put; drv->count = _st_mysql_count; drv->get = _st_mysql_get; drv->delete = _st_mysql_delete; drv->replace = _st_mysql_replace; drv->free = _st_mysql_free; return st_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_oracle.c�����������������������������������������������������0000664�0000000�0000000�00000104423�12614627753�0021404�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "storage.h" #include <string.h> #include <oci.h> /** internal structure, holds our data */ typedef struct OracleDriver { OCIEnv *ociEnvironment; OCIError *ociError; OCISvcCtx *ociService; OCIStmt *ociStatement; OCIDefine *ociDefine; OCIBind *ociBind; xht filters; char *prefix; } *OracleDriverPointer; #define BLOCKSIZE (1024) /** internal: do and return the math and ensure it gets realloc'd */ static int _st_oracle_realloc(void **oblocks, int len) { void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define ORACLE_SAFE(blocks, size, len) if((size) > len) len = _st_oracle_realloc((void**)&(blocks),(size)); int checkOCIError(st_driver_t drv, const char *szDoing, OCIError *m_ociError, sword nStatus) { text txtErrorBuffer[512]; ub4 nErrorCode; switch (nStatus) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: log_write(drv->st->log, LOG_ERR, "(%s) Error - OCI_SUCCESS_WITH_INFO\n", szDoing); break; case OCI_NEED_DATA: log_write(drv->st->log, LOG_ERR, "(%s) Error - OCI_NEED_DATA\n", szDoing); break; case OCI_NO_DATA: log_write(drv->st->log, LOG_ERR, "(%s) Error - OCI_NODATA\n", szDoing); break; case OCI_ERROR: OCIErrorGet(m_ociError, (ub4) 1, (text *) NULL, &nErrorCode, txtErrorBuffer, (ub4) sizeof(txtErrorBuffer), OCI_HTYPE_ERROR); log_write(drv->st->log, LOG_ERR, "(%s) Error - %s\n", szDoing, txtErrorBuffer); break; case OCI_INVALID_HANDLE: log_write(drv->st->log, LOG_ERR, "(%s) Error - OCI_INVALID_HANDLE\n", szDoing); break; case OCI_STILL_EXECUTING: log_write(drv->st->log, LOG_ERR, "(%s) Error - OCI_STILL_EXECUTE\n", szDoing); break; default: break; } return nStatus; } /* Return the number of occurrences of key in src */ int count_chars(char *src, char key) { int count = 0; while ( *src != '\0' ) { if ( *src == key ) count++; src++; } return count; } int oracle_escape_string(char *dest, int dest_length, const char *src, int src_length) { int result = 0; /* src is not null ended */ char *src_end = src + src_length; char *dest_end = dest + dest_length - 1; while (src < src_end) { if (dest < dest_end) { static const char ESCAPED_STR[] = "&"; static const char QUOTE_STR[] = "'"; if (strchr(ESCAPED_STR, *src) != NULL) { if (dest + 9 < dest_end) { /* '||'&'||' */ *dest++ = '\''; *dest++ = '|'; *dest++ = '|'; *dest++ = '\''; *dest++ = '&'; *dest++ = '\''; *dest++ = '|'; *dest++ = '|'; *dest++ = '\''; src++; } else { result = -1; break; } } else if (strchr(QUOTE_STR, *src) != NULL) { if (dest + 2 < dest_end) { *dest++ = '\''; *dest++ = *src; src++; } else { result = -1; break; } } else { *dest++ = *src++; } } else { result = -1; break; } } *dest = '\0'; return result; } static int oracle_ping(st_driver_t drv) { OracleDriverPointer odpOracleDriver = (OracleDriverPointer)drv->private; // Prepare the check statement int nResultCode = OCIStmtPrepare(odpOracleDriver->ociStatement, odpOracleDriver->ociError, "select sysdate from dual", (ub4) 24, OCI_NTV_SYNTAX, OCI_DEFAULT); // This is the real check nResultCode = OCIStmtExecute(odpOracleDriver->ociService, odpOracleDriver->ociStatement, odpOracleDriver->ociError, (ub4) 0, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DESCRIBE_ONLY ); // If there was an error... if (nResultCode != 0) { char szErrorBuffer[250]; char *svHost, *svUser, *svPass; char *svPort, *svSid, *oracle_server_host = NULL; static char* oracle_server_parameters = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=\"%s\")(PORT=\"%s\"))(CONNECT_DATA=(SID=\"%s\")))"; int _len = 0; OCIErrorGet((dvoid *)odpOracleDriver->ociError, (ub4) 1, (text *) NULL, &nResultCode, szErrorBuffer, (ub4) sizeof(szErrorBuffer), OCI_HTYPE_ERROR); log_write(drv->st->log, LOG_ERR, "storage_oracle.c (oracle_ping): %s", szErrorBuffer); // Obtain user configuration svHost = config_get_one(drv->st->config, "storage.oracle.host", 0); svUser = config_get_one(drv->st->config, "storage.oracle.user", 0); svPass = config_get_one(drv->st->config, "storage.oracle.pass", 0); svPort = config_get_one(drv->st->config, "storage.oracle.port", 0); svSid = config_get_one(drv->st->config, "storage.oracle.dbname", 0); ORACLE_SAFE( oracle_server_host, strlen(svHost) + strlen(svPort) + strlen(svSid) + strlen(oracle_server_parameters), _len ); sprintf( oracle_server_host, oracle_server_parameters, svHost, svPort, svSid ); // Logon to the database nResultCode = OCILogon((dvoid *)odpOracleDriver->ociEnvironment, (dvoid *)odpOracleDriver->ociError, &(odpOracleDriver->ociService), svUser, strlen(svUser), svPass, strlen(svPass), oracle_server_host, strlen(oracle_server_host)); if (nResultCode != 0) { OCIErrorGet((dvoid *)odpOracleDriver->ociError, (ub4) 1, (text *) NULL, &nResultCode, szErrorBuffer, (ub4) sizeof(szErrorBuffer), OCI_HTYPE_ERROR); log_write(drv->st->log, LOG_ERR, "storage_oracle.c (oracle_ping): %s", szErrorBuffer); } free(oracle_server_host); } return nResultCode; } static void _st_oracle_convert_filter_recursive(st_filter_t f, const char **buf, int *buflen, int *nbuf) { st_filter_t scan; switch(f->type) { case st_filter_type_PAIR: ORACLE_SAFE((*buf), *buflen + 12, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( \"%s\" = \'%s\' ) ", f->key, f->val); break; case st_filter_type_AND: ORACLE_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_oracle_convert_filter_recursive(scan, buf, buflen, nbuf); if(scan->next != NULL) { ORACLE_SAFE((*buf), *buflen + 4, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "AND "); } } ORACLE_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_OR: ORACLE_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_oracle_convert_filter_recursive(scan, buf, buflen, nbuf); if(scan->next != NULL) { ORACLE_SAFE((*buf), *buflen + 3, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "OR "); } } ORACLE_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_NOT: ORACLE_SAFE((*buf), *buflen + 6, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( NOT "); _st_oracle_convert_filter_recursive(f->sub, buf, buflen, nbuf); ORACLE_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; } } static char *_st_oracle_convert_filter(st_driver_t drv, const char *owner, const char *filter) { OracleDriverPointer data = (OracleDriverPointer) drv->private; char *buf = NULL, *sbuf = NULL, *cfilter; int buflen = 0, nbuf = 0, fbuf; st_filter_t f; ORACLE_SAFE(buf, 24 + strlen(owner), buflen); nbuf = sprintf(buf, "\"collection-owner\" = '%s'", owner); sbuf = xhash_get(data->filters, filter); if(sbuf != NULL) { ORACLE_SAFE(buf, buflen + strlen(sbuf) + 7, buflen); nbuf += sprintf(&buf[nbuf], " AND %s", sbuf); return buf; } cfilter = pstrdup(xhash_pool(data->filters), filter); f = storage_filter(filter); if(f == NULL) { return buf; } ORACLE_SAFE(buf, buflen + 5, buflen); nbuf += sprintf(&buf[nbuf], " AND "); fbuf = nbuf; _st_oracle_convert_filter_recursive(f, &buf, &buflen, &nbuf); xhash_put(data->filters, cfilter, pstrdup(xhash_pool(data->filters), &buf[fbuf])); pool_free(f->p); return buf; } static st_ret_t _st_oracle_add_type(st_driver_t drv, const char *type) { return st_SUCCESS; } static st_ret_t _st_oracle_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os) { static const char NAD_PREFIX[] = "NAD"; OracleDriverPointer data = (OracleDriverPointer) drv->private; char *left = NULL, *right = NULL; int lleft = 0, lright = 0, nleft, nright; os_object_t o; char *key = NULL, *cval = NULL; int vlen; dvoid *val = NULL; os_type_t ot; char *xml = NULL; int xlen; char tbuf[128]; int nResultCode = 0; if(os_count(os) == 0) { return st_SUCCESS; } if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } if(os_iter_first(os)) { do { ORACLE_SAFE(left, strlen(type) + 36, lleft); nleft = sprintf(left, "INSERT INTO \"%s\" ( \"collection-owner\"", type); ORACLE_SAFE(right, strlen(owner) + 15, lright); nright = sprintf(right, " ) VALUES ( '%s'", owner); o = os_iter_object(os); if(os_object_iter_first(o)) { do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(dvoid *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get(o, &key, &val, &ot); switch(ot) { case os_type_BOOLEAN: cval = ((int)val != 0) ? strdup("1") : strdup("0"); vlen = 1; break; case os_type_INTEGER: cval = (char *) malloc(sizeof(char) * 20); sprintf(cval, "%d", (int) val); vlen = strlen(cval); break; case os_type_STRING: /* Ensure that we have enough space for an escaped string. */ cval = (char *) malloc(sizeof(char) * ((strlen((char *) val) * 2 + count_chars((char *) val,'&') * 8) + 1)); vlen = oracle_escape_string(cval , (strlen((char *) val) * 2) + count_chars((char *) val,'&') * 8 + 1, (char *) val, strlen((char *) val)); break; /* !!! might not be a good idea to mark nads this way */ case os_type_NAD: nad_print((nad_t) val, 0, &xml, &xlen); /* Ensure that we have enough space for an escaped string. */ cval = (char *) malloc(sizeof(char) * ((xlen * 2 + count_chars((char *) val,'&') * 8) + 4)); vlen = oracle_escape_string(&cval[3],(xlen * 2 + count_chars((char *) val,'&') * 8) + 4, (char *) xml, xlen) + 3; strncpy(cval, "NAD", 3); break; } log_debug(ZONE, "key %s val %s", key, cval); ORACLE_SAFE(left, lleft + strlen(key) + 4, lleft); nleft += sprintf(&left[nleft], ", \"%s\"", key); ORACLE_SAFE(right, lright + strlen(cval) + 4, lright); nright += sprintf(&right[nright], ", '%s'", cval); free(cval); } while(os_object_iter_next(o)); ORACLE_SAFE(left, lleft + strlen(right) + 2, lleft); sprintf(&left[nleft], "%s )", right); log_debug(ZONE, "_st_oracle_put_guts: Generated SQL: %s", left); nResultCode = checkOCIError(drv, "oracle_put_guts: Prepare", data->ociError, OCIStmtPrepare(data->ociStatement, data->ociError, left, (ub4) strlen(left), OCI_NTV_SYNTAX, OCI_DEFAULT)); if (nResultCode != 0) { free(left); free(right); return st_FAILED; } nResultCode = checkOCIError(drv, "oracle_put_guts: Execute", data->ociError, OCIStmtExecute(data->ociService, data->ociStatement, data->ociError, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT | OCI_COMMIT_ON_SUCCESS)); if (nResultCode != 0) { free(left); free(right); return st_FAILED; } } } while(os_iter_next(os)); } free(left); free(right); return st_SUCCESS; } static st_ret_t _st_oracle_put(st_driver_t drv, const char *type, const char *owner, os_t os) { if( !owner ) { log_debug(ZONE,"_st_oracle_put: owner is null"); return st_FAILED; } if(os_count(os) == 0) { return st_SUCCESS; } if(oracle_ping(drv) != 0) { log_write(drv->st->log, LOG_ERR, "oracle: connection to database lost"); return st_FAILED; } if(_st_oracle_put_guts(drv, type, owner, os) != st_SUCCESS) { return st_FAILED; } return st_SUCCESS; } static st_ret_t _st_oracle_get(st_driver_t drv, const char *a_szType, const char *owner, const char *filter, os_t *os) { OracleDriverPointer data = (OracleDriverPointer) drv->private; os_object_t o; os_type_t ot; char szBuffer[128]; char *szWhereClause = NULL; char *szQuery = NULL; int nQueryLength = 0; int nResultCode = 0; int nNumberOfFields = 0; int nIndex = 0; if( !owner ) { log_debug(ZONE,"_st_oracle_get: owner is null"); return st_FAILED; } if(oracle_ping(drv) != 0) { log_write(drv->st->log, LOG_ERR, "_st_oracle_get: Connection to database lost!"); return st_FAILED; } if(data->prefix != NULL) { snprintf(szBuffer, sizeof(szBuffer), "%s%s", data->prefix, a_szType); a_szType = szBuffer; } szWhereClause = _st_oracle_convert_filter(drv, owner, filter); log_debug(ZONE, "_st_oracle_get: Generated Filter: %s", szWhereClause); ORACLE_SAFE(szQuery, strlen(a_szType) + strlen(szWhereClause) + 50, nQueryLength); sprintf(szQuery, "SELECT * FROM \"%s\" WHERE %s ORDER BY \"object-sequence\"", a_szType, szWhereClause); free(szWhereClause); log_debug(ZONE, "_st_oracle_get: Prepared SQL: %s", szQuery); nResultCode = checkOCIError(drv, "_st_oracle_get: Prepare Statement", data->ociError, OCIStmtPrepare(data->ociStatement, data->ociError, szQuery, (ub4)strlen(szQuery), OCI_NTV_SYNTAX, OCI_DEFAULT)); if (nResultCode != 0) { free(szQuery); return st_FAILED; } nResultCode = checkOCIError(drv, "_st_oracle_get: Statement Describe", data->ociError, OCIStmtExecute(data->ociService, data->ociStatement, data->ociError, (ub4)0, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DESCRIBE_ONLY)); if (nResultCode != 0) { free(szQuery); return st_FAILED; } free(szQuery); nResultCode = OCI_SUCCESS; checkOCIError(drv, "_st_oracle_get: Get Field Count", data->ociError, OCIAttrGet(data->ociStatement, OCI_HTYPE_STMT, (dvoid *)&nNumberOfFields, (ub4 *)NULL, OCI_ATTR_PARAM_COUNT, data->ociError)); if (nNumberOfFields == 0) { return st_NOTFOUND; } /* * TODO: Handle memory better. * The DDL for the "vcard" table has 21 fields. The following implementation allocates 82K for 21 fields. */ OCIDefine *arrFields[nNumberOfFields]; char arrszFieldData[nNumberOfFields][4001]; /* Size each field for the maximum VARCHAR2 size + terminating null */ char arrszFieldName[nNumberOfFields][255]; ub2 arrnFieldType[nNumberOfFields]; sb2 arrnFieldIndicator[nNumberOfFields]; ub2 arrnFieldSize[nNumberOfFields]; char *svFieldName; int nNameSize; int nIntValue; nad_t nad; ub2 dummy[1]; for (nIndex = 0; nIndex < nNumberOfFields; nIndex++) { arrFields[nIndex] = NULL; checkOCIError(drv, "_st_oracle_get: Get Parameter", data->ociError, OCIParamGet(data->ociStatement, OCI_HTYPE_STMT, data->ociError, (dvoid **) &arrFields[nIndex], (ub4) (nIndex + 1))); checkOCIError(drv, "_st_oracle_get: Get Field Name", data->ociError, OCIAttrGet(arrFields[nIndex], OCI_DTYPE_PARAM, (dvoid *) &svFieldName, &nNameSize, OCI_ATTR_NAME, data->ociError)); strncpy(arrszFieldName[nIndex], svFieldName, nNameSize); arrszFieldName[nIndex][nNameSize] = '\0'; arrnFieldType[nIndex] = 0; checkOCIError(drv, "_st_oracle_get: Get Field Type", data->ociError, OCIAttrGet(arrFields[nIndex], OCI_DTYPE_PARAM, (dvoid *) &arrnFieldType[nIndex], (ub4 *) NULL, (ub4) OCI_ATTR_DATA_TYPE, data->ociError)); checkOCIError(drv, "_st_oracle_get: Get Field Size", data->ociError, OCIAttrGet(arrFields[nIndex], OCI_DTYPE_PARAM, (dvoid *) &dummy, (ub4 *) NULL, (ub4) OCI_ATTR_DATA_SIZE, data->ociError)); arrnFieldSize[nIndex] = dummy[0]; log_debug(ZONE, "Field %s of Size %d", arrszFieldName[nIndex], arrnFieldSize[nIndex]); if (arrnFieldSize[nIndex] > 4000 || arrnFieldSize[nIndex] < 1) { arrnFieldSize[nIndex] = 4000; } checkOCIError(drv, "_st_oracle_get: Define String", data->ociError, OCIDefineByPos(data->ociStatement, &arrFields[nIndex], data->ociError, (nIndex + 1), (dvoid *)&arrszFieldData[nIndex], 4000, SQLT_STR, &arrnFieldIndicator[nIndex], (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT)); } nResultCode = OCIStmtExecute(data->ociService, data->ociStatement, data->ociError, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT); if (nResultCode == OCI_SUCCESS || nResultCode == OCI_SUCCESS_WITH_INFO) { for (nIndex = 0; nIndex < nNumberOfFields; nIndex++) { if (arrnFieldIndicator[nIndex] == -1) { arrszFieldData[nIndex][0] = '\0'; } } } else if (nResultCode != OCI_NO_DATA) { checkOCIError(drv, "_st_oracle_get: Execute Statement", data->ociError, nResultCode); return st_FAILED; } if (nResultCode == OCI_NO_DATA) { return st_NOTFOUND; } *os = os_new(); while (nResultCode != OCI_NO_DATA) { o = os_object_new(*os); for (nIndex = 0; nIndex < nNumberOfFields; nIndex++) { if(strcmp(arrszFieldName[nIndex], "collection-owner") == 0) { continue; } if (arrszFieldData[nIndex][0] == '\0') { continue; } switch(arrnFieldType[nIndex]) { case SQLT_CHR: /* VARCHAR2, VARCHAR, CHAR_VARYING, CHARACTER_VARYING, NVARCHAR2, * NCHAR_VARYING, NATIONAL_CHAR_VARYING, or NATIONAL_CHARACTER_VARYING field. */ if (arrnFieldSize[nIndex] > 2) { log_debug(ZONE, "Field %s is Field Type SQLT_CHR of Size %d, setting os_type_STRING", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_STRING; } else { log_debug(ZONE, "Field %s is Field Type SQLT_CHR of Size %d, setting os_type_BOOLEAN", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_BOOLEAN; } break; case SQLT_AFC: /* CHAR, CHARACTER, NATIONAL_CHAR, NATIONAL_CHARACTER, or NCHAR field. */ if (arrnFieldSize[nIndex] > 2) { log_debug(ZONE, "Field %s is Field Type SQLT_AFC of Size %d, setting os_type_STRING", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_STRING; } else { log_debug(ZONE, "Field %s is Field Type SQLT_AFC of Size %d, setting os_type_BOOLEAN", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_BOOLEAN; } break; case SQLT_NUM: /* INT, REAL, NUMERIC, DOUBLE_PRECISION, SMALLINT, FLOAT, DECIMAL, NUMBER, or INTEGER field. */ log_debug(ZONE, "Field %s is Field Type SQLT_NUM of Size %d", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_INTEGER; break; case SQLT_CLOB: /* CLOB for binary photo */ log_debug(ZONE, "Field %s is Field Type SQLT_CLOB of Size %d", arrszFieldName[nIndex], arrnFieldSize[nIndex]); ot = os_type_STRING; break; default: log_debug(ZONE, "Unknown field type %d, for column %s ignoring it", arrnFieldType[nIndex], arrszFieldName[nIndex]); continue; } switch(ot) { case os_type_BOOLEAN: nIntValue = (arrszFieldData[nIndex][0] == '0') ? 0 : 1; os_object_put(o, arrszFieldName[nIndex], &nIntValue, ot); break; case os_type_INTEGER: nIntValue = atoi(arrszFieldData[nIndex]); os_object_put(o, arrszFieldName[nIndex], &nIntValue, ot); break; case os_type_STRING: os_object_put(o, arrszFieldName[nIndex], arrszFieldData[nIndex], os_type_STRING); break; case os_type_NAD: case os_type_UNKNOWN: break; } } log_debug(ZONE, "Get Next Row."); nResultCode = OCIStmtFetch2(data->ociStatement, data->ociError, 1, OCI_DEFAULT, 0, OCI_DEFAULT); if (nResultCode == OCI_SUCCESS || nResultCode == OCI_SUCCESS_WITH_INFO) { for (nIndex = 0; nIndex < nNumberOfFields; nIndex++) { if (arrnFieldIndicator[nIndex] == -1) { arrszFieldData[nIndex][0] = '\0'; } } } else if (nResultCode != OCI_NO_DATA) { checkOCIError(drv, "_st_oracle_get: Fetch Next Row", data->ociError, nResultCode); // If we get a database error exit the while loop. This probably should return st_FAILED here. break; } } return st_SUCCESS; } static int _st_oracle_count( st_driver_t drv, const char *a_szType, const char *owner, const char *filter, int *count ) { OracleDriverPointer data = (OracleDriverPointer) drv->private; const char *szStmtTemplate = "SELECT COUNT(*) FROM \"%s\" WHERE %s"; char *szQuery = NULL; char szBuffer[128]; char *szWhereClause = NULL; int nResultCode = 0; int nQueryLength = 0; if( !owner ) { log_debug(ZONE,"_st_oracle_count: owner is null"); return st_FAILED; } if(oracle_ping(drv) != 0) { log_write(drv->st->log, LOG_ERR, "_st_oracle_count: Connection to database lost!"); return st_FAILED; } if(data->prefix != NULL) { snprintf(szBuffer, sizeof(szBuffer), "%s%s", data->prefix, a_szType); a_szType = szBuffer; } szWhereClause = _st_oracle_convert_filter(drv, owner, filter); log_debug(ZONE, "_st_oracle_count: Generated Filter: %s", szWhereClause); ORACLE_SAFE(szQuery, strlen(a_szType) + strlen(szWhereClause) + strlen(szStmtTemplate), nQueryLength); sprintf(szQuery, szStmtTemplate, a_szType, szWhereClause); free(szWhereClause); nResultCode = checkOCIError(drv, "_st_oracle_count: Prepare Statement", data->ociError, OCIStmtPrepare(data->ociStatement, data->ociError, szQuery, (ub4)strlen(szQuery), OCI_NTV_SYNTAX, OCI_DEFAULT)); if (nResultCode != 0) { free(szQuery); return st_FAILED; } nResultCode = checkOCIError(drv, "_st_oracle_count: Define Pos", data->ociError, OCIDefineByPos( data->ociStatement, &data->ociDefine, data->ociError, 1, count, sizeof(int), SQLT_INT, 0, 0, 0, OCI_DEFAULT ) ); if (nResultCode != 0) { free(szQuery); return st_FAILED; } nResultCode = checkOCIError(drv, "_st_oracle_count: Statement Execute", data->ociError, OCIStmtExecute(data->ociService, data->ociStatement, data->ociError, (ub4)0, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_STMT_SCROLLABLE_READONLY)); if (nResultCode != 0) { free(szQuery); return st_FAILED; } OCIStmtFetch2( data->ociStatement, data->ociError, 1, OCI_FETCH_FIRST, 0, OCI_DEFAULT); free(szQuery); return st_SUCCESS; } static st_ret_t _st_oracle_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { OracleDriverPointer data = (OracleDriverPointer) drv->private; char *cond, *buf = NULL; int buflen = 0; int nResultCode = 0; char tbuf[128]; if(oracle_ping(drv) != 0) { log_write(drv->st->log, LOG_ERR, "oracle: Connection to database lost"); return st_FAILED; } if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_oracle_convert_filter(drv, owner, filter); log_debug(ZONE, "oracle: Generated filter: %s", cond); ORACLE_SAFE(buf, strlen(type) + strlen(cond) + 19, buflen); sprintf(buf, "DELETE FROM \"%s\" WHERE %s", type, cond); free(cond); log_debug(ZONE, "_st_oracle_delete: Prepared SQL: %s", buf); nResultCode = checkOCIError(drv, "_st_oracle_delete: Prepare", data->ociError, OCIStmtPrepare(data->ociStatement, data->ociError, buf, (ub4) strlen(buf), OCI_NTV_SYNTAX, OCI_DEFAULT)); if (nResultCode != 0) { free(buf); return st_FAILED; } log_debug(ZONE, "_st_oracle_delete: Executing Delete."); nResultCode = checkOCIError(drv, "_st_oracle_delete: Execute", data->ociError, OCIStmtExecute(data->ociService, data->ociStatement, data->ociError, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT | OCI_COMMIT_ON_SUCCESS)); free(buf); log_debug(ZONE, "Result query: %d",nResultCode); if(nResultCode != 0) { return st_FAILED; } return st_SUCCESS; } static st_ret_t _st_oracle_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { if(oracle_ping(drv) != 0) { log_write(drv->st->log, LOG_ERR, "oracle: connection to database lost"); return st_FAILED; } if(_st_oracle_delete(drv, type, owner, filter) == st_FAILED) { return st_FAILED; } if(_st_oracle_put_guts(drv, type, owner, os) == st_FAILED) { return st_FAILED; } return st_SUCCESS; } static void _st_oracle_free(st_driver_t drv) { OracleDriverPointer data = (OracleDriverPointer) drv->private; OCILogoff(data->ociService, data->ociError); OCIHandleFree((dvoid *) data->ociStatement, OCI_HTYPE_STMT); OCIHandleFree((dvoid *) data->ociService, OCI_HTYPE_SVCCTX); OCIHandleFree((dvoid *) data->ociError, OCI_HTYPE_ERROR); OCIHandleFree((dvoid *) data->ociEnvironment, OCI_HTYPE_ENV); xhash_free(data->filters); free(data->prefix); free(data); } st_ret_t st_init(st_driver_t drv) { int nResultCode; char *svHost, *svUser, *svPass; char *svPort, *svSid, *oracle_server_host = NULL; OCIEnv *ociEnvironment; OCIError *ociError; OCISvcCtx *ociService; OCIStmt *ociStatement; static char* oracle_server_parameters = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=\"%s\")(PORT=\"%s\"))(CONNECT_DATA=(SID=\"%s\")))"; int _len = 0; OracleDriverPointer data; svHost = config_get_one(drv->st->config, "storage.oracle.host", 0); svUser = config_get_one(drv->st->config, "storage.oracle.user", 0); svPass = config_get_one(drv->st->config, "storage.oracle.pass", 0); svPort = config_get_one(drv->st->config, "storage.oracle.port", 0); svSid = config_get_one(drv->st->config, "storage.oracle.dbname", 0); if(svHost == NULL || svUser == NULL || svPass == NULL || svPort == NULL || svSid == NULL) { log_write(drv->st->log, LOG_ERR, "(st_oracle_init: ) Invalid driver config from XML file."); return st_FAILED; } ORACLE_SAFE( oracle_server_host, strlen(svHost) + strlen(svPort) + strlen(svSid) + strlen(oracle_server_parameters), _len ); sprintf( oracle_server_host, oracle_server_parameters, svHost, svPort, svSid ); nResultCode = OCIEnvCreate( (OCIEnv**)&ociEnvironment, OCI_DEFAULT, (dvoid*)0, 0, 0, 0, (size_t)0, (dvoid **)0 ); if (nResultCode != 0) { log_write(drv->st->log, LOG_ERR, "(st_oracle_init: ) Could not Initialize OCI Environment (%d)", nResultCode); return st_FAILED; } /* Initialize handles */ nResultCode = OCIHandleAlloc((dvoid *) ociEnvironment, (dvoid **) &ociError, OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0); if (nResultCode != 0) { log_write(drv->st->log, LOG_ERR, "(st_oracle_init: ) Could not create OCI Error object (%d)" , nResultCode); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return st_FAILED; } nResultCode = checkOCIError(drv, "st_oracle_init: Allocate Service", ociError, OCIHandleAlloc((dvoid *) ociEnvironment, (dvoid **)&ociService, OCI_HTYPE_SVCCTX, (size_t)NULL, (dvoid **)NULL)); if (nResultCode != 0) { nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return st_FAILED; } /* Connect to database server */ nResultCode = checkOCIError(drv, "st_oracle_init: Connect to Server", ociError, OCILogon(ociEnvironment, ociError, &ociService, svUser, strlen(svUser), svPass, strlen(svPass), oracle_server_host, strlen(oracle_server_host))); if (nResultCode != 0) { nResultCode = OCIHandleFree((dvoid *) ociService, OCI_HTYPE_SVCCTX); nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return st_FAILED; } /* Allocate and prepare SQL statement */ nResultCode = checkOCIError(drv, "st_oracle_init: Allocate Statement", ociError, OCIHandleAlloc((dvoid *)ociEnvironment, (dvoid **)&ociStatement, OCI_HTYPE_STMT, (size_t)NULL, (dvoid **)NULL)); if (nResultCode != 0) { nResultCode = OCILogoff(ociService, ociError); nResultCode = OCIHandleFree((dvoid *) ociService, OCI_HTYPE_SVCCTX); nResultCode = OCIHandleFree((dvoid *) ociError, OCI_HTYPE_ERROR); nResultCode = OCIHandleFree((dvoid *) ociEnvironment, OCI_HTYPE_ENV); return st_FAILED; } free(oracle_server_host); data = (OracleDriverPointer) calloc(1, sizeof(struct OracleDriver)); data->ociEnvironment = ociEnvironment; data->ociError = ociError; data->ociService = ociService; data->ociStatement = ociStatement; data->ociDefine = NULL; data->ociBind = NULL; data->filters = xhash_new(17); data->prefix = config_get_one(drv->st->config, "storage.oracle.prefix", 0); drv->private = (void *) data; drv->add_type = _st_oracle_add_type; drv->put = _st_oracle_put; drv->count = _st_oracle_count; drv->get = _st_oracle_get; drv->delete = _st_oracle_delete; drv->replace = _st_oracle_replace; drv->free = _st_oracle_free; return st_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_pgsql.c������������������������������������������������������0000664�0000000�0000000�00000054120�12614627753�0021263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file sm/storage_pgsql.c * @brief postgresql storage module * @author Robert Norris * $Date: 2005/06/02 04:48:25 $ * $Revision: 1.25 $ */ #include "storage.h" #include <libpq-fe.h> /** internal structure, holds our data */ typedef struct drvdata_st { PGconn *conn; const char *prefix; int txn; } *drvdata_t; #define FALLBACK_BLOCKSIZE (4096) /** internal: do and return the math and ensure it gets realloc'd */ static size_t _st_pgsql_realloc(char **oblocks, size_t len) { void *nblocks; size_t nlen; static size_t block_size = 0; if (block_size == 0) { #ifdef HAVE_GETPAGESIZE block_size = getpagesize(); #elif defined(_SC_PAGESIZE) block_size = sysconf(_SC_PAGESIZE); #elif defined(_SC_PAGE_SIZE) block_size = sysconf(_SC_PAGE_SIZE); #else block_size = FALLBACK_BLOCKSIZE; #endif } /* round up to standard block sizes */ nlen = (((len-1)/block_size)+1)*block_size; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define PGSQL_SAFE(blocks, size, len) if((size) >= len) len = _st_pgsql_realloc(&(blocks),(size + 1)); static void _st_pgsql_convert_filter_recursive(st_driver_t drv, st_filter_t f, char **buf, unsigned int *buflen, unsigned int *nbuf) { st_filter_t scan; int vlen; char *cval; switch(f->type) { case st_filter_type_PAIR: /* do sql escaping for apostrophes */ cval = (char *) malloc(sizeof(char) * ((strlen(f->val) * 2) + 1)); vlen = PQescapeString(cval, f->val, strlen(f->val)); PGSQL_SAFE((*buf), *buflen + 12 + vlen - strlen(f->val), *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( \"%s\" = \'%s\' ) ", f->key, f->val); free(cval); break; case st_filter_type_AND: PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_pgsql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { PGSQL_SAFE((*buf), *buflen + 4, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "AND "); } } PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_OR: PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_pgsql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { PGSQL_SAFE((*buf), *buflen + 3, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "OR "); } } PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_NOT: PGSQL_SAFE((*buf), *buflen + 6, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( NOT "); _st_pgsql_convert_filter_recursive(drv, f->sub, buf, buflen, nbuf); PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; } } static char *_st_pgsql_convert_filter(st_driver_t drv, const char *owner, const char *filter) { /* drvdata_t data = (drvdata_t) drv->private;*/ char *buf = NULL; unsigned int buflen = 0, nbuf = 0; st_filter_t f; PGSQL_SAFE(buf, 24 + strlen(owner), buflen); nbuf = sprintf(buf, "\"collection-owner\" = '%s'", owner); f = storage_filter(filter); if(f == NULL) return buf; PGSQL_SAFE(buf, buflen + 5, buflen); nbuf += sprintf(&buf[nbuf], " AND "); _st_pgsql_convert_filter_recursive(drv, f, &buf, &buflen, &nbuf); pool_free(f->p); return buf; } static st_ret_t _st_pgsql_add_type(st_driver_t drv, const char *type) { return st_SUCCESS; } static st_ret_t _st_pgsql_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; char *left = NULL, *right = NULL; int lleft = 0, lright = 0, nleft, nright; os_object_t o; char *key, *cval = NULL; void *val; os_type_t ot; const char *xml; int xlen; PGresult *res; char tbuf[128]; if(os_count(os) == 0) return st_SUCCESS; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } if(os_iter_first(os)) do { PGSQL_SAFE(left, strlen(type) + 55, lleft); nleft = sprintf(left, "INSERT INTO \"%s\" ( \"collection-owner\", \"object-sequence\"", type); PGSQL_SAFE(right, strlen(owner) + 43, lright); nright = sprintf(right, " ) VALUES ( '%s', nextval('object-sequence')", owner); o = os_iter_object(os); if(os_object_iter_first(o)) do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(void *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get(o, &key, &val, &ot); switch(ot) { case os_type_BOOLEAN: cval = ((int)val != 0) ? strdup("t") : strdup("f"); break; case os_type_INTEGER: cval = (char *) malloc(sizeof(char) * 20); sprintf(cval, "%d", (int)val); break; case os_type_STRING: cval = (char *) malloc(sizeof(char) * ((strlen((char *) val) * 2) + 1)); PQescapeString(cval, (char *) val, strlen((char *) val)); break; case os_type_NAD: nad_print((nad_t) val, 0, &xml, &xlen); cval = (char *) malloc(sizeof(char) * ((xlen * 2) + 4)); PQescapeString(&cval[3], xml, xlen); strncpy(cval, "NAD", 3); break; case os_type_UNKNOWN: break; } log_debug(ZONE, "key %s val %s", key, cval); PGSQL_SAFE(left, lleft + strlen(key) + 4, lleft); nleft += sprintf(&left[nleft], ", \"%s\"", key); PGSQL_SAFE(right, lright + strlen(cval) + 4, lright); nright += sprintf(&right[nright], ", '%s'", cval); free(cval); } while(os_object_iter_next(o)); PGSQL_SAFE(left, lleft + strlen(right) + 3, lleft); sprintf(&left[nleft], "%s );", right); log_debug(ZONE, "prepared sql: %s", left); res = PQexec(data->conn, left); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, left); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql insert failed: %s", PQresultErrorMessage(res)); free(left); free(right); PQclear(res); return st_FAILED; } PQclear(res); } while(os_iter_next(os)); free(left); free(right); return st_SUCCESS; } static st_ret_t _st_pgsql_put(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; PGresult *res; if(os_count(os) == 0) return st_SUCCESS; if(data->txn) { res = PQexec(data->conn, "BEGIN;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "BEGIN;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction begin failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } PQclear(res); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction setup failed: %s", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } PQclear(res); } if(_st_pgsql_put_guts(drv, type, owner, os) != st_SUCCESS) { if(data->txn) PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } if(data->txn) { res = PQexec(data->conn, "COMMIT;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "COMMIT;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction commit failed: %s", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } PQclear(res); } return st_SUCCESS; } static st_ret_t _st_pgsql_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; PGresult *res; int ntuples, nfields, i, j; os_object_t o; char *fname, *val; os_type_t ot; int ival; char tbuf[128]; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_pgsql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); PGSQL_SAFE(buf, strlen(type) + strlen(cond) + 51, buflen); sprintf(buf, "SELECT * FROM \"%s\" WHERE %s ORDER BY \"object-sequence\";", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); res = PQexec(data->conn, buf); if(PQresultStatus(res) != PGRES_TUPLES_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, buf); } free(buf); if(PQresultStatus(res) != PGRES_TUPLES_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql select failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } ntuples = PQntuples(res); if(ntuples == 0) { PQclear(res); return st_NOTFOUND; } log_debug(ZONE, "%d tuples returned", ntuples); nfields = PQnfields(res); if(nfields == 0) { log_debug(ZONE, "weird, tuples were returned but no fields *shrug*"); PQclear(res); return st_NOTFOUND; } *os = os_new(); for(i = 0; i < ntuples; i++) { o = os_object_new(*os); for(j = 0; j < nfields; j++) { fname = PQfname(res, j); if(strcmp(fname, "collection-owner") == 0) continue; switch(PQftype(res, j)) { case 16: /* boolean */ ot = os_type_BOOLEAN; break; case 23: /* integer */ ot = os_type_INTEGER; break; case 25: /* text */ ot = os_type_STRING; break; default: log_debug(ZONE, "unknown oid %d, ignoring it", PQfname(res, j)); continue; } if(PQgetisnull(res, i, j)) continue; val = PQgetvalue(res, i, j); switch(ot) { case os_type_BOOLEAN: ival = (val[0] == 't') ? 1 : 0; os_object_put(o, fname, &ival, ot); break; case os_type_INTEGER: ival = atoi(val); os_object_put(o, fname, &ival, ot); break; case os_type_STRING: os_object_put(o, fname, val, os_type_STRING); break; case os_type_NAD: case os_type_UNKNOWN: break; } } } PQclear(res); return st_SUCCESS; } static st_ret_t _st_pgsql_count(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; PGresult *res; int ntuples, nfields; char tbuf[128]; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_pgsql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); PGSQL_SAFE(buf, strlen(type) + strlen(cond) + 31, buflen); sprintf(buf, "SELECT COUNT(*) FROM \"%s\" WHERE %s", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); res = PQexec(data->conn, buf); if(PQresultStatus(res) != PGRES_TUPLES_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, buf); } free(buf); if(PQresultStatus(res) != PGRES_TUPLES_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql select failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } ntuples = PQntuples(res); if(ntuples == 0) { PQclear(res); return st_NOTFOUND; } log_debug(ZONE, "%d tuples returned", ntuples); nfields = PQnfields(res); if(nfields == 0) { log_debug(ZONE, "weird, tuples were returned but no fields *shrug*"); PQclear(res); return st_NOTFOUND; } if(PQgetisnull(res, 0, 0) || PQftype(res, 0) != 20) return st_NOTFOUND; if (count!=NULL) *count = atoi(PQgetvalue(res, 0, 0)); PQclear(res); return st_SUCCESS; } static st_ret_t _st_pgsql_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; int buflen = 0; PGresult *res; char tbuf[128]; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_pgsql_convert_filter(drv, owner, filter); log_debug(ZONE, "generated filter: %s", cond); PGSQL_SAFE(buf, strlen(type) + strlen(cond) + 23, buflen); sprintf(buf, "DELETE FROM \"%s\" WHERE %s;", type, cond); free(cond); log_debug(ZONE, "prepared sql: %s", buf); res = PQexec(data->conn, buf); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, buf); } free(buf); if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql delete failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } PQclear(res); return st_SUCCESS; } static st_ret_t _st_pgsql_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { drvdata_t data = (drvdata_t) drv->private; PGresult *res; if(data->txn) { res = PQexec(data->conn, "BEGIN;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "BEGIN;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction begin failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } PQclear(res); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction setup failed: %s", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } PQclear(res); } if(_st_pgsql_delete(drv, type, owner, filter) == st_FAILED) { if(data->txn) PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } if(_st_pgsql_put_guts(drv, type, owner, os) == st_FAILED) { if(data->txn) PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } if(data->txn) { res = PQexec(data->conn, "COMMIT;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "COMMIT;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->log, LOG_ERR, "pgsql: sql transaction commit failed: %s", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED; } PQclear(res); } return st_SUCCESS; } static void _st_pgsql_free(st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; PQfinish(data->conn); free(data); } st_ret_t st_init(st_driver_t drv) { const char *host, *port, *dbname, *schema, *user, *pass, *conninfo; char sql[1024]; PGconn *conn; drvdata_t data; host = config_get_one(drv->st->config, "storage.pgsql.host", 0); port = config_get_one(drv->st->config, "storage.pgsql.port", 0); dbname = config_get_one(drv->st->config, "storage.pgsql.dbname", 0); schema = config_get_one(drv->st->config, "storage.pgsql.schema", 0); user = config_get_one(drv->st->config, "storage.pgsql.user", 0); pass = config_get_one(drv->st->config, "storage.pgsql.pass", 0); conninfo = config_get_one(drv->st->config, "storage.pgsql.conninfo",0); if(conninfo) { conn = PQconnectdb(conninfo); } else { conn = PQsetdbLogin(host, port, NULL, NULL, dbname, user, pass); } if(conn == NULL) { log_write(drv->st->log, LOG_ERR, "pgsql: unable to allocate database connection state"); return st_FAILED; } if(PQstatus(conn) != CONNECTION_OK) log_write(drv->st->log, LOG_ERR, "pgsql: connection to database failed: %s", PQerrorMessage(conn)); if (schema) { snprintf(sql, sizeof(sql), "SET search_path TO \"%s\"", schema); PQexec(conn, sql); } data = (drvdata_t) calloc(1, sizeof(struct drvdata_st)); data->conn = conn; if(config_get_one(drv->st->config, "storage.pgsql.transactions", 0) != NULL) data->txn = 1; else log_write(drv->st->log, LOG_WARNING, "pgsql: transactions disabled"); data->prefix = config_get_one(drv->st->config, "storage.pgsql.prefix", 0); drv->private = (void *) data; drv->add_type = _st_pgsql_add_type; drv->put = _st_pgsql_put; drv->count = _st_pgsql_count; drv->get = _st_pgsql_get; drv->delete = _st_pgsql_delete; drv->replace = _st_pgsql_replace; drv->free = _st_pgsql_free; return st_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/storage/storage_sqlite.c�����������������������������������������������������0000664�0000000�0000000�00000043235�12614627753�0021443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * Copyright (c) 2004 Christof Meerwald * * 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, MA02111-1307USA */ /* Released under the GPL by Chris Parker <parkerc@i-vsn.com>, IVSN * to the Jabberd project. */ /* Modified and updated for SQLite 3 by Christof Meerwald, * http://cmeerw.org */ #include "storage.h" #include <sqlite3.h> /** internal structure, holds our data */ typedef struct drvdata_st { sqlite3 *db; const char *prefix; int txn; } *drvdata_t; #define BLOCKSIZE (1024) /** internal: do and return the math and ensure it gets realloc'd */ static int _st_sqlite_realloc (void **oblocks, int len) { void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ while ((nblocks = realloc(*oblocks, nlen)) == NULL) sleep (1); *oblocks = nblocks; return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define SQLITE_SAFE(blocks, size, len) \ if((size) >= (len)) \ len = _st_sqlite_realloc((void**)&(blocks),(size) + 1); #define SQLITE_SAFE_CAT(blocks, size, len, s1) \ do { \ SQLITE_SAFE(blocks, size + sizeof (s1) - 1, len); \ memcpy (&blocks[size], s1, sizeof (s1)); \ size += sizeof (s1) - 1; \ } while (0) #define SQLITE_SAFE_CAT3(blocks, size, len, s1, s2, s3) \ do { \ const unsigned int l = strlen (s2); \ SQLITE_SAFE(blocks, size + sizeof (s1) + l + sizeof (s2) - 2, len); \ memcpy (&blocks[size], s1, sizeof (s1) - 1); \ memcpy (&blocks[size + sizeof (s1) - 1], s2, l); \ memcpy (&blocks[size + sizeof (s1) - 1 + l], s3, sizeof (s3)); \ size += sizeof (s1) + l + sizeof (s3) - 2; \ } while (0) static void _st_sqlite_convert_filter_recursive (st_filter_t f, char **buf, int *buflen, int *nbuf) { st_filter_t scan; switch (f->type) { case st_filter_type_PAIR: SQLITE_SAFE_CAT3 ((*buf), *nbuf, *buflen, "( \"", f->key, "\" = ? ) "); break; case st_filter_type_AND: SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( "); for (scan = f->sub; scan != NULL; scan = scan->next) { _st_sqlite_convert_filter_recursive (scan, buf, buflen, nbuf); if (scan->next != NULL) { SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "AND "); } } SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") "); return; case st_filter_type_OR: SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( "); for (scan = f->sub; scan != NULL; scan = scan->next) { _st_sqlite_convert_filter_recursive (scan, buf, buflen, nbuf); if (scan->next != NULL) { SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "OR "); } } SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") "); return; case st_filter_type_NOT: SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, "( NOT "); _st_sqlite_convert_filter_recursive(f->sub, buf, buflen, nbuf); SQLITE_SAFE_CAT ((*buf), *nbuf, *buflen, ") "); return; } } static char *_st_sqlite_convert_filter (st_driver_t drv, const char *owner, const char *filter) { char *buf = NULL; int buflen = 0, nbuf = 0; st_filter_t f; SQLITE_SAFE_CAT (buf, nbuf, buflen, "\"collection-owner\" = ?"); f = storage_filter (filter); if (f == NULL) { return buf; } SQLITE_SAFE_CAT (buf, nbuf, buflen, " AND "); _st_sqlite_convert_filter_recursive (f, &buf, &buflen, &nbuf); pool_free (f->p); return buf; } static void _st_sqlite_bind_filter_recursive (st_filter_t f, sqlite3_stmt *stmt, unsigned int bind_off) { st_filter_t scan; unsigned int i; switch (f->type) { case st_filter_type_PAIR: sqlite3_bind_text (stmt, bind_off, f->val, strlen (f->val), SQLITE_TRANSIENT); break; case st_filter_type_AND: for (scan = f->sub, i = 0; scan != NULL; scan = scan->next, ++i) { _st_sqlite_bind_filter_recursive (scan, stmt, bind_off + i); } return; case st_filter_type_OR: for (scan = f->sub, i = 0; scan != NULL; scan = scan->next, ++i) { _st_sqlite_bind_filter_recursive (scan, stmt, bind_off + i); } return; case st_filter_type_NOT: _st_sqlite_bind_filter_recursive(f->sub, stmt, bind_off); return; } } static void _st_sqlite_bind_filter (st_driver_t drv, const char *owner, const char *filter, sqlite3_stmt *stmt, unsigned int bind_off) { st_filter_t f; sqlite3_bind_text (stmt, bind_off, owner, strlen (owner), SQLITE_TRANSIENT); f = storage_filter (filter); if (f == NULL) { return; } _st_sqlite_bind_filter_recursive (f, stmt, bind_off + 1); pool_free (f->p); } static st_ret_t _st_sqlite_add_type (st_driver_t drv, const char *type) { return st_SUCCESS; } static st_ret_t _st_sqlite_put_guts (st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; char *left = NULL, *right = NULL; unsigned int lleft = 0, lright = 0; os_object_t o; char *key, *cval = NULL; void *val; os_type_t ot; const char *xml; int xlen; char tbuf[128]; int res; if (os_count (os) == 0) { return st_SUCCESS; } if (data->prefix != NULL) { snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type); type = tbuf; } if (os_iter_first (os)) { do { unsigned int i = 0; unsigned int nleft = 0, nright = 0; sqlite3_stmt *stmt; SQLITE_SAFE_CAT3 (left, nleft, lleft, "INSERT INTO \"", type, "\" ( \"collection-owner\""); SQLITE_SAFE_CAT (right, nright, lright, " ) VALUES ( ?"); o = os_iter_object (os); if (os_object_iter_first(o)) do { os_object_iter_get (o, &key, &val, &ot); log_debug (ZONE, "key %s val %s", key, cval); SQLITE_SAFE_CAT3 (left, nleft, lleft, ", \"", key, "\""); SQLITE_SAFE_CAT (right, nright, lright, ", ?"); } while (os_object_iter_next (o)); SQLITE_SAFE (left, nleft + nright, lleft); memcpy (&left[nleft], right, nright); nleft += nright; free (right); right = NULL; lright = 0; SQLITE_SAFE_CAT (left, nleft, lleft, " )"); log_debug (ZONE, "prepared sql: %s", left); res = sqlite3_prepare (data->db, left, strlen (left), &stmt, NULL); free (left); left = NULL; lleft = 0; if (res != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: sql insert failed: %s", sqlite3_errmsg (data->db)); return st_FAILED; } sqlite3_bind_text (stmt, 1, owner, strlen (owner), SQLITE_TRANSIENT); o = os_iter_object (os); if (os_object_iter_first(o)) do { /* For os_type_BOOLEAN and os_type_INTEGER, sizeof(int) bytes are stored in val, which might be less than sizeof(void *). Therefore, the difference is garbage unless cleared first. */ val = NULL; os_object_iter_get (o, &key, &val, &ot); switch(ot) { case os_type_BOOLEAN: sqlite3_bind_int (stmt, i + 2, ((int)val != 0) ? 1 : 0); break; case os_type_INTEGER: sqlite3_bind_int (stmt, i + 2, (int)val); break; case os_type_STRING: sqlite3_bind_text (stmt, i + 2, (const char *) val, strlen ((const char *) val), SQLITE_TRANSIENT); break; /* !!! might not be a good idea to mark nads this way */ case os_type_NAD: nad_print ((nad_t) val, 0, &xml, &xlen); cval = (char *) malloc(sizeof(char) * (xlen + 4)); memcpy (&cval[3], xml, xlen + 1); memcpy (cval, "NAD", 3); sqlite3_bind_text (stmt, i + 2, cval, xlen + 3, free); break; case os_type_UNKNOWN: default: log_write (drv->st->log, LOG_ERR, "sqlite: unknown value in query"); } i += 1; } while (os_object_iter_next (o)); res = sqlite3_step (stmt); if (res != SQLITE_DONE) { log_write (drv->st->log, LOG_ERR, "sqlite: sql insert failed: %s", sqlite3_errmsg (data->db)); sqlite3_finalize (stmt); return st_FAILED; } sqlite3_finalize (stmt); } while (os_iter_next (os)); } return st_SUCCESS; } static st_ret_t _st_sqlite_put (st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; int res; char *err_msg = NULL; if (os_count (os) == 0) { return st_SUCCESS; } if (data->txn) { res = sqlite3_exec (data->db, "BEGIN", NULL, NULL, &err_msg); if (res != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: sql transaction begin failed: %s", err_msg); sqlite3_free (err_msg); return st_FAILED; } } if (_st_sqlite_put_guts (drv, type, owner, os) != st_SUCCESS) { if (data->txn) { res = sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL); } return st_FAILED; } if (data->txn) { res = sqlite3_exec (data->db, "COMMIT", NULL, NULL, &err_msg); if (res != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: sql transaction commit failed: %s", err_msg); sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL); return st_FAILED; } } return st_SUCCESS; } static st_ret_t _st_sqlite_get (st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; unsigned int nbuf = 0; unsigned int buflen = 0; int i; unsigned int num_rows = 0; os_object_t o; const char *val; os_type_t ot; int ival; char tbuf[128]; sqlite3_stmt *stmt; int result; if (data->prefix != NULL) { snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_sqlite_convert_filter (drv, owner, filter); SQLITE_SAFE_CAT3 (buf, nbuf, buflen, "SELECT * FROM \"", type, "\" WHERE "); strcpy (&buf[nbuf], cond); strcpy (&buf[strlen(buf)], " ORDER BY \"object-sequence\""); free (cond); log_debug (ZONE, "prepared sql: %s", buf); result = sqlite3_prepare (data->db, buf, strlen (buf), &stmt, NULL); free (buf); if (result != SQLITE_OK) { return st_FAILED; } _st_sqlite_bind_filter (drv, owner, filter, stmt, 1); *os = os_new (); do { unsigned int num_cols; result = sqlite3_step (stmt); if (result != SQLITE_ROW) { continue; } o = os_object_new (*os); num_cols = sqlite3_data_count (stmt); for (i = 0; i < num_cols; i++) { const char *colname; int coltype; colname = sqlite3_column_name (stmt, i); if (strcmp (colname, "collection-owner") == 0) { continue; } coltype = sqlite3_column_type (stmt, i); if (coltype == SQLITE_NULL) { log_debug (ZONE, "coldata is NULL"); continue; } if (coltype == SQLITE_INTEGER) { if (!strcmp (sqlite3_column_decltype (stmt, i), "BOOL")) { ot = os_type_BOOLEAN; } else { ot = os_type_INTEGER; } ival = sqlite3_column_int (stmt, i); os_object_put (o, colname, &ival, ot); } else if (coltype == SQLITE3_TEXT) { ot = os_type_STRING; val = (const char*)sqlite3_column_text (stmt, i); os_object_put (o, colname, val, ot); } else { log_write (drv->st->log, LOG_NOTICE, "sqlite: unknown field: %s:%d", colname, coltype); } } num_rows++; } while (result == SQLITE_ROW); sqlite3_finalize (stmt); if (num_rows == 0) { os_free(*os); *os = NULL; return st_NOTFOUND; } return st_SUCCESS; } static st_ret_t _st_sqlite_count (st_driver_t drv, const char *type, const char *owner, const char *filter, int *count) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; unsigned int nbuf = 0; unsigned int buflen = 0; char tbuf[128]; int res, coltype; sqlite3_stmt *stmt; if (data->prefix != NULL) { snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_sqlite_convert_filter (drv, owner, filter); log_debug (ZONE, "generated filter: %s", cond); SQLITE_SAFE_CAT3 (buf, nbuf, buflen, "SELECT COUNT(*) FROM \"", type, "\" WHERE "); strcpy (&buf[nbuf], cond); free (cond); log_debug (ZONE, "prepared sql: %s", buf); res = sqlite3_prepare (data->db, buf, strlen (buf), &stmt, NULL); free (buf); if (res != SQLITE_OK) { return st_FAILED; } _st_sqlite_bind_filter (drv, owner, filter, stmt, 1); res = sqlite3_step (stmt); if (res != SQLITE_ROW) { log_write (drv->st->log, LOG_ERR, "sqlite: sql select failed: %s", sqlite3_errmsg (data->db)); sqlite3_finalize (stmt); return st_FAILED; } coltype = sqlite3_column_type (stmt, 0); if (coltype != SQLITE_INTEGER) { log_write (drv->st->log, LOG_ERR, "sqlite: weird, count() returned non integer value: %s", sqlite3_errmsg (data->db)); sqlite3_finalize (stmt); return st_FAILED; } *count = sqlite3_column_int (stmt, 0); sqlite3_finalize (stmt); return st_SUCCESS; } static st_ret_t _st_sqlite_delete (st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; unsigned int nbuf = 0; unsigned int buflen = 0; char tbuf[128]; int res; sqlite3_stmt *stmt; if (data->prefix != NULL) { snprintf (tbuf, sizeof (tbuf), "%s%s", data->prefix, type); type = tbuf; } cond = _st_sqlite_convert_filter (drv, owner, filter); log_debug (ZONE, "generated filter: %s", cond); SQLITE_SAFE_CAT3 (buf, nbuf, buflen, "DELETE FROM \"", type, "\" WHERE "); strcpy (&buf[nbuf], cond); free (cond); log_debug (ZONE, "prepared sql: %s", buf); res = sqlite3_prepare (data->db, buf, strlen (buf), &stmt, NULL); free (buf); if (res != SQLITE_OK) { return st_FAILED; } _st_sqlite_bind_filter (drv, owner, filter, stmt, 1); res = sqlite3_step (stmt); if (res != SQLITE_DONE) { log_write (drv->st->log, LOG_ERR, "sqlite: sql delete failed: %s", sqlite3_errmsg (data->db)); sqlite3_finalize (stmt); return st_FAILED; } sqlite3_finalize (stmt); return st_SUCCESS; } static st_ret_t _st_sqlite_replace (st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) { drvdata_t data = (drvdata_t) drv->private; int res; char *err_msg = NULL; if (data->txn) { res = sqlite3_exec (data->db, "BEGIN", NULL, NULL, &err_msg); if (res != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: sql transaction begin failed: %s", err_msg); sqlite3_free (err_msg); return st_FAILED; } } if (_st_sqlite_delete (drv, type, owner, filter) == st_FAILED) { if (data->txn) { sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL); } return st_FAILED; } if (_st_sqlite_put_guts (drv, type, owner, os) == st_FAILED) { if (data->txn) { sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL); } return st_FAILED; } if (data->txn) { res = sqlite3_exec (data->db, "COMMIT", NULL, NULL, &err_msg); if (res != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: sql transaction commit failed: %s", err_msg); sqlite3_exec (data->db, "ROLLBACK", NULL, NULL, NULL); return st_FAILED; } } return st_SUCCESS; } static void _st_sqlite_free (st_driver_t drv) { drvdata_t data = (drvdata_t) drv->private; sqlite3_close (data->db); free (data); } DLLEXPORT st_ret_t st_init(st_driver_t drv) { const char *dbname; sqlite3 *db; drvdata_t data; int ret; const char *busy_timeout; dbname = config_get_one (drv->st->config, "storage.sqlite.dbname", 0); if (dbname == NULL) { log_write (drv->st->log, LOG_ERR, "sqlite: invalid driver config"); return st_FAILED; } ret = sqlite3_open (dbname, &db); if (ret != SQLITE_OK) { log_write (drv->st->log, LOG_ERR, "sqlite: can't open database '%s'", dbname); return st_FAILED; } data = (drvdata_t) calloc (1, sizeof (struct drvdata_st)); data->db = db; if (config_get_one (drv->st->config, "storage.sqlite.transactions", 0) != NULL) { data->txn = 1; } else { log_write (drv->st->log, LOG_WARNING, "sqlite: transactions disabled"); } busy_timeout = config_get_one (drv->st->config, "storage.sqlite.busy-timeout", 0); if (busy_timeout != NULL) { sqlite3_busy_timeout (db, atoi (busy_timeout)); } data->prefix = config_get_one (drv->st->config, "storage.sqlite.prefix", 0); drv->private = (void *) data; drv->add_type = _st_sqlite_add_type; drv->put = _st_sqlite_put; drv->count = _st_sqlite_count; drv->get = _st_sqlite_get; drv->delete = _st_sqlite_delete; drv->replace = _st_sqlite_replace; drv->free = _st_sqlite_free; return st_SUCCESS; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015737�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/Makefile.am������������������������������������������������������������0000664�0000000�0000000�00000000475�12614627753�0020001�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet noinst_LTLIBRARIES = libsubst.la noinst_HEADERS = dirent.h getopt.h ip6_misc.h subst.h syslog.h libsubst_la_SOURCES = dirent.c getopt.c gettimeofday.c inet_aton.c inet_ntop.c inet_pton.c snprintf.c syslog.c strndup.c timegm.c libsubst_la_LIBADD = @LDFLAGS@ libsubst_la_LDFLAGS = -export-dynamic ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/dirent.c���������������������������������������������������������������0000664�0000000�0000000�00000006253�12614627753�0017376�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Implementation of POSIX directory browsing functions and types for Win32. Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) History: Created March 1997. Updated June 2003. Rights: See end of file. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_DIRENT_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_SYS_NDIR_H) #ifdef HAVE__FINDFIRST #include "dirent.h" #include <errno.h> #include <io.h> /* _findfirst and _findnext set errno iff they return -1 */ #include <stdlib.h> #include <string.h> #ifdef __cplusplus extern "C" { #endif struct DIR { long handle; /* -1 for failed rewind */ struct _finddata_t info; struct dirent result; /* d_name null iff first time */ char *name; /* null-terminated char string */ }; DIR *opendir(const char *name) { DIR *dir = 0; if(name && name[0]) { size_t base_length = strlen(name); const char *all = /* search pattern must end with suitable wildcard */ strchr("/\\", name[base_length - 1]) ? "*" : "/*"; if((dir = (DIR *) malloc(sizeof *dir)) != 0 && (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) { strcat(strcpy(dir->name, name), all); if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1) { dir->result.d_name = 0; } else /* rollback */ { free(dir->name); free(dir); dir = 0; } } else /* rollback */ { free(dir); dir = 0; errno = ENOMEM; } } else { errno = EINVAL; } return dir; } int closedir(DIR *dir) { int result = -1; if(dir) { if(dir->handle != -1) { result = _findclose(dir->handle); } free(dir->name); free(dir); } if(result == -1) /* map all errors to EBADF */ { errno = EBADF; } return result; } struct dirent *readdir(DIR *dir) { struct dirent *result = 0; if(dir && dir->handle != -1) { if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { result = &dir->result; result->d_name = dir->info.name; } } else { errno = EBADF; } return result; } void rewinddir(DIR *dir) { if(dir && dir->handle != -1) { _findclose(dir->handle); dir->handle = (long) _findfirst(dir->name, &dir->info); dir->result.d_name = 0; } else { errno = EBADF; } } #ifdef __cplusplus } #endif #endif #endif /* Copyright Kevlin Henney, 1997, 2003. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose is hereby granted without fee, provided that this copyright and permissions notice appear in all copies and derivatives. This software is supplied "as is" without express or implied warranty. But that said, if there are any problems please get in touch. */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/dirent.h���������������������������������������������������������������0000664�0000000�0000000�00000003136�12614627753�0017400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef DIRENT_INCLUDED #define DIRENT_INCLUDED #ifdef HAVE_CONFIG_H # include "config.h" #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #if !defined(HAVE_DIRENT_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_SYS_NDIR_H) #ifdef HAVE__FINDFIRST /* Declaration of POSIX directory browsing functions and types for Win32. Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) History: Created March 1997. Updated June 2003. Rights: See end of file. */ #ifdef __cplusplus extern "C" { #endif #include <direct.h> typedef struct DIR DIR; struct dirent { char *d_name; }; JABBERD2_API DIR *opendir(const char *); JABBERD2_API int closedir(DIR *); JABBERD2_API struct dirent *readdir(DIR *); JABBERD2_API void rewinddir(DIR *); /* Copyright Kevlin Henney, 1997, 2003. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose is hereby granted without fee, provided that this copyright and permissions notice appear in all copies and derivatives. This software is supplied "as is" without express or implied warranty. But that said, if there are any problems please get in touch. */ #ifdef __cplusplus } #endif #endif #endif #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/getopt.c���������������������������������������������������������������0000664�0000000�0000000�00000051160�12614627753�0017410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 Free Software Foundation, Inc. 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef HAVE_GETOPT #ifndef __STDC__ # ifndef const # define const # endif #endif #define __GNU_LIBRARY__ /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */ #ifndef _NO_PROTO #define _NO_PROTO #endif #include <stdio.h> #include <string.h> /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined(_WIN32) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include <stdlib.h> #endif /* GNU C library. */ /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ /* #define GETOPT_COMPAT */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = 0; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ #define BAD_OPTION '\0' int optopt = BAD_OPTION; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include <string.h> #define my_index strchr #define my_strlen strlen #else /* Avoid depending on library functions or files whose names are inconsistent. */ #if __STDC__ || defined(PROTO) extern char *getenv(const char *name); extern int strcmp(const char *s1, const char *s2); extern int strncmp(const char *s1, const char *s2, int n); static int my_strlen(const char *s); static char *my_index(const char *str, int chr); #else extern char *getenv(); #endif static int my_strlen(const char *str) { int n = 0; while (*str++) n++; return n; } static char *my_index(const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } #endif /* GNU C library. */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. To perform the swap, we first reverse the order of all elements. So all options now come before all non options, but they are in the wrong order. So we put back the options and non options in original order by reversing them again. For example: original input: a b c -x -y reverse all: -y -x c b a reverse options: -x -y c b a reverse non options: -x -y a b c */ #if __STDC__ || defined(PROTO) static void exchange(char **argv); #endif static void exchange(char **argv) { char *temp, **first, **last; /* Reverse all the elements [first_nonopt, optind) */ first = &argv[first_nonopt]; last = &argv[optind - 1]; while (first < last) { temp = *first; *first = *last; *last = temp; first++; last--; } /* Put back the options in order */ first = &argv[first_nonopt]; first_nonopt += (optind - last_nonopt); last = &argv[first_nonopt - 1]; while (first < last) { temp = *first; *first = *last; *last = temp; first++; last--; } /* Put back the non options in order */ first = &argv[first_nonopt]; last_nonopt = optind; last = &argv[last_nonopt - 1]; while (first < last) { temp = *first; *first = *last; *last = temp; first++; last--; } } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return BAD_OPTION after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return BAD_OPTION. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal(int argc, const char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) { int option_index; optarg = 0; /* Initialize the internal data when the first call is made. Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ if (optind == 0) { first_nonopt = last_nonopt = optind = 1; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (getenv("POSIXLY_CORRECT") != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; } if (nextchar == NULL || *nextchar == '\0') { if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Now skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) optind++; last_nonopt = optind; } /* Special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp(argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Start decoding its characters. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only)) #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ )) { const struct option *p; char *s = nextchar; int exact = 0; int ambig = 0; const struct option *pfound = NULL; int indfound = 0; while (*s && *s != '=') s++; /* Test all options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp(p->name, nextchar, s - nextchar)) { if (s - nextchar == my_strlen(p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf(stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optind]); nextchar += my_strlen(nextchar); optind++; return BAD_OPTION; } if (pfound != NULL) { option_index = indfound; optind++; if (*s) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = s + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], pfound->name); else /* +option or -option */ fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optind - 1][0], pfound->name); } nextchar += my_strlen(nextchar); return BAD_OPTION; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf(stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += my_strlen(nextchar); return optstring[0] == ':' ? ':' : BAD_OPTION; } } nextchar += my_strlen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ || my_index(optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf(stderr, "%s: unrecognized option `--%s'\n", argv[0], nextchar); else /* +option or -option */ fprintf(stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return BAD_OPTION; } } /* Look at and handle the next option-character. */ { char c = *nextchar++; char *temp = my_index(optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { #if 0 if (c < 040 || c >= 0177) fprintf(stderr, "%s: unrecognized option, character code 0%o\n", argv[0], c); else fprintf(stderr, "%s: unrecognized option `-%c'\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf(stderr, "%s: illegal option -- %c\n", argv[0], c); #endif } optopt = c; return BAD_OPTION; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = 0; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { #if 0 fprintf(stderr, "%s: option `-%c' requires an argument\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = BAD_OPTION; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt(int argc, const char *const *argv, const char *optstring) { return _getopt_internal(argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } int getopt_long(int argc, const char *const *argv, const char *options, const struct option long_options, int *opt_index) { return _getopt_internal(argc, argv, options, &long_options, opt_index, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main(int argc, const char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt(argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf("option %c\n", c); break; case 'a': printf("option a\n"); break; case 'b': printf("option b\n"); break; case 'c': printf("option c with value `%s'\n", optarg); break; case BAD_OPTION: break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } exit(0); } #endif /* TEST */ #endif /* HAVE_GETOPT */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/getopt.h���������������������������������������������������������������0000664�0000000�0000000�00000011320�12614627753�0017407�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ JABBERD2_API char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ JABBERD2_API int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ JABBERD2_API int opterr; /* Set to an option character which was unrecognized. */ JABBERD2_API int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if __STDC__ || defined(PROTO) #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ JABBERD2_API int getopt (int argc, const char *const *argv, const char *shortopts); #endif /* not __GNU_LIBRARY__ */ JABBERD2_API int getopt_long (int argc, const char *const *argv, const char *shortopts, const struct option *longopts, int *longind); JABBERD2_API int getopt_long_only (int argc, const char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ JABBERD2_API int _getopt_internal (int argc, const char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ JABBERD2_API int getopt (); JABBERD2_API int getopt_long (); JABBERD2_API int getopt_long_only (); JABBERD2_API int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/gettimeofday.c���������������������������������������������������������0000664�0000000�0000000�00000003705�12614627753�0020571�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * $PostgreSQL: /cvsroot/pgsql-server/src/port/gettimeofday.c,v 1.3 2003/11/29 19:52:13 pgsql Exp $ * * Copyright (c) 2003 SRA, Inc. * Copyright (c) 2003 SKC, Inc. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose, without fee, and without a * written agreement is hereby granted, provided that the above * copyright notice and this paragraph and the following two * paragraphs appear in all copies. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef HAVE_GETTIMEOFDAY #include "ac-stdint.h" #include <time.h> #include <stdio.h> #include <sys/types.h> #include <sys/timeb.h> #include <windows.h> #include "subst.h" /* FILETIME of Jan 1 1970 00:00:00. */ static const unsigned __int64 epoch = 116444736000000000L; /* * timezone information is stored outside the kernel so tzp isn't used anymore. */ int gettimeofday(struct timeval * tp, struct timezone * tzp) { FILETIME file_time; SYSTEMTIME system_time; ULARGE_INTEGER ularge; GetSystemTime(&system_time); SystemTimeToFileTime(&system_time, &file_time); ularge.LowPart = file_time.dwLowDateTime; ularge.HighPart = file_time.dwHighDateTime; tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); return 0; } #endif �����������������������������������������������������������jabberd2-jabberd-2.3.4/subst/inet_aton.c������������������������������������������������������������0000664�0000000�0000000�00000005060�12614627753�0020064�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Kungliga Tekniska * Hgskolan and its contributors. * * 4. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $Id: inet_aton.c,v 1.5 2005/06/02 04:48:25 zion Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_INET_ATON) && defined(_WIN32) #ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) #else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) #endif /* JABBERD2_EXPORTS */ #include "ac-stdint.h" #include "ip6_misc.h" /* Minimal implementation of inet_aton. * Cannot distinguish between failure and a local broadcast address. */ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif JABBERD2_API int inet_aton(const char *cp, struct in_addr *addr) { addr->s_addr = inet_addr(cp); return (addr->s_addr == INADDR_NONE) ? 0 : 1; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/inet_ntop.c������������������������������������������������������������0000664�0000000�0000000�00000002522�12614627753�0020103�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_INET_NTOP) && defined(_WIN32) #ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) #else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) #endif /* JABBERD2_EXPORTS */ #include "ac-stdint.h" #include "ip6_misc.h" #include <stdio.h> #include <errno.h> #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif static const char * inet_ntop_v4 (const void *src, char *dst, size_t size) { const char digits[] = "0123456789"; int i; struct in_addr *addr = (struct in_addr *)src; u_long a = ntohl(addr->s_addr); const char *orig_dst = dst; if (size < INET_ADDRSTRLEN) { errno = ENOSPC; return NULL; } for (i = 0; i < 4; ++i) { int n = (a >> (24 - i * 8)) & 0xFF; int non_zerop = 0; if (non_zerop || n / 100 > 0) { *dst++ = digits[n / 100]; n %= 100; non_zerop = 1; } if (non_zerop || n / 10 > 0) { *dst++ = digits[n / 10]; n %= 10; non_zerop = 1; } *dst++ = digits[n]; if (i != 3) *dst++ = '.'; } *dst++ = '\0'; return orig_dst; } JABBERD2_API const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET : return inet_ntop_v4 (src, dst, size); default : errno = WSAEAFNOSUPPORT; return NULL; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/inet_pton.c������������������������������������������������������������0000664�0000000�0000000�00000001144�12614627753�0020102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_INET_PTON) && defined(_WIN32) #ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) #else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) #endif /* JABBERD2_EXPORTS */ #include "ac-stdint.h" #include "ip6_misc.h" #include <errno.h> #ifndef EAFNOSUPPORT #define EAFNOSUPPORT 97 /* not present in errno.h provided with VC */ #endif JABBERD2_API int inet_pton(int af, const char *src, void *dst) { if (af != AF_INET) { errno = EAFNOSUPPORT; return -1; } return inet_aton (src, dst); } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/ip6_misc.h�������������������������������������������������������������0000664�0000000�0000000�00000012724�12614627753�0017627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 1993, 1994, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) $Header: /home/cvs/jabberd2/subst/ip6_misc.h,v 1.5 2005/06/02 04:48:25 zion Exp $ (LBL) */ /* * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows */ #include <winsock2.h> #ifndef __MINGW32__ #include <ws2tcpip.h> #endif /* __MINGW32__ */ #ifndef IN_MULTICAST #define IN_MULTICAST(a) IN_CLASSD(a) #endif #ifndef IN_EXPERIMENTAL #define IN_EXPERIMENTAL(a) ((((uint32_t) (a)) & 0xe0000000) == 0xe0000000) #endif #ifndef IN_LOOPBACK #define IN_LOOPBACKNET 127 #endif #ifdef __MINGW32__ /* IPv6 address */ struct in6_addr { union { uint8_t u6_addr8[16]; uint16_t u6_addr16[8]; uint32_t u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 #define s6_addr64 in6_u.u6_addr64 }; #define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } #define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } #endif /* __MINGW32__ */ #ifdef __MINGW32__ typedef unsigned short sa_family_t; #define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family /* Ditto, for IPv6. */ struct sockaddr_in6 { __SOCKADDR_COMMON (sin6_); uint16_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; #define IN6_IS_ADDR_V4MAPPED(a) \ ((((uint32_t *) (a))[0] == 0) && (((uint32_t *) (a))[1] == 0) && \ (((uint32_t *) (a))[2] == htonl (0xffff))) #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff) #define IN6_IS_ADDR_LINKLOCAL(a) \ ((((uint32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) #define IN6_IS_ADDR_LOOPBACK(a) \ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == htonl (1)) #endif /* __MINGW32__ */ #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim #define nd_rd_type nd_rd_hdr.icmp6_type #define nd_rd_code nd_rd_hdr.icmp6_code #define nd_rd_cksum nd_rd_hdr.icmp6_cksum #define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] /* * IPV6 extension headers */ #define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ #define IPPROTO_IPV6 41 /* IPv6 header. */ #define IPPROTO_ROUTING 43 /* IPv6 routing header */ #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ #define IPPROTO_ESP 50 /* encapsulating security payload */ #define IPPROTO_AH 51 /* authentication header */ #define IPPROTO_ICMPV6 58 /* ICMPv6 */ #define IPPROTO_NONE 59 /* IPv6 no next header */ #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ #define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ #define IPV6_RTHDR_TYPE_0 0 /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ #define IP6OPT_JUMBO_LEN 6 #define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 #define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ #define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ #define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ #define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ #define IP6OPT_EID 0x8a /* 10 0 01010 */ #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 #define IP6OPT_TYPE_DISCARD 0x40 #define IP6OPT_TYPE_FORCEICMP 0x80 #define IP6OPT_TYPE_ICMP 0xC0 #define IP6OPT_MUTABLE 0x20 #ifdef __MINGW32__ #ifndef EAI_ADDRFAMILY struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif #endif /* __MINGW32__ */ ��������������������������������������������jabberd2-jabberd-2.3.4/subst/snprintf.c�������������������������������������������������������������0000664�0000000�0000000�00000070235�12614627753�0017755�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * Copyright (c) 1995-1998 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. * * 5. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see <http://www.apache.org/>. * * This code is based on, and used with the permission of, the * SIO stdio-replacement strx_* functions by Panos Tsirigotis * <panos@alumni.cs.colorado.edu> for xinetd. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_SNPRINTF) || defined(HAVE_BROKEN_SNPRINTF) || !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF) /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <math.h> #ifdef HAVE_GCVT #define ap_ecvt ecvt #define ap_fcvt fcvt #define ap_gcvt gcvt #else /* * cvt.c - IEEE floating point formatting routines for FreeBSD * from GNU libc-4.6.27 */ /* * ap_ecvt converts to decimal * the number of digits is specified by ndigit * decpt is set to the position of the decimal point * sign is set to 0 for positive, 1 for negative */ #define NDIG 80 static char * ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag) { register int r2; double fi, fj; register char *p, *p1; static char buf[NDIG]; if (ndigits >= NDIG - 1) ndigits = NDIG - 2; r2 = 0; *sign = 0; p = &buf[0]; if (arg < 0) { *sign = 1; arg = -arg; } arg = modf(arg, &fi); p1 = &buf[NDIG]; /* * Do integer part */ if (fi != 0) { p1 = &buf[NDIG]; while (fi != 0) { fj = modf(fi / 10, &fi); *--p1 = (int) ((fj + .03) * 10) + '0'; r2++; } while (p1 < &buf[NDIG]) *p++ = *p1++; } else if (arg > 0) { while ((fj = arg * 10) < 1) { arg = fj; r2--; } } p1 = &buf[ndigits]; if (eflag == 0) p1 += r2; *decpt = r2; if (p1 < &buf[0]) { buf[0] = '\0'; return (buf); } while (p <= p1 && p < &buf[NDIG]) { arg *= 10; arg = modf(arg, &fj); *p++ = (int) fj + '0'; } if (p1 >= &buf[NDIG]) { buf[NDIG - 1] = '\0'; return (buf); } p = p1; *p1 += 5; while (*p1 > '9') { *p1 = '0'; if (p1 > buf) ++ * --p1; else { *p1 = '1'; (*decpt)++; if (eflag == 0) { if (p > buf) *p = '0'; p++; } } } *p = '\0'; return (buf); } static char * ap_ecvt(double arg, int ndigits, int *decpt, int *sign) { return (ap_cvt(arg, ndigits, decpt, sign, 1)); } static char * ap_fcvt(double arg, int ndigits, int *decpt, int *sign) { return (ap_cvt(arg, ndigits, decpt, sign, 0)); } /* * ap_gcvt - Floating output conversion to * minimal length string */ static char * ap_gcvt(double number, int ndigit, char *buf) { int sign, decpt; register char *p1, *p2; int i; p1 = ap_ecvt(number, ndigit, &decpt, &sign); p2 = buf; if (sign) *p2++ = '-'; for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) ndigit--; if ((decpt >= 0 && decpt - ndigit > 4) || (decpt < 0 && decpt < -3)) { /* use E-style */ decpt--; *p2++ = *p1++; *p2++ = '.'; for (i = 1; i < ndigit; i++) *p2++ = *p1++; *p2++ = 'e'; if (decpt < 0) { decpt = -decpt; *p2++ = '-'; } else *p2++ = '+'; if (decpt / 100 > 0) *p2++ = decpt / 100 + '0'; if (decpt / 10 > 0) *p2++ = (decpt % 100) / 10 + '0'; *p2++ = decpt % 10 + '0'; } else { if (decpt <= 0) { if (*p1 != '0') *p2++ = '.'; while (decpt < 0) { decpt++; *p2++ = '0'; } } for (i = 1; i <= ndigit; i++) { *p2++ = *p1++; if (i == decpt) *p2++ = '.'; } if (ndigit < decpt) { while (ndigit++ < decpt) *p2++ = '0'; *p2++ = '.'; } } if (p2[-1] == '.') p2--; *p2 = '\0'; return (buf); } #endif /* HAVE_CVT */ typedef enum { NO = 0, YES = 1 } boolean_e; #define FALSE 0 #define TRUE 1 #define NUL '\0' #define INT_NULL ((int *)0) #define WIDE_INT long typedef WIDE_INT wide_int; typedef unsigned WIDE_INT u_wide_int; typedef int bool_int; #define S_NULL "(null)" #define S_NULL_LEN 6 #define FLOAT_DIGITS 6 #define EXPONENT_LENGTH 10 /* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * * XXX: this is a magic number; do not decrease it */ #define NUM_BUF_SIZE 512 /* * Descriptor for buffer area */ struct buf_area { char *buf_end; char *nextb; /* pointer to next byte to read/write */ }; typedef struct buf_area buffy; /* * The INS_CHAR macro inserts a character in the buffer and writes * the buffer back to disk if necessary * It uses the char pointers sp and bep: * sp points to the next available character in the buffer * bep points to the end-of-buffer+1 * While using this macro, note that the nextb pointer is NOT updated. * * NOTE: Evaluation of the c argument should not have any side-effects */ #define INS_CHAR( c, sp, bep, cc ) \ { \ if ( sp < bep ) \ { \ *sp++ = c ; \ cc++ ; \ } \ } #define NUM( c ) ( c - '0' ) #define STR_TO_DEC( str, num ) \ num = NUM( *str++ ) ; \ while ( isdigit((int)*str ) ) \ { \ num *= 10 ; \ num += NUM( *str++ ) ; \ } /* * This macro does zero padding so that the precision * requirement is satisfied. The padding is done by * adding '0's to the left of the string that is going * to be printed. */ #define FIX_PRECISION( adjust, precision, s, s_len ) \ if ( adjust ) \ while ( s_len < precision ) \ { \ *--s = '0' ; \ s_len++ ; \ } /* * Macro that does padding. The padding is done by printing * the character ch. */ #define PAD( width, len, ch ) do \ { \ INS_CHAR( ch, sp, bep, cc ) ; \ width-- ; \ } \ while ( width > len ) /* * Prefix the character ch to the string str * Increase length * Set the has_prefix flag */ #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES /* * Convert num to its decimal format. * Return value: * - a pointer to a string containing the number (no sign) * - len contains the length of the string * - is_negative is set to TRUE or FALSE depending on the sign * of the number (always set to FALSE if is_unsigned is TRUE) * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ static char * conv_10(register wide_int num, register bool_int is_unsigned, register bool_int * is_negative, char *buf_end, register int *len) { register char *p = buf_end; register u_wide_int magnitude; if (is_unsigned) { magnitude = (u_wide_int) num; *is_negative = FALSE; } else { *is_negative = (num < 0); /* * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number * b. negate it (becomes positive) * c. convert it to unsigned * d. add 1 */ if (*is_negative) { wide_int t = num + 1; magnitude = ((u_wide_int) - t) + 1; } else magnitude = (u_wide_int) num; } /* * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10; *--p = magnitude - new_magnitude * 10 + '0'; magnitude = new_magnitude; } while (magnitude); *len = buf_end - p; return (p); } /* * Convert a floating point number to a string formats 'f', 'e' or 'E'. * The result is placed in buf, and len denotes the length of the string * The sign is returned in the is_negative argument (and is not placed * in buf). */ static char * conv_fp(register char format, register double num, boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) { register char *s = buf; register char *p; int decimal_point; if (format == 'f') p = ap_fcvt(num, precision, &decimal_point, is_negative); else /* either e or E format */ p = ap_ecvt(num, precision + 1, &decimal_point, is_negative); /* * Check for Infinity and NaN */ if (isalpha((int)*p)) { *len = strlen(strcpy(buf, p)); *is_negative = FALSE; return (buf); } if (format == 'f') { if (decimal_point <= 0) { *s++ = '0'; if (precision > 0) { *s++ = '.'; while (decimal_point++ < 0) *s++ = '0'; } else if (add_dp) { *s++ = '.'; } } else { while (decimal_point-- > 0) { *s++ = *p++; } if (precision > 0 || add_dp) { *s++ = '.'; } } } else { *s++ = *p++; if (precision > 0 || add_dp) *s++ = '.'; } /* * copy the rest of p, the NUL is NOT copied */ while (*p) *s++ = *p++; if (format != 'f') { char temp[EXPONENT_LENGTH]; /* for exponent conversion */ int t_len; bool_int exponent_is_negative; *s++ = format; /* either e or E */ decimal_point--; if (decimal_point != 0) { p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len); *s++ = exponent_is_negative ? '-' : '+'; /* * Make sure the exponent has at least 2 digits */ if (t_len == 1) *s++ = '0'; while (t_len--) *s++ = *p++; } else { *s++ = '+'; *s++ = '0'; *s++ = '0'; } } *len = s - buf; return (buf); } /* * Convert num to a base X number where X is a power of 2. nbits determines X. * For example, if nbits is 3, we do base 8 conversion * Return value: * a pointer to a string containing the number * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ static char * conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) { register int mask = (1 << nbits) - 1; register char *p = buf_end; static char low_digits[] = "0123456789abcdef"; static char upper_digits[] = "0123456789ABCDEF"; register char *digits = (format == 'X') ? upper_digits : low_digits; do { *--p = digits[num & mask]; num >>= nbits; } while (num); *len = buf_end - p; return (p); } /* * Do format conversion placing the output in buffer */ static int format_converter(register buffy * odp, const char *fmt, va_list ap) { register char *sp; register char *bep; register int cc = 0; register int i; register char *s = NULL; char *q; int s_len; register int min_width = 0; int precision = 0; enum { LEFT, RIGHT } adjust; char pad_char; char prefix_char; double fp_num; wide_int i_num = (wide_int) 0; u_wide_int ui_num; char num_buf[NUM_BUF_SIZE]; char char_buf[2]; /* for printing %% and %<unknown> */ /* * Flag variables */ boolean_e is_long; boolean_e alternate_form; boolean_e print_sign; boolean_e print_blank; boolean_e adjust_precision; boolean_e adjust_width; bool_int is_negative; sp = odp->nextb; bep = odp->buf_end; while (*fmt) { if (*fmt != '%') { INS_CHAR(*fmt, sp, bep, cc); } else { /* * Default variable settings */ adjust = RIGHT; alternate_form = print_sign = print_blank = NO; pad_char = ' '; prefix_char = NUL; fmt++; /* * Try to avoid checking for flags, width or precision */ if (isascii((int)*fmt) && !islower((int)*fmt)) { /* * Recognize flags: -, #, BLANK, + */ for (;; fmt++) { if (*fmt == '-') adjust = LEFT; else if (*fmt == '+') print_sign = YES; else if (*fmt == '#') alternate_form = YES; else if (*fmt == ' ') print_blank = YES; else if (*fmt == '0') pad_char = '0'; else break; } /* * Check if a width was specified */ if (isdigit((int)*fmt)) { STR_TO_DEC(fmt, min_width); adjust_width = YES; } else if (*fmt == '*') { min_width = va_arg(ap, int); fmt++; adjust_width = YES; if (min_width < 0) { adjust = LEFT; min_width = -min_width; } } else adjust_width = NO; /* * Check if a precision was specified * * XXX: an unreasonable amount of precision may be specified * resulting in overflow of num_buf. Currently we * ignore this possibility. */ if (*fmt == '.') { adjust_precision = YES; fmt++; if (isdigit((int)*fmt)) { STR_TO_DEC(fmt, precision); } else if (*fmt == '*') { precision = va_arg(ap, int); fmt++; if (precision < 0) precision = 0; } else precision = 0; } else adjust_precision = NO; } else adjust_precision = adjust_width = NO; /* * Modifier check */ if (*fmt == 'l') { is_long = YES; fmt++; } else is_long = NO; /* * Argument extraction and printing. * First we determine the argument type. * Then, we convert the argument to a string. * On exit from the switch, s points to the string that * must be printed, s_len has the length of the string * The precision requirements, if any, are reflected in s_len. * * NOTE: pad_char may be set to '0' because of the 0 flag. * It is reset to ' ' by non-numeric formats */ switch (*fmt) { case 'u': if (is_long) i_num = va_arg(ap, u_wide_int); else i_num = (wide_int) va_arg(ap, unsigned int); /* * The rest also applies to other integer formats, so fall * into that case. */ case 'd': case 'i': /* * Get the arg if we haven't already. */ if ((*fmt) != 'u') { if (is_long) i_num = va_arg(ap, wide_int); else i_num = (wide_int) va_arg(ap, int); }; s = conv_10(i_num, (*fmt) == 'u', &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); FIX_PRECISION(adjust_precision, precision, s, s_len); if (*fmt != 'u') { if (is_negative) prefix_char = '-'; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; } break; case 'o': if (is_long) ui_num = va_arg(ap, u_wide_int); else ui_num = (u_wide_int) va_arg(ap, unsigned int); s = conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && *s != '0') { *--s = '0'; s_len++; } break; case 'x': case 'X': if (is_long) ui_num = (u_wide_int) va_arg(ap, u_wide_int); else ui_num = (u_wide_int) va_arg(ap, unsigned int); s = conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && i_num != 0) { *--s = *fmt; /* 'x' or 'X' */ *--s = '0'; s_len += 2; } break; case 's': s = va_arg(ap, char *); if (s != NULL) { if (!adjust_precision) { s_len = strlen(s); } else { /* From the C library standard in section 7.9.6.1: * ...if the precision is specified, no more then * that many characters are written. If the * precision is not specified or is greater * than the size of the array, the array shall * contain a null character. * * My reading is is precision is specified and * is less then or equal to the size of the * array, no null character is required. So * we can't do a strlen. * * This figures out the length of the string * up to the precision. Once it's long enough * for the specified precision, we don't care * anymore. * * NOTE: you must do the length comparison * before the check for the null character. * Otherwise, you'll check one beyond the * last valid character. */ const char *walk; for (walk = s, s_len = 0; (s_len < precision) && (*walk != '\0'); ++walk, ++s_len); } } else { s = S_NULL; s_len = S_NULL_LEN; } pad_char = ' '; break; case 'f': case 'e': case 'E': fp_num = va_arg(ap, double); s = conv_fp(*fmt, fp_num, alternate_form, (adjust_precision == NO) ? FLOAT_DIGITS : precision, &is_negative, &num_buf[1], &s_len); if (is_negative) prefix_char = '-'; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; break; case 'g': case 'G': if (adjust_precision == NO) precision = FLOAT_DIGITS; else if (precision == 0) precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]); if (*s == '-') prefix_char = *s++; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; s_len = strlen(s); if (alternate_form && (q = strchr(s, '.')) == NULL) s[s_len++] = '.'; if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) *q = 'E'; break; case 'c': char_buf[0] = (char) (va_arg(ap, int)); s = &char_buf[0]; s_len = 1; pad_char = ' '; break; case '%': char_buf[0] = '%'; s = &char_buf[0]; s_len = 1; pad_char = ' '; break; case 'n': *(va_arg(ap, int *)) = cc; break; /* * Always extract the argument as a "char *" pointer. We * should be using "void *" but there are still machines * that don't understand it. * If the pointer size is equal to the size of an unsigned * integer we convert the pointer to a hex number, otherwise * we print "%p" to indicate that we don't handle "%p". */ case 'p': ui_num = (u_wide_int) va_arg(ap, char *); if (sizeof(char *) <= sizeof(u_wide_int)) s = conv_p2(ui_num, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); else { s = "%p"; s_len = 2; } pad_char = ' '; break; case NUL: /* * The last character of the format string was %. * We ignore it. */ continue; /* * The default case is for unrecognized %'s. * We print %<char> to help the user identify what * option is not understood. * This is also useful in case the user wants to pass * the output of format_converter to another function * that understands some other %<char> (like syslog). * Note that we can't point s inside fmt because the * unknown <char> could be preceded by width etc. */ default: char_buf[0] = '%'; char_buf[1] = *fmt; s = char_buf; s_len = 2; pad_char = ' '; break; } if (prefix_char != NUL) { *--s = prefix_char; s_len++; } if (adjust_width && adjust == RIGHT && min_width > s_len) { if (pad_char == '0' && prefix_char != NUL) { INS_CHAR(*s, sp, bep, cc) s++; s_len--; min_width--; } PAD(min_width, s_len, pad_char); } /* * Print the string s. */ for (i = s_len; i != 0; i--) { INS_CHAR(*s, sp, bep, cc); s++; } if (adjust_width && adjust == LEFT && min_width > s_len) PAD(min_width, s_len, pad_char); } fmt++; } odp->nextb = sp; return (cc); } /* * This is the general purpose conversion function. */ static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) { buffy od; int cc; /* * First initialize the descriptor * Notice that if no length is given, we initialize buf_end to the * highest possible address. */ od.buf_end = len ? &buf[len] : (char *) ~0; od.nextb = buf; /* * Do the conversion */ cc = format_converter(&od, format, ap); if (len == 0 || od.nextb <= od.buf_end) *(od.nextb) = '\0'; if (ccp) *ccp = cc; } JABBERD2_API int ap_snprintf(char *buf, size_t len, const char *format,...) { int cc; va_list ap; va_start(ap, format); strx_printv(&cc, buf, (len - 1), format, ap); va_end(ap); return (cc); } JABBERD2_API int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) { int cc; strx_printv(&cc, buf, (len - 1), format, ap); return (cc); } #endif /* HAVE_SNPRINTF */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/strndup.c��������������������������������������������������������������0000664�0000000�0000000�00000001233�12614627753�0017601�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #ifndef HAVE_STRNDUP #include <stddef.h> /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ JABBERD2_API char *strndup(char *str, size_t len) { char *dup = (char *)malloc(len+1); if (dup) { strncpy(dup,str,len); dup[len]= '\0'; } return dup; } #endif /* HAVE_STRNDUP */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/subst.h����������������������������������������������������������������0000664�0000000�0000000�00000005574�12614627753�0017263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* substituted functions */ #ifndef INCL_SUBST_H #define INCL_SUBST_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif #if defined (HAVE_STDARG_H) #include <stdarg.h> #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #if !defined(HAVE_SNPRINTF) || defined(HAVE_BROKEN_SNPRINTF) JABBERD2_API int ap_snprintf(char *, size_t, const char *, ...); # define snprintf ap_snprintf #endif #if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF) JABBERD2_API int ap_vsnprintf(char *, size_t, const char *, va_list ap); # define vsnprintf ap_vsnprintf #endif #ifndef HAVE_GETOPT # include "getopt.h" #endif #ifndef HAVE_SYSLOG_H # include "syslog.h" #endif #ifndef HAVE_GETTIMEOFDAY # if defined(HAVE_SYS_TIME_H) # include <sys/time.h> # elif defined(HAVE_SYS_TIMEB_H) # include <sys/timeb.h> # endif struct timezone { int tz_minuteswest; int tz_dsttime; }; JABBERD2_API int gettimeofday(struct timeval *tp, struct timezone *tz); #endif #ifdef HAVE_WINSOCK2_H # include <winsock2.h> # include "ip6_misc.h" # define EWOULDBLOCK WSAEWOULDBLOCK # define ECONNREFUSED WSAECONNREFUSED # define EINPROGRESS WSAEINPROGRESS #endif #ifndef HAVE_INET_ATON JABBERD2_API int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_INET_NTOP JABBERD2_API const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_PTON JABBERD2_API int inet_pton(int af, const char *src, void *dst); #endif #ifndef HAVE_IN_PORT_T typedef uint16_t in_port_t; #endif #ifdef HAVE__MKDIR # define mkdir(a,b) _mkdir(a) #endif #ifndef HAVE_STRNDUP JABBERD2_API char *strndup(char *str, size_t len); #endif #ifndef HAVE_TIMEGM #include <time.h> JABBERD2_API time_t timegm (struct tm *tm); #endif #endif ������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/syslog.c���������������������������������������������������������������0000664�0000000�0000000�00000007431�12614627753�0017430�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* $Id: syslog.c,v 1.5 2005/06/02 04:48:25 zion Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined(HAVE_SYSLOG_H) && defined(HAVE_REPORTEVENT) #include <stdio.h> #include <windows.h> #include <string.h> #include <stdlib.h> #include "syslog.h" static HANDLE hAppLog = NULL; static FILE *log_stream; static int debug_level = 0; static struct dsn_c_pvt_sfnt { int val; const char *strval; } facilities[] = { { LOG_KERN, "kern" }, { LOG_USER, "user" }, { LOG_MAIL, "mail" }, { LOG_DAEMON, "daemon" }, { LOG_AUTH, "auth" }, { LOG_SYSLOG, "syslog" }, { LOG_LPR, "lpr" }, #ifdef LOG_NEWS { LOG_NEWS, "news" }, #endif #ifdef LOG_UUCP { LOG_UUCP, "uucp" }, #endif #ifdef LOG_CRON { LOG_CRON, "cron" }, #endif #ifdef LOG_AUTHPRIV { LOG_AUTHPRIV, "authpriv" }, #endif #ifdef LOG_FTP { LOG_FTP, "ftp" }, #endif { LOG_LOCAL0, "local0"}, { LOG_LOCAL1, "local1"}, { LOG_LOCAL2, "local2"}, { LOG_LOCAL3, "local3"}, { LOG_LOCAL4, "local4"}, { LOG_LOCAL5, "local5"}, { LOG_LOCAL6, "local6"}, { LOG_LOCAL7, "local7"}, { LOG_USER, "log_user"}, { 0, NULL } }; /* * Log to the NT Event Log */ void syslog(int level, const char *fmt, ...) { va_list ap; char buf[1024]; const char *str[1]; str[0] = buf; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); /* Make sure that the channel is open to write the event */ if (hAppLog != NULL) { switch (level) { case LOG_INFO: case LOG_NOTICE: case LOG_DEBUG: ReportEvent(hAppLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, str, NULL); break; case LOG_WARNING: ReportEvent(hAppLog, EVENTLOG_WARNING_TYPE, 0, 0, NULL, 1, 0, str, NULL); break; default: ReportEvent(hAppLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, str, NULL); break; } } } /* * Initialize event logging */ void openlog(const char *name, int flags, ...) { /* Get a handle to the Application event log */ hAppLog = RegisterEventSource(NULL, name); } /* * Close the Handle to the application Event Log * We don't care whether or not we succeeded so ignore return values * In fact if we failed then we would have nowhere to put the message */ void closelog() { DeregisterEventSource(hAppLog); } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/subst/syslog.h���������������������������������������������������������������0000664�0000000�0000000�00000004755�12614627753�0017443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* $Id: syslog.h,v 1.5 2005/06/02 04:48:25 zion Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifndef HAVE_SYSLOG_H #ifndef _SYSLOG_H #define _SYSLOG_H #include <stdio.h> /* Constant definitions for openlog() */ #define LOG_PID 1 #define LOG_CONS 2 /* NT event log does not support facility level */ #define LOG_KERN 0 #define LOG_USER 0 #define LOG_MAIL 0 #define LOG_DAEMON 0 #define LOG_AUTH 0 #define LOG_SYSLOG 0 #define LOG_LPR 0 #define LOG_LOCAL0 0 #define LOG_LOCAL1 0 #define LOG_LOCAL2 0 #define LOG_LOCAL3 0 #define LOG_LOCAL4 0 #define LOG_LOCAL5 0 #define LOG_LOCAL6 0 #define LOG_LOCAL7 0 #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ JABBERD2_API void syslog(int level, const char *fmt, ...); JABBERD2_API void openlog(const char *, int, ...); JABBERD2_API void closelog(void); #endif #endif �������������������jabberd2-jabberd-2.3.4/subst/timegm.c���������������������������������������������������������������0000664�0000000�0000000�00000002064�12614627753�0017367�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef HAVE_TIMEGM #include <time.h> #include <stdlib.h> #include <stdio.h> #if !defined(HAVE_SNPRINTF) || defined(HAVE_BROKEN_SNPRINTF) int ap_snprintf(char *, size_t, const char *, ...); # define snprintf ap_snprintf #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ JABBERD2_API time_t timegm(struct tm *tm) { time_t ret; char *tz; /* save current timezone and set UTC */ tz = getenv("TZ"); putenv("TZ=UTC"); /* use Coordinated Universal Time (i.e. zero offset) */ tzset(); ret = mktime(tm); if(tz) { char buf[256]; snprintf(buf, sizeof(buf), "TZ=%s", tz); putenv(buf); } else putenv("TZ="); tzset(); return ret; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/��������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015231�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/Makefile.am���������������������������������������������������������������0000664�0000000�0000000�00000000610�12614627753�0017262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet AM_CPPFLAGS = -I@top_srcdir@ noinst_LTLIBRARIES = libsx.la noinst_HEADERS = plugins.h sasl.h sx.h libsx_la_SOURCES = callback.c chain.c client.c env.c error.c io.c server.c sx.c sasl.c ack.c libsx_la_LIBADD = @LDFLAGS@ if HAVE_SSL libsx_la_SOURCES += ssl.c endif if HAVE_LIBZ libsx_la_SOURCES += compress.c endif if USE_WEBSOCKET libsx_la_SOURCES += websocket.c endif ������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/ack.c���������������������������������������������������������������������0000664�0000000�0000000�00000010105�12614627753�0016130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Tomasz Sterna * * 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; version 2 of the License * * 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, MA02111-1307USA */ /* * this sx plugin implements stanza acknowledgements * as described in XEP-0198: Stanza Acknowledgements */ #include "sx.h" #define STREAM_ACK_NS_DECL " xmlns:ack='" uri_ACK "'" static void _sx_ack_header(sx_t s, sx_plugin_t p, sx_buf_t buf) { /* WebSocket framing has own acks */ if (s->flags & SX_WEBSOCKET_WRAPPER) return; log_debug(ZONE, "hacking ack namespace decl onto stream header"); /* get enough space */ _sx_buffer_alloc_margin(buf, 0, strlen(STREAM_ACK_NS_DECL) + 2); /* overwrite the trailing ">" with a decl followed by a new ">" */ memcpy(&buf->data[buf->len - 1], STREAM_ACK_NS_DECL ">", strlen(STREAM_ACK_NS_DECL)+1); buf->len += strlen(STREAM_ACK_NS_DECL); } /** sx features callback */ static void _sx_ack_features(sx_t s, sx_plugin_t p, nad_t nad) { /* offer feature only when authenticated and not enabled yet and not on WebSocket framing */ if(s->state == state_OPEN && s->plugin_data[p->index] == NULL && !(s->flags & SX_WEBSOCKET_WRAPPER)) nad_append_elem(nad, -1, "ack:ack", 1); } /** process handshake packets from the client */ static int _sx_ack_process(sx_t s, sx_plugin_t p, nad_t nad) { int attr; /* not interested if we're not a server or have WebSocket framing */ if(s->type != type_SERVER || s->flags & SX_WEBSOCKET_WRAPPER) return 1; /* only want ack packets */ if((NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_ACK) || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_ACK, strlen(uri_ACK)) != 0)) return 1; /* pings */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp(NAD_ENAME(nad, 0), "ping", 4) == 0) { jqueue_push(s->wbufq, _sx_buffer_new("<ack:pong/>", 11, NULL, NULL), 0); s->want_write = 1; /* handled the packet */ nad_free(nad); return 0; } /* enable only when authenticated */ if(s->state == state_OPEN && NAD_ENAME_L(nad, 0) == 6 && strncmp(NAD_ENAME(nad, 0), "enable", 6) == 0) { jqueue_push(s->wbufq, _sx_buffer_new("<ack:enabled/>", 14, NULL, NULL), 254); s->want_write = 1; s->plugin_data[p->index] = (void *) 1; /* handled the packet */ nad_free(nad); return 0; } /* 'r' or 'a' when enabled */ if(s->plugin_data[p->index] != NULL && NAD_ENAME_L(nad, 0) == 1 && (strncmp(NAD_ENAME(nad, 0), "r", 1) == 0 || strncmp(NAD_ENAME(nad, 0), "a", 1) == 0) ) { attr = nad_find_attr(nad, 0, -1, "c", NULL); if(attr >= 0) { char *buf = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 13 + 1)); snprintf(buf, NAD_AVAL_L(nad, attr) + 13 + 1, "<ack:a b='%.*s'/>", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); jqueue_push(s->wbufq, _sx_buffer_new(buf, NAD_AVAL_L(nad, attr) + 13, NULL, NULL), 255); free(buf); s->want_write = 1; } /* handled the packet */ nad_free(nad); return 0; } _sx_debug(ZONE, "unhandled ack namespace element '%.*s', dropping packet", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } /** args: none */ int sx_ack_init(sx_env_t env, sx_plugin_t p, va_list args) { log_debug(ZONE, "initialising stanza acknowledgements sx plugin"); p->header = _sx_ack_header; p->features = _sx_ack_features; p->process = _sx_ack_process; return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/callback.c����������������������������������������������������������������0000664�0000000�0000000�00000010657�12614627753�0017142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" /** primary expat callbacks */ void _sx_element_start(void *arg, const char *name, const char **atts) { sx_t s = (sx_t) arg; char buf[1024]; char *uri, *elem, *prefix; const char **attr; int ns; int el; if(s->fail) return; /* starting a new nad */ if(s->nad == NULL) s->nad = nad_new(); /* make a copy */ strncpy(buf, name, 1024); buf[1023] = '\0'; /* expat gives us: prefixed namespaced elem: uri|elem|prefix default namespaced elem: uri|elem un-namespaced elem: elem */ /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_add_namespace(s->nad, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ el = nad_append_elem(s->nad, ns, elem, s->depth - 1); /* now the attributes, one at a time */ attr = atts; while(attr[0] != NULL) { /* make a copy */ strncpy(buf, attr[0], 1024); buf[1023] = '\0'; /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_append_namespace(s->nad, el, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ nad_append_attr(s->nad, ns, elem, (char *) attr[1]); attr += 2; } s->depth++; } void _sx_element_end(void *arg, const char *name) { sx_t s = (sx_t) arg; if(s->fail) return; s->depth--; if(s->depth == 1) { /* completed nad, save it for later processing */ jqueue_push(s->rnadq, s->nad, 0); s->nad = NULL; /* and reset read bytes counter */ s->rbytes = 0; } /* close received */ else if(s->depth == 0) s->depth = -1; } void _sx_cdata(void *arg, const char *str, int len) { sx_t s = (sx_t) arg; if(s->fail) return; /* no nad? no cdata */ if(s->nad == NULL) return; /* go */ nad_append_cdata(s->nad, (char *) str, len, s->depth - 1); } void _sx_namespace_start(void *arg, const char *prefix, const char *uri) { sx_t s = (sx_t) arg; int ns; if(s->fail) return; /* some versions of MSXML send xmlns='' occassionaally. it seems safe to ignore it */ if(uri == NULL) return; /* starting a new nad */ if(s->nad == NULL) s->nad = nad_new(); ns = nad_add_namespace(s->nad, (char *) uri, (char *) prefix); /* Always set the namespace (to catch cases where nad_add_namespace doesn't add it) */ s->nad->scope = ns; } #ifdef HAVE_XML_STOPPARSER /* Stop the parser if an entity declaration is hit. */ void _sx_entity_declaration(void *arg, const char *entityName, int is_parameter_entity, const char *value, int value_length, const char *base, const char *systemId, const char *publicId, const char *notationName) { sx_t s = (sx_t) arg; XML_StopParser(s->expat, XML_FALSE); } #endif ���������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/chain.c�������������������������������������������������������������������0000664�0000000�0000000�00000006303�12614627753�0016461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* manage and run the io and nad chains */ #include "sx.h" void _sx_chain_io_plugin(sx_t s, sx_plugin_t p) { _sx_chain_t cn, tail; _sx_debug(ZONE, "adding io plugin"); cn = (_sx_chain_t) malloc(sizeof(struct _sx_chain_st)); cn->p = p; if(s->wio == NULL) { s->wio = cn; cn->wnext = NULL; } else { cn->wnext = s->wio; s->wio = cn; } if(s->rio == NULL) s->rio = cn; else { for(tail = s->rio; tail->rnext != NULL; tail = tail->rnext); tail->rnext = cn; } cn->rnext = NULL; } void _sx_chain_nad_plugin(sx_t s, sx_plugin_t p) { _sx_chain_t cn, tail; _sx_debug(ZONE, "adding nad plugin"); cn = (_sx_chain_t) malloc(sizeof(struct _sx_chain_st)); cn->p = p; if(s->wnad == NULL) { s->wnad = cn; cn->wnext = NULL; } else { cn->wnext = s->wnad; s->wnad = cn; } if(s->rnad == NULL) s->rnad = cn; else { for(tail = s->rnad; tail->rnext != NULL; tail = tail->rnext); tail->rnext = cn; } cn->rnext = NULL; } int _sx_chain_io_write(sx_t s, sx_buf_t buf) { _sx_chain_t scan; int ret = 1; _sx_debug(ZONE, "calling io write chain"); for(scan = s->wio; scan != NULL; scan = scan->wnext) if(scan->p->wio != NULL) if((ret = (scan->p->wio)(s, scan->p, buf)) <= 0) return ret; return ret; } int _sx_chain_io_read(sx_t s, sx_buf_t buf) { _sx_chain_t scan; int ret = 1; _sx_debug(ZONE, "calling io read chain"); for(scan = s->rio; scan != NULL; scan = scan->rnext) if(scan->p->rio != NULL) if((ret = (scan->p->rio)(s, scan->p, buf)) <= 0) return ret; return ret; } int _sx_chain_nad_write(sx_t s, nad_t nad, int elem) { _sx_chain_t scan; _sx_debug(ZONE, "calling nad write chain"); for(scan = s->wnad; scan != NULL; scan = scan->wnext) if(scan->p->wnad != NULL) if((scan->p->wnad)(s, scan->p, nad, elem) == 0) return 0; return 1; } int _sx_chain_nad_read(sx_t s, nad_t nad) { _sx_chain_t scan; _sx_debug(ZONE, "calling nad read chain"); for(scan = s->rnad; scan != NULL; scan = scan->rnext) if(scan->p->rnad != NULL) if((scan->p->rnad)(s, scan->p, nad) == 0) return 0; return 1; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/client.c������������������������������������������������������������������0000664�0000000�0000000�00000013167�12614627753�0016663�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" static void _sx_client_element_start(void *arg, const char *name, const char **atts) { sx_t s = (sx_t) arg; int tflag = 0, fflag = 0, vflag = 0, iflag = 0, i; const char **attr; sx_error_t sxe; if(s->fail) return; /* check element and namespace */ i = strlen(uri_STREAMS) + 7; if(strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|')) { /* throw an error */ _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream open"); _sx_event(s, event_ERROR, (void *) &sxe); _sx_error(s, stream_err_BAD_FORMAT, NULL); s->fail = 1; return; } /* pull interesting things out of the header */ attr = atts; while(attr[0] != NULL) { if(!tflag && strcmp(attr[0], "to") == 0) { s->res_to = strdup(attr[1]); tflag = 1; } if(!fflag && strcmp(attr[0], "from") == 0) { s->res_from = strdup(attr[1]); fflag = 1; } if(!vflag && strcmp(attr[0], "version") == 0) { s->res_version = strdup(attr[1]); vflag = 1; } if(!iflag && strcmp(attr[0], "id") == 0) { s->id = strdup(attr[1]); iflag = 1; } attr += 2; } s->depth++; _sx_debug(ZONE, "stream response: to %s from %s version %s id %s", s->res_to, s->res_from, s->res_version, s->id); /* we're alive */ XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end); XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata); XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start); /* get the plugins to setup */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->stream != NULL) (s->env->plugins[i]->stream)(s, s->env->plugins[i]); /* bump us to stream if a plugin didn't do it already */ if(s->state < state_STREAM) { _sx_state(s, state_STREAM); _sx_event(s, event_STREAM, NULL); } } static void _sx_client_element_end(void *arg, const char *name) { sx_t s = (sx_t) arg; if(s->fail) return; s->depth--; } static void _sx_client_notify_header(sx_t s, void *arg) { /* expat callbacks */ XML_SetElementHandler(s->expat, (void *) _sx_client_element_start, (void *) _sx_client_element_end); /* state change */ _sx_state(s, state_STREAM_SENT); _sx_debug(ZONE, "stream header sent, waiting for reply"); /* waiting for a response */ s->want_read = 1; } void sx_client_init(sx_t s, unsigned int flags, const char *ns, const char *to, const char *from, const char *version) { sx_buf_t buf; char *c; int i, len; assert((int) (s != NULL)); /* can't do anything if we're alive already */ if(s->state != state_NONE) return; s->type = type_CLIENT; s->flags = flags; _sx_debug(ZONE, "doing client init for sx %d %s", s->tag, _sx_flags(s)); if(ns != NULL) s->ns = strdup(ns); if(to != NULL) s->req_to = strdup(to); if(from != NULL) s->req_from = strdup(from); if(version != NULL) s->req_version = strdup(version); /* plugin */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->client != NULL) (s->env->plugins[i]->client)(s, s->env->plugins[i]); _sx_debug(ZONE, "stream request: ns %s to %s from %s version %s", ns, to, from, version); /* build the stream start */ len = strlen(uri_STREAMS) + 52; if(ns != NULL) len += 9 + strlen(ns); if(to != NULL) len += 6 + strlen(to); if(from != NULL) len += 8 + strlen(from); if(version != NULL) len += 11 + strlen(version); buf = _sx_buffer_new(NULL, len+1, _sx_client_notify_header, NULL); c = buf->data; strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'"); if(ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", ns); } if(to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", to); } if(from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", from); } if(version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", version); } c = strchr(c, '\0'); sprintf(c, ">"); assert(buf->len == strlen(buf->data)+1); buf->len --; /* plugins can mess with the header too */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->header != NULL) (s->env->plugins[i]->header)(s, s->env->plugins[i], buf); _sx_debug(ZONE, "prepared stream header: %.*s", buf->len, buf->data); /* off it goes */ jqueue_push(s->wbufq, buf, 0); /* we have stuff to write */ s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/compress.c����������������������������������������������������������������0000664�0000000�0000000�00000026556�12614627753�0017246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2007 Tomasz Sterna * * 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; version 2 of the License. * * 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, MA02111-1307USA */ /** * this plugin implements the XEP-0138: Stream Compression */ #include "sx.h" static void _sx_compress_notify_compress(sx_t s, void *arg) { _sx_debug(ZONE, "preparing for compress"); _sx_reset(s); /* start listening */ sx_server_init(s, s->flags | SX_COMPRESS_WRAPPER); } static int _sx_compress_process(sx_t s, sx_plugin_t p, nad_t nad) { int flags; char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; sx_error_t sxe; /* not interested if we're a server and we never offered it */ if(s->type == type_SERVER && !(s->flags & SX_COMPRESS_OFFER)) return 1; /* only want compress packets */ if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != sizeof(uri_COMPRESS)-1 || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_COMPRESS, sizeof(uri_COMPRESS)-1) != 0) return 1; /* compress from client */ if(s->type == type_SERVER) { if(NAD_ENAME_L(nad, 0) == 8 && strncmp(NAD_ENAME(nad, 0), "compress", 8) == 0) { nad_free(nad); /* can't go on if we've been here before */ if(s->flags & SX_COMPRESS_WRAPPER) { _sx_debug(ZONE, "compress requested on already compressed channel, dropping packet"); return 0; } _sx_debug(ZONE, "compress requested, setting up"); /* go ahead */ jqueue_push(s->wbufq, _sx_buffer_new("<compressed xmlns='" uri_COMPRESS "'/>", sizeof(uri_COMPRESS)-1 + 22, _sx_compress_notify_compress, NULL), 0); s->want_write = 1; /* handled the packet */ return 0; } } else if(s->type == type_CLIENT) { /* kick off the handshake */ if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "compressed", 7) == 0) { nad_free(nad); /* save interesting bits */ flags = s->flags; if(s->ns != NULL) ns = strdup(s->ns); if(s->req_to != NULL) to = strdup(s->req_to); if(s->req_from != NULL) from = strdup(s->req_from); if(s->req_version != NULL) version = strdup(s->req_version); /* reset state */ _sx_reset(s); _sx_debug(ZONE, "server ready for compression, starting"); /* second time round */ sx_client_init(s, flags | SX_COMPRESS_WRAPPER, ns, to, from, version); /* free bits */ if(ns != NULL) free(ns); if(to != NULL) free(to); if(from != NULL) free(from); if(version != NULL) free(version); return 0; } /* busted server */ if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "failure", 7) == 0) { nad_free(nad); _sx_debug(ZONE, "server can't handle compression, business as usual"); _sx_gen_error(sxe, SX_ERR_COMPRESS_FAILURE, "compress failure", "Server was unable to establish compression"); _sx_event(s, event_ERROR, (void *) &sxe); return 0; } } _sx_debug(ZONE, "unknown compress namespace element '%.*s', dropping packet", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } static void _sx_compress_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; /* if the session is already compressed, or the app told us not to, or we are on WebSocket framing, * or STARTTLS is required and stream is not encrypted yet, then we don't offer anything */ if((s->flags & SX_COMPRESS_WRAPPER) || !(s->flags & SX_COMPRESS_OFFER) || ((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) || (s->flags & SX_WEBSOCKET_WRAPPER)) return; _sx_debug(ZONE, "offering compression"); ns = nad_add_namespace(nad, uri_COMPRESS_FEATURE, NULL); nad_append_elem(nad, ns, "compression", 1); nad_append_elem(nad, ns, "method", 2); nad_append_cdata(nad, "zlib", 4, 3); } static int _sx_compress_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; int ret; sx_error_t sxe; /* only bothering if they asked for wrappermode */ if(!(s->flags & SX_COMPRESS_WRAPPER)) return 1; _sx_debug(ZONE, "in _sx_compress_wio"); /* move the data into the zlib write buffer */ if(buf->len > 0) { _sx_debug(ZONE, "loading %d bytes into zlib write buffer", buf->len); _sx_buffer_alloc_margin(sc->wbuf, 0, buf->len); memcpy(sc->wbuf->data + sc->wbuf->len, buf->data, buf->len); sc->wbuf->len += buf->len; _sx_buffer_clear(buf); } /* compress the data */ if(sc->wbuf->len > 0) { sc->wstrm.avail_in = sc->wbuf->len; sc->wstrm.next_in = (Bytef*)sc->wbuf->data; /* deflate() on write buffer until there is data to compress */ do { /* make place for deflated data */ _sx_buffer_alloc_margin(buf, 0, sc->wbuf->len + SX_COMPRESS_CHUNK); sc->wstrm.avail_out = sc->wbuf->len + SX_COMPRESS_CHUNK; sc->wstrm.next_out = (Bytef*)(buf->data + buf->len); ret = deflate(&(sc->wstrm), Z_SYNC_FLUSH); assert(ret != Z_STREAM_ERROR); buf->len += sc->wbuf->len + SX_COMPRESS_CHUNK - sc->wstrm.avail_out; } while (sc->wstrm.avail_out == 0); if(ret != Z_OK || sc->wstrm.avail_in != 0) { /* throw an error */ _sx_gen_error(sxe, SX_ERR_COMPRESS, "compression error", "Error during compression"); _sx_event(s, event_ERROR, (void *) &sxe); sx_error(s, stream_err_INTERNAL_SERVER_ERROR, "Error during compression"); sx_close(s); return -2; /* fatal */ } sc->wbuf->len = sc->wstrm.avail_in; sc->wbuf->data = (char*)sc->wstrm.next_in; } _sx_debug(ZONE, "passing %d bytes from zlib write buffer", buf->len); return 1; } static int _sx_compress_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; int ret; sx_error_t sxe; /* only bothering if they asked for wrappermode */ if(!(s->flags & SX_COMPRESS_WRAPPER)) return 1; _sx_debug(ZONE, "in _sx_compress_rio"); /* move the data into the zlib read buffer */ if(buf->len > 0) { _sx_debug(ZONE, "loading %d bytes into zlib read buffer", buf->len); _sx_buffer_alloc_margin(sc->rbuf, 0, buf->len); memcpy(sc->rbuf->data + sc->rbuf->len, buf->data, buf->len); sc->rbuf->len += buf->len; _sx_buffer_clear(buf); } /* decompress the data */ if(sc->rbuf->len > 0) { sc->rstrm.avail_in = sc->rbuf->len; sc->rstrm.next_in = (Bytef*)sc->rbuf->data; /* run inflate() on read buffer while able to fill the output buffer */ do { /* make place for inflated data */ _sx_buffer_alloc_margin(buf, 0, SX_COMPRESS_CHUNK); sc->rstrm.avail_out = SX_COMPRESS_CHUNK; sc->rstrm.next_out = (Bytef*)(buf->data + buf->len); ret = inflate(&(sc->rstrm), Z_SYNC_FLUSH); assert(ret != Z_STREAM_ERROR); switch (ret) { case Z_NEED_DICT: case Z_DATA_ERROR: case Z_MEM_ERROR: /* throw an error */ _sx_gen_error(sxe, SX_ERR_COMPRESS, "compression error", "Error during decompression"); _sx_event(s, event_ERROR, (void *) &sxe); sx_error(s, stream_err_INVALID_XML, "Error during decompression"); sx_close(s); return -2; } buf->len += SX_COMPRESS_CHUNK - sc->rstrm.avail_out; } while (sc->rstrm.avail_out == 0); sc->rbuf->len = sc->rstrm.avail_in; sc->rbuf->data = (char*)sc->rstrm.next_in; } _sx_debug(ZONE, "passing %d bytes from zlib read buffer", buf->len); /* flag if we want to read */ if(sc->rbuf->len > 0) s->want_read = 1; if(buf->len == 0) return 0; return 1; } static void _sx_compress_new(sx_t s, sx_plugin_t p) { _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; /* only bothering if they asked for wrappermode and not already active */ if(!(s->flags & SX_COMPRESS_WRAPPER) || sc) return; _sx_debug(ZONE, "preparing for compressed connect for %d", s->tag); sc = (_sx_compress_conn_t) calloc(1, sizeof(struct _sx_compress_conn_st)); /* initialize streams */ sc->rstrm.zalloc = Z_NULL; sc->rstrm.zfree = Z_NULL; sc->rstrm.opaque = Z_NULL; sc->rstrm.avail_in = 0; sc->rstrm.next_in = Z_NULL; inflateInit(&(sc->rstrm)); sc->wstrm.zalloc = Z_NULL; sc->wstrm.zfree = Z_NULL; sc->wstrm.opaque = Z_NULL; deflateInit(&(sc->wstrm), Z_DEFAULT_COMPRESSION); /* read and write buffers */ sc->rbuf = _sx_buffer_new(NULL, 0, NULL, NULL); sc->wbuf = _sx_buffer_new(NULL, 0, NULL, NULL); s->plugin_data[p->index] = (void *) sc; /* bring the plugin online */ _sx_chain_io_plugin(s, p); } /** cleanup */ static void _sx_compress_free(sx_t s, sx_plugin_t p) { _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; if(sc == NULL) return; log_debug(ZONE, "cleaning up compression state"); if(s->type == type_NONE) { free(sc); return; } /* end streams */ inflateEnd(&(sc->rstrm)); deflateEnd(&(sc->wstrm)); /* free buffers */ _sx_buffer_free(sc->rbuf); _sx_buffer_free(sc->wbuf); free(sc); s->plugin_data[p->index] = NULL; } /** args: none */ int sx_compress_init(sx_env_t env, sx_plugin_t p, va_list args) { _sx_debug(ZONE, "initialising compression plugin"); p->client = _sx_compress_new; p->server = _sx_compress_new; p->rio = _sx_compress_rio; p->wio = _sx_compress_wio; p->features = _sx_compress_features; p->process = _sx_compress_process; p->free = _sx_compress_free; return 0; } int sx_compress_client_compress(sx_plugin_t p, sx_t s, const char *pemfile) { assert((int) (p != NULL)); assert((int) (s != NULL)); /* sanity */ if(s->type != type_CLIENT || s->state != state_STREAM) { _sx_debug(ZONE, "wrong conn type or state for client compress"); return 1; } /* check if we're already compressed */ if((s->flags & SX_COMPRESS_WRAPPER)) { _sx_debug(ZONE, "channel already compressed"); return 1; } _sx_debug(ZONE, "initiating compress sequence"); /* go */ jqueue_push(s->wbufq, _sx_buffer_new("<compress xmlns='" uri_COMPRESS "'><method>zlib</method></compress>", sizeof(uri_COMPRESS)-1 + 51, NULL, NULL), 0); s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/env.c���������������������������������������������������������������������0000664�0000000�0000000�00000003742�12614627753�0016173�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" sx_env_t sx_env_new(void) { sx_env_t env; env = (sx_env_t) calloc(1, sizeof(struct _sx_env_st)); return env; } void sx_env_free(sx_env_t env) { int i; assert((int) (env != NULL)); /* !!! usage counts */ for(i = 0; i < env->nplugins; i++) { if(env->plugins[i]->unload != NULL) (env->plugins[i]->unload)(env->plugins[i]); free(env->plugins[i]); } free(env->plugins); free(env); } sx_plugin_t sx_env_plugin(sx_env_t env, sx_plugin_init_t init, ...) { sx_plugin_t p; int ret; va_list args; assert((int) (env != NULL)); assert((int) (init != NULL)); va_start(args, init); p = (sx_plugin_t) calloc(1, sizeof(struct _sx_plugin_st)); p->env = env; p->index = env->nplugins; ret = (init)(env, p, args); va_end(args); if(ret != 0) { free(p); return NULL; } env->plugins = (sx_plugin_t *) realloc(env->plugins, sizeof(sx_plugin_t) * (env->nplugins + 1)); env->plugins[env->nplugins] = p; env->nplugins++; _sx_debug(ZONE, "plugin initialised (index %d)", p->index); return p; } ������������������������������jabberd2-jabberd-2.3.4/sx/error.c�������������������������������������������������������������������0000664�0000000�0000000�00000012111�12614627753�0016522�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" /** if you change these, reflect your changes in the defines in sx.h */ static const char *_stream_errors[] = { "bad-format", "bad-namespace-prefix", "conflict", "connection-timeout", "host-gone", "host-unknown", "improper-addressing", "internal-server-error", "invalid-from", "invalid-id", "invalid-namespace", "invalid-xml", "not-authorized", "policy-violation", "remote-connection-failed", "restricted-xml", "resource-constraint", "see-other-host", "system-shutdown", "undefined-condition", "unsupported-encoding", "unsupported-stanza-type", "unsupported-version", "xml-not-well-formed", NULL }; /** send an error */ void _sx_error(sx_t s, int err, const char *text) { int len = 0; sx_buf_t buf; /* open stream if not already */ if(s->state < state_STREAM) { if (s->flags & SX_WEBSOCKET_WRAPPER) jqueue_push(s->wbufq, _sx_buffer_new("<open xmlns='" uri_XFRAMING "' version='1.0' />", sizeof(uri_XFRAMING) + 30, NULL, NULL), 0); else jqueue_push(s->wbufq, _sx_buffer_new("<stream:stream xmlns:stream='" uri_STREAMS "' version='1.0'>", sizeof(uri_STREAMS) + 44, NULL, NULL), 0); } /* build the error */ len = strlen(uri_STREAMS) + strlen(uri_STREAM_ERR) + strlen(_stream_errors[err]) + 58; if(text != NULL) len += strlen(uri_STREAM_ERR) + strlen(text) + 22; buf = _sx_buffer_new(NULL, len, NULL, NULL); if(text == NULL) len = sprintf(buf->data, "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/></stream:error>", _stream_errors[err]); else len = sprintf(buf->data, "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/><text xmlns='" uri_STREAM_ERR "'>%s</text></stream:error>", _stream_errors[err], text); buf->len--; assert(len == buf->len); _sx_debug(ZONE, "prepared error: %.*s", buf->len, buf->data); jqueue_push(s->wbufq, buf, 0); /* close the stream if needed */ if(s->state < state_STREAM) { if (s->flags & SX_WEBSOCKET_WRAPPER) jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0); else jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0); } /* stuff to write */ s->want_write = 1; } void sx_error(sx_t s, int err, const char *text) { assert(s != NULL); assert(err >= 0 && err < stream_err_LAST); _sx_error(s, err, text); _sx_event(s, event_WANT_WRITE, NULL); } //** send an extended error with custom contents other than text */ // Ideally should be merged with sx_error. sx_error should permit additional content beneath the <stream:error> element, other than a <text> node. void _sx_error_extended(sx_t s, int err, const char *content) { int len = 0; sx_buf_t buf; /* build the string */ if(s->state < state_STREAM) len = strlen(uri_STREAMS) + 61; len += strlen(uri_STREAMS) + strlen(uri_STREAM_ERR) + strlen(_stream_errors[err]) + 58; if(content != NULL) len += strlen(content) + strlen(_stream_errors[err]) + 2; buf = _sx_buffer_new(NULL, len, NULL, NULL); len = 0; if(s->state < state_STREAM) len = sprintf(buf->data, "<stream:stream xmlns:stream='" uri_STREAMS "' version='1.0'>"); if(content == NULL) len += sprintf(&(buf->data[len]), "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/></stream:error>", _stream_errors[err]); else len += sprintf(&(buf->data[len]), "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'>%s</%s></stream:error>", _stream_errors[err], content, _stream_errors[err]); if(s->state < state_STREAM) len += sprintf(&(buf->data[len]), "</stream:stream>"); buf->len--; assert(len == buf->len); _sx_debug(ZONE, "prepared error: %.*s", buf->len, buf->data); /* go */ jqueue_push(s->wbufq, buf, 0); /* stuff to write */ s->want_write = 1; } void sx_error_extended(sx_t s, int err, const char *content) { assert(s != NULL); assert(err >= 0 && err < stream_err_LAST); _sx_error_extended(s, err, content); _sx_event(s, event_WANT_WRITE, NULL); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/io.c����������������������������������������������������������������������0000664�0000000�0000000�00000037040�12614627753�0016010�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" /** handler for read data */ void _sx_process_read(sx_t s, sx_buf_t buf) { sx_error_t sxe; nad_t nad; char *errstring; int i; int ns, elem; /* Note that buf->len can validly be 0 here, if we got data from the socket but the plugin didn't return anything to us (e.g. a SSL packet was split across a tcp segment boundary) */ /* count bytes read */ s->rbytes += buf->len; /* parse it */ if(XML_Parse(s->expat, buf->data, buf->len, 0) == 0) { /* only report error we haven't already */ if(!s->fail) { /* parse error */ errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat)); _sx_debug(ZONE, "XML parse error: %s, character %d: %.*s", errstring, XML_GetCurrentByteIndex(s->expat) - s->rbytes_total, buf->len, buf->data); _sx_gen_error(sxe, SX_ERR_XML_PARSE, "XML parse error", errstring); _sx_event(s, event_ERROR, (void *) &sxe); _sx_error(s, stream_err_XML_NOT_WELL_FORMED, errstring); _sx_close(s); _sx_buffer_free(buf); return; } /* !!! is this the right thing to do? we should probably set * s->fail and let the code further down handle it. */ _sx_buffer_free(buf); return; } /* check if the stanza size limit is exceeded (it wasn't reset by parser) */ if(s->rbytesmax && s->rbytes > s->rbytesmax) { /* parse error */ _sx_debug(ZONE, "maximum stanza size (%d) exceeded by reading %d bytes", s->rbytesmax, s->rbytes); errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat)); _sx_gen_error(sxe, SX_ERR_XML_PARSE, "stream read error", "Maximum stanza size exceeded"); _sx_event(s, event_ERROR, (void *) &sxe); _sx_error(s, stream_err_POLICY_VIOLATION, errstring); _sx_close(s); _sx_buffer_free(buf); return; } /* count bytes processed */ s->rbytes_total += buf->len; /* done with the buffer */ _sx_buffer_free(buf); /* process completed nads */ if(s->state >= state_STREAM) while((nad = jqueue_pull(s->rnadq)) != NULL) { int plugin_error; #ifdef SX_DEBUG const char *out; int len; nad_print(nad, 0, &out, &len); _sx_debug(ZONE, "completed nad: %.*s", len, out); #endif /* check for errors */ if(NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_STREAMS, strlen(uri_STREAMS)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "error", 5) == 0) { errstring = NULL; /* get text error description if available - XMPP 4.7.2 */ if((ns = nad_find_scoped_namespace(nad, uri_STREAM_ERR, NULL)) >= 0) if((elem = nad_find_elem(nad, 0, ns, "text", 1)) >= 0) if(NAD_CDATA_L(nad, elem) > 0) { errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, elem) + 1)); sprintf(errstring, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); } /* if not available, look for legacy error text as in <stream:error>description</stream:error> */ if (errstring == NULL && NAD_CDATA_L(nad, 0) > 0) { errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, 0) + 1)); sprintf(errstring, "%.*s", NAD_CDATA_L(nad, 0), NAD_CDATA(nad, 0)); } /* if not available, log the whole packet for debugging */ if (errstring == NULL) { const char *xml; int xlen; nad_print(nad, 0, &xml, &xlen); errstring = (char *) malloc(sizeof(char) * (xlen + 1)); sprintf(errstring, "%.*s", xlen, xml); } if(s->state < state_CLOSING) { _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", errstring); _sx_event(s, event_ERROR, (void *) &sxe); _sx_state(s, state_CLOSING); } if(errstring != NULL) free(errstring); nad_free(nad); break; } /* check for close */ if ((s->flags & SX_WEBSOCKET_WRAPPER) && NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_XFRAMING) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_XFRAMING, strlen(uri_XFRAMING)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "close", 5) == 0) { _sx_debug(ZONE, "<close/> frame @ depth %d", s->depth); s->fail = 1; break; } /* run it by the plugins */ if(_sx_chain_nad_read(s, nad) == 0) return; /* now let the plugins process the completed nad */ plugin_error = 0; if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->process != NULL) { int plugin_ret; plugin_ret = (s->env->plugins[i]->process)(s, s->env->plugins[i], nad); if(plugin_ret == 0) { plugin_error ++; break; } } /* hand it to the app */ if ((plugin_error == 0) && (s->state < state_CLOSING)) _sx_event(s, event_PACKET, (void *) nad); } /* something went wrong, bail */ if(s->fail) { _sx_close(s); return; } /* stream was closed */ if(s->depth < 0 && s->state < state_CLOSING) { /* close the stream if necessary */ if(s->state >= state_STREAM_SENT) { if (s->flags & SX_WEBSOCKET_WRAPPER) jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0); else jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0); s->want_write = 1; } _sx_state(s, state_CLOSING); return; } } /** we can read */ int sx_can_read(sx_t s) { sx_buf_t in, out; int read, ret; assert((int) (s != NULL)); /* do we care? */ if(!s->want_read && s->state < state_CLOSING) return 0; /* no more thanks */ _sx_debug(ZONE, "%d ready for reading", s->tag); /* new buffer */ in = _sx_buffer_new(NULL, 1024, NULL, NULL); /* get them to read stuff */ read = _sx_event(s, event_READ, (void *) in); /* bail if something went wrong */ if(read < 0) { _sx_buffer_free(in); s->want_read = 0; s->want_write = 0; return 0; } if(read == 0) { /* nothing to read * should never happen because we did get a read event, * thus there is something to read, or error handled * via (read < 0) block before (errors return -1) */ _sx_debug(ZONE, "decoded 0 bytes read data - this should not happen"); _sx_buffer_free(in); } else { _sx_debug(ZONE, "passed %d read bytes", in->len); /* make a copy for processing */ out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg); /* run it by the plugins */ ret = _sx_chain_io_read(s, out); if(ret <= 0) { if(ret < 0) { /* permanent failure, its all over */ /* !!! shut down */ s->want_read = s->want_write = 0; } _sx_buffer_free(in); _sx_buffer_free(out); /* done */ if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL); return s->want_read; } _sx_buffer_free(in); _sx_debug(ZONE, "decoded read data (%d bytes): %.*s", out->len, out->len, out->data); /* into the parser with you */ _sx_process_read(s, out); } /* if we've written everything, and we're closed, then inform the app it can kill us */ if(s->want_write == 0 && s->state == state_CLOSING) { _sx_state(s, state_CLOSED); _sx_event(s, event_CLOSED, NULL); return 0; } if(s->state == state_CLOSED) return 0; if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL); return s->want_read; } /** we can write */ static int _sx_get_pending_write(sx_t s) { sx_buf_t in, out; int ret; assert(s != NULL); if (s->wbufpending != NULL) { /* there's already a pending buffer ready to write */ return 0; } /* get the first buffer off the queue */ in = jqueue_pull(s->wbufq); if(in == NULL) { /* if there was a write event, and something is interested, we still have to tell the plugins */ in = _sx_buffer_new(NULL, 0, NULL, NULL); } /* if there's more to write, we want to make sure we get it */ s->want_write = jqueue_size(s->wbufq); /* make a copy for processing */ out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg); _sx_debug(ZONE, "encoding %d bytes for writing: %.*s", in->len, in->len, in->data); /* run it by the plugins */ ret = _sx_chain_io_write(s, out); if(ret <= 0) { /* TODO/!!!: Are we leaking the 'out' buffer here? How about the 'in' buffer? */ if(ret == -1) { /* temporary failure, push it back on the queue */ jqueue_push(s->wbufq, in, (s->wbufq->front != NULL) ? s->wbufq->front->priority : 0); s->want_write = 1; } else if(ret == -2) { /* permanent failure, its all over */ /* !!! shut down */ s->want_read = s->want_write = 0; return -1; } /* done */ return 0; } _sx_buffer_free(in); if (out->len == 0) /* if there's nothing to write, then we're done */ _sx_buffer_free(out); else s->wbufpending = out; return 0; } int sx_can_write(sx_t s) { sx_buf_t out; int ret, written; assert((int) (s != NULL)); /* do we care? */ if(!s->want_write && s->state < state_CLOSING) return 0; /* no more thanks */ _sx_debug(ZONE, "%d ready for writing", s->tag); ret = _sx_get_pending_write(s); if (ret < 0) { /* fatal error */ _sx_debug(ZONE, "fatal error after attempt to write on fd %d", s->tag); /* permanent error so inform the app it can kill us */ sx_kill(s); return 0; } /* if there's nothing to write, then we're done */ if(s->wbufpending == NULL) { if(s->want_read) _sx_event(s, event_WANT_READ, NULL); return s->want_write; } out = s->wbufpending; s->wbufpending = NULL; /* get the callback to do the write */ _sx_debug(ZONE, "handing app %d bytes to write", out->len); written = _sx_event(s, event_WRITE, (void *) out); if(written < 0) { /* bail if something went wrong */ _sx_buffer_free(out); s->want_read = 0; s->want_write = 0; return 0; } else if(written < out->len) { /* if not fully written, this buffer is still pending */ out->len -= written; out->data += written; s->wbufpending = out; s->want_write ++; } else { /* notify */ if(out->notify != NULL) (out->notify)(s, out->notify_arg); /* done with this */ _sx_buffer_free(out); } /* if we've written everything, and we're closed, then inform the app it can kill us */ if(s->want_write == 0 && s->state == state_CLOSING) { _sx_state(s, state_CLOSED); _sx_event(s, event_CLOSED, NULL); return 0; } if(s->state == state_CLOSED) return 0; if(s->want_read) _sx_event(s, event_WANT_READ, NULL); return s->want_write; } /** send a new nad out */ int _sx_nad_write(sx_t s, nad_t nad, int elem) { const char *out; int len; /* silently drop it if we're closing or closed */ if(s->state >= state_CLOSING) { log_debug(ZONE, "stream closed, dropping outgoing packet"); nad_free(nad); return 1; } /* run it through the plugins */ if(_sx_chain_nad_write(s, nad, elem) == 0) return 1; /* serialise it */ nad_print(nad, elem, &out, &len); _sx_debug(ZONE, "queueing for write: %.*s", len, out); /* ready to go */ jqueue_push(s->wbufq, _sx_buffer_new(out, len, NULL, NULL), 0); nad_free(nad); /* things to write */ s->want_write = 1; return 0; } /** app version */ void sx_nad_write_elem(sx_t s, nad_t nad, int elem) { assert((int) (s != NULL)); assert((int) (nad != NULL)); if(_sx_nad_write(s, nad, elem) == 1) return; /* things to write */ s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); if(s->want_read) _sx_event(s, event_WANT_READ, NULL); } /** send raw data out */ int _sx_raw_write(sx_t s, const char *buf, int len) { /* siltently drop it if we're closing or closed */ if(s->state >= state_CLOSING) { log_debug(ZONE, "stream closed, dropping outgoing raw data"); return 1; } _sx_debug(ZONE, "queuing for write: %.*s", len, buf); /* ready to go */ jqueue_push(s->wbufq, _sx_buffer_new(buf, len, NULL, NULL), 0); /* things to write */ s->want_write = 1; return 0; } /** app version */ void sx_raw_write(sx_t s, const char *buf, int len) { assert((int) (s != NULL)); assert((int) (buf != NULL)); assert(len); if(_sx_raw_write(s, buf, len) == 1) return; /* things to write */ s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); if(s->want_read) _sx_event(s, event_WANT_READ, NULL); } /** close a stream */ void _sx_close(sx_t s) { /* close the stream if necessary */ if(s->state >= state_STREAM_SENT) { if (s->flags & SX_WEBSOCKET_WRAPPER) jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0); else jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0); s->want_write = 1; } _sx_state(s, state_CLOSING); } void sx_close(sx_t s) { assert((int) (s != NULL)); if(s->state >= state_CLOSING) return; if(s->state >= state_STREAM_SENT && s->state < state_CLOSING) { _sx_close(s); _sx_event(s, event_WANT_WRITE, NULL); } else { _sx_state(s, state_CLOSED); _sx_event(s, event_CLOSED, NULL); } } void sx_kill(sx_t s) { assert((int) (s != NULL)); _sx_state(s, state_CLOSED); _sx_event(s, event_CLOSED, NULL); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/plugins.h�����������������������������������������������������������������0000664�0000000�0000000�00000013067�12614627753�0017072�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2007 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris, Tomasz Sterna * * 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, MA02111-1307USA */ #ifndef INCL_SX_PLUGINS_H #define INCL_SX_PLUGINS_H /** sx stream flags */ #define SX_SSL_WRAPPER (1<<0) /** SSL wrapper on legacy 5223 port */ #define SX_SSL_STARTTLS_OFFER (1<<1) /** don't offer starttls without this */ #define SX_SSL_STARTTLS_REQUIRE (1<<2) /** starttls is required on the stream */ #define SX_SASL_OFFER (1<<3) /** don't offer sasl without this */ #define SX_COMPRESS_WRAPPER (1<<4) #define SX_COMPRESS_OFFER (1<<5) #define SX_WEBSOCKET_WRAPPER (1<<6) /** indicates stream over WebSocket connection */ /** magic numbers, so plugins can find each other */ #define SX_SSL_MAGIC (0x01) /** error codes */ /* prefix 0x0. is taken by sx core errors in sx.h */ #define SX_ERR_SSL (0x010) #define SX_ERR_STARTTLS_FAILURE (0x011) #define SX_ERR_COMPRESS (0x020) #define SX_ERR_COMPRESS_FAILURE (0x021) #define SX_CONN_EXTERNAL_ID_MAX_COUNT 8 #ifdef __cplusplus extern "C" { #endif /* SSL plugin */ #ifdef HAVE_SSL #include <openssl/md5.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/x509v3.h> /** init function */ JABBERD2_API int sx_ssl_init(sx_env_t env, sx_plugin_t p, va_list args); /** add cert function */ JABBERD2_API int sx_ssl_server_addcert(sx_plugin_t p, const char *name, const char *pemfile, const char *cachain, int mode, const char *private_key_password, const char *ciphers); /** trigger for client starttls */ JABBERD2_API int sx_ssl_client_starttls(sx_plugin_t p, sx_t s, const char *pemfile, const char *private_key_password); /* previous states */ #define SX_SSL_STATE_NONE (0) #define SX_SSL_STATE_WANT_READ (1) #define SX_SSL_STATE_WANT_WRITE (2) #define SX_SSL_STATE_ERROR (3) /** a single conn */ typedef struct _sx_ssl_conn_st { /* id and ssf for sasl external auth */ char *external_id[SX_CONN_EXTERNAL_ID_MAX_COUNT]; SSL *ssl; BIO *wbio, *rbio; jqueue_t wq; int last_state; char *pemfile; char *private_key_password; } *_sx_ssl_conn_t; #endif /* HAVE_SSL */ /* SASL plugin */ /** init function */ JABBERD2_API int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args); /** the callback function */ typedef int (*sx_sasl_callback_t)(int cb, void *arg, void **res, sx_t s, void *cbarg); /* callbacks */ #define sx_sasl_cb_GET_REALM (0x00) #define sx_sasl_cb_GET_PASS (0x01) #define sx_sasl_cb_CHECK_PASS (0x02) #define sx_sasl_cb_CHECK_AUTHZID (0x03) #define sx_sasl_cb_GEN_AUTHZID (0x04) #define sx_sasl_cb_CHECK_MECH (0x05) /* error codes */ #define sx_sasl_ret_OK (0) #define sx_sasl_ret_FAIL (1) /** trigger for client auth */ JABBERD2_API int sx_sasl_auth(sx_plugin_t p, sx_t s, const char *appname, const char *mech, const char *user, const char *pass); /* for passing auth data to callback */ typedef struct sx_sasl_creds_st { const char *authnid; const char *realm; const char *authzid; const char *pass; } *sx_sasl_creds_t; /* Stream Compression plugin */ #ifdef HAVE_LIBZ #include <zlib.h> /** init function */ JABBERD2_API int sx_compress_init(sx_env_t env, sx_plugin_t p, va_list args); /* allocation chunk for decompression */ #define SX_COMPRESS_CHUNK 16384 /** a single conn */ typedef struct _sx_compress_conn_st { /* zlib streams for deflate() and inflate() */ z_stream wstrm, rstrm; /* buffers for compressed and decompressed data */ sx_buf_t wbuf, rbuf; } *_sx_compress_conn_t; #endif /* HAVE_LIBZ */ /* Stanza Acknowledgements plugin */ /** init function */ JABBERD2_API int sx_ack_init(sx_env_t env, sx_plugin_t p, va_list args); /* websocket wrapper plugin */ //#ifdef USE_WEBSOCKET #include <http_parser.h> #include <util/util.h> JABBERD2_API int sx_websocket_init(sx_env_t env, sx_plugin_t p, va_list args); /** websocket state */ typedef enum { websocket_PRE, websocket_HEADERS, /* parsing HTTP headers */ websocket_ACTIVE, /* active websocket connection */ websocket_CLOSING /* shutdown in progress */ } _sx_websocket_state_t; /** a single conn */ typedef struct _sx_websocket_conn_st { http_parser parser; _sx_websocket_state_t state; int header_value; pool_t p; spool field, value; xht headers; void *frame; } *_sx_websocket_conn_t; //#endif #ifdef __cplusplus } #endif #endif /* INCL_SX_PLUGINS_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/sasl.c��������������������������������������������������������������������0000664�0000000�0000000�00000077556�12614627753�0016363�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* SASL authentication handler */ #include "sx.h" #include "sasl.h" #include <gsasl.h> #include <gsasl-mech.h> #include <string.h> /** our sasl application context */ typedef struct _sx_sasl_st { char *appname; Gsasl *gsasl_ctx; sx_sasl_callback_t cb; void *cbarg; char *ext_id[SX_CONN_EXTERNAL_ID_MAX_COUNT]; } *_sx_sasl_t; /** our sasl per session context */ typedef struct _sx_sasl_sess_st { sx_t s; _sx_sasl_t ctx; } *_sx_sasl_sess_t; /** utility: generate a success nad */ static nad_t _sx_sasl_success(sx_t s, const char *data, int dlen) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "success", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad; } /** utility: generate a failure nad */ static nad_t _sx_sasl_failure(sx_t s, const char *err) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "failure", 0); if(err != NULL) nad_append_elem(nad, ns, err, 1); return nad; } /** utility: generate a challenge nad */ static nad_t _sx_sasl_challenge(sx_t s, const char *data, int dlen) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "challenge", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad; } /** utility: generate a response nad */ static nad_t _sx_sasl_response(sx_t s, const char *data, int dlen) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "response", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad; } /** utility: generate an abort nad */ static nad_t _sx_sasl_abort(sx_t s) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "abort", 0); return nad; } static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { sx_error_t sxe; size_t len; int ret; char *out; Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; _sx_debug(ZONE, "doing sasl encode"); /* encode the output */ ret = gsasl_encode(sd, buf->data, buf->len, &out, &len); if (ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_encode failed (%d): %s", ret, gsasl_strerror (ret)); /* Fatal error */ _sx_gen_error(sxe, SX_ERR_AUTH, "SASL Stream encoding failed", (char*) gsasl_strerror (ret)); _sx_event(s, event_ERROR, (void *) &sxe); return -1; } /* replace the buffer */ _sx_buffer_set(buf, out, len, NULL); free(out); _sx_debug(ZONE, "%d bytes encoded for sasl channel", buf->len); return 1; } static int _sx_sasl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { sx_error_t sxe; size_t len; int ret; char *out; Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; _sx_debug(ZONE, "doing sasl decode"); /* decode the input */ ret = gsasl_decode(sd, buf->data, buf->len, &out, &len); if (ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_decode failed (%d): %s", ret, gsasl_strerror (ret)); /* Fatal error */ _sx_gen_error(sxe, SX_ERR_AUTH, "SASL Stream decoding failed", (char*) gsasl_strerror (ret)); _sx_event(s, event_ERROR, (void *) &sxe); return -1; } /* replace the buffer */ _sx_buffer_set(buf, out, len, NULL); free(out); _sx_debug(ZONE, "%d bytes decoded from sasl channel", len); return 1; } /** move the stream to the auth state */ void _sx_sasl_open(sx_t s, Gsasl_session *sd) { char *method, *authzid; const char *realm = NULL; struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; _sx_sasl_sess_t sctx = gsasl_session_hook_get(sd); _sx_sasl_t ctx = sctx->ctx; const char *mechname = gsasl_mechanism_name (sd); /* get the method */ method = (char *) malloc(sizeof(char) * (strlen(mechname) + 6)); sprintf(method, "SASL/%s", mechname); /* and the authorization identifier */ creds.authzid = gsasl_property_fast(sd, GSASL_AUTHZID); creds.authnid = gsasl_property_fast(sd, GSASL_AUTHID); creds.realm = gsasl_property_fast(sd, GSASL_REALM); if(0 && ctx && ctx->cb) { /* not supported yet */ if((ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, s, ctx->cbarg)!=sx_sasl_ret_OK) { _sx_debug(ZONE, "stream authzid: %s verification failed, not advancing to auth state", creds.authzid); free(method); return; } } else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) { creds.authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)); authzid = NULL; } else { /* override unchecked arbitrary authzid */ if(creds.realm && creds.realm[0] != '\0') { realm = creds.realm; } else { realm = s->req_to; } authzid = (char *) malloc(sizeof(char) * (strlen(creds.authnid) + strlen(realm) + 2)); sprintf(authzid, "%s@%s", creds.authnid, realm); creds.authzid = authzid; } /* proceed stream to authenticated state */ sx_auth(s, method, creds.authzid); free(method); if(authzid) free(authzid); } /** make the stream authenticated second time round */ static void _sx_sasl_stream(sx_t s, sx_plugin_t p) { Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; /* do nothing the first time */ if(sd == NULL) return; /* are we auth'd? */ if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) { _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet"); return; } /* otherwise, its auth time */ _sx_sasl_open(s, sd); } static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; int nmechs, ret; char *mechs, *mech, *c; if(s->type != type_SERVER) return; if(sd != NULL) { _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms"); return; } if(!(s->flags & SX_SASL_OFFER)) { _sx_debug(ZONE, "application didn't ask us to offer sasl, so we won't"); return; } #ifdef HAVE_SSL if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms"); return; } #endif _sx_debug(ZONE, "offering sasl mechanisms"); ret = gsasl_server_mechlist(ctx->gsasl_ctx, &mechs); if(ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_server_mechlist failed (%d): %s, not offering sasl for this conn", ret, gsasl_strerror (ret)); return; } mech = mechs; nmechs = 0; while(mech != NULL) { c = strchr(mech, ' '); if(c != NULL) *c = '\0'; if ((ctx->cb)(sx_sasl_cb_CHECK_MECH, mech, NULL, s, ctx->cbarg)==sx_sasl_ret_OK) { if (nmechs == 0) { int ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "mechanisms", 1); } _sx_debug(ZONE, "offering mechanism: %s", mech); nad_append_elem(nad, -1 /*ns*/, "mechanism", 2); nad_append_cdata(nad, mech, strlen(mech), 3); nmechs++; } if(c == NULL) mech = NULL; else mech = ++c; } free(mechs); } /** auth done, restart the stream */ static void _sx_sasl_notify_success(sx_t s, void *arg) { sx_plugin_t p = (sx_plugin_t) arg; _sx_chain_io_plugin(s, p); _sx_debug(ZONE, "auth completed, resetting"); _sx_reset(s); sx_server_init(s, s->flags); } /** process handshake packets from the client */ static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, Gsasl_session *sd, const char *mech, const char *in, int inlen) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; _sx_sasl_sess_t sctx = NULL; char *buf = NULL, *out = NULL, *realm = NULL, **ext_id; char hostname[256]; int ret; #ifdef HAVE_SSL int i; #endif size_t buflen, outlen; if(mech != NULL) { _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech); if(!gsasl_server_support_p(ctx->gsasl_ctx, mech)) { _sx_debug(ZONE, "client requested mechanism (%s) that we didn't offer", mech); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); return; } /* startup */ ret = gsasl_server_start(ctx->gsasl_ctx, mech, &sd); if(ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0); return; } /* get the realm */ if(ctx->cb != NULL) (ctx->cb)(sx_sasl_cb_GET_REALM, NULL, (void **) &realm, s, ctx->cbarg); /* cleanup any existing session context */ sctx = gsasl_session_hook_get(sd); if (sctx != NULL) free(sctx); /* allocate and initialize our per session context */ sctx = (_sx_sasl_sess_t) calloc(1, sizeof(struct _sx_sasl_sess_st)); sctx->s = s; sctx->ctx = ctx; gsasl_session_hook_set(sd, (void *) sctx); gsasl_property_set(sd, GSASL_SERVICE, ctx->appname); gsasl_property_set(sd, GSASL_REALM, realm); /* get hostname */ hostname[0] = '\0'; gethostname(hostname, 256); hostname[255] = '\0'; gsasl_property_set(sd, GSASL_HOSTNAME, hostname); /* get EXTERNAL data from the ssl plugin */ ext_id = NULL; #ifdef HAVE_SSL for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->magic == SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL) ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id; if (ext_id != NULL) { //_sx_debug(ZONE, "sasl context ext id '%s'", ext_id); /* if there is, store it for later */ for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) if (ext_id[i] != NULL) { ctx->ext_id[i] = strdup(ext_id[i]); } else { ctx->ext_id[i] = NULL; break; } } #endif _sx_debug(ZONE, "sasl context initialised for %d", s->tag); s->plugin_data[p->index] = (void *) sd; if(strcmp(mech, "ANONYMOUS") == 0) { /* * special case for SASL ANONYMOUS: ignore the initial * response provided by the client and generate a random * authid to use as the jid node for the user, as * specified in XEP-0175 */ (ctx->cb)(sx_sasl_cb_GEN_AUTHZID, NULL, (void **)&out, s, ctx->cbarg); buf = strdup(out); buflen = strlen(buf); } else if (strstr(in, "<") != NULL && strncmp(in, "=", strstr(in, "<") - in ) == 0) { /* XXX The above check is hackish, but `in` is just weird */ /* This is a special case for SASL External c2s. See XEP-0178 */ _sx_debug(ZONE, "gsasl auth string is empty"); buf = strdup(""); buflen = strlen(buf); } else { /* decode and process */ ret = gsasl_base64_from(in, inlen, &buf, &buflen); if (ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INCORRECT_ENCODING), 0); if(buf != NULL) free(buf); return; } } ret = gsasl_step(sd, buf, buflen, &out, &outlen); if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) { _sx_debug(ZONE, "gsasl_step failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MALFORMED_REQUEST), 0); if(out != NULL) free(out); if(buf != NULL) free(buf); return; } } else { /* decode and process */ ret = gsasl_base64_from(in, inlen, &buf, &buflen); if (ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INCORRECT_ENCODING), 0); return; } if(!sd) { _sx_debug(ZONE, "response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MECH_TOO_WEAK), 0); if(buf != NULL) free(buf); return; } _sx_debug(ZONE, "response from client (decoded: %.*s)", buflen, buf); ret = gsasl_step(sd, buf, buflen, &out, &outlen); } if(buf != NULL) free(buf); /* auth completed */ if(ret == GSASL_OK) { _sx_debug(ZONE, "sasl handshake completed"); /* encode the leftover response */ ret = gsasl_base64_to(out, outlen, &buf, &buflen); if (ret == GSASL_OK) { /* send success */ _sx_nad_write(s, _sx_sasl_success(s, buf, buflen), 0); free(buf); /* set a notify on the success nad buffer */ ((sx_buf_t) s->wbufq->front->data)->notify = _sx_sasl_notify_success; ((sx_buf_t) s->wbufq->front->data)->notify_arg = (void *) p; } else { _sx_debug(ZONE, "gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INCORRECT_ENCODING), 0); if(buf != NULL) free(buf); } if(out != NULL) free(out); return; } /* in progress */ if(ret == GSASL_NEEDS_MORE) { _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out); /* encode the challenge */ ret = gsasl_base64_to(out, outlen, &buf, &buflen); if (ret == GSASL_OK) { _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0); free(buf); } else { _sx_debug(ZONE, "gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INCORRECT_ENCODING), 0); if(buf != NULL) free(buf); } if(out != NULL) free(out); return; } if(out != NULL) free(out); /* its over */ _sx_debug(ZONE, "sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret)); /* !!! TODO XXX check ret and flag error appropriately */ _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MALFORMED_REQUEST), 0); } /** process handshake packets from the server */ static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, Gsasl_session *sd, const char *in, int inlen) { char *buf = NULL, *out = NULL; size_t buflen, outlen; int ret; _sx_debug(ZONE, "data from client"); /* decode the response */ ret = gsasl_base64_from(in, inlen, &buf, &buflen); if (ret == GSASL_OK) { _sx_debug(ZONE, "decoded data: %.*s", buflen, buf); /* process the data */ ret = gsasl_step(sd, buf, buflen, &out, &outlen); if(buf != NULL) free(buf); buf = NULL; /* in progress */ if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) { _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out); /* encode the response */ ret = gsasl_base64_to(out, outlen, &buf, &buflen); if (ret == GSASL_OK) { _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0); } if(out != NULL) free(out); if(buf != NULL) free(buf); return; } } if(out != NULL) free(out); if(buf != NULL) free(buf); /* its over */ _sx_debug(ZONE, "sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret)); _sx_nad_write(s, _sx_sasl_abort(s), 0); } /** main nad processor */ static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) { Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; int attr; char mech[128]; sx_error_t sxe; int flags; char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; /* only want sasl packets */ if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_SASL) || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_SASL, strlen(uri_SASL)) != 0) return 1; /* quietly drop it if sasl is disabled, or if not ready */ if(s->state != state_STREAM) { _sx_debug(ZONE, "not correct state for sasl, ignoring"); nad_free(nad); return 0; } /* packets from the client */ if(s->type == type_SERVER) { if(!(s->flags & SX_SASL_OFFER)) { _sx_debug(ZONE, "they tried to do sasl, but we never offered it, ignoring"); nad_free(nad); return 0; } #ifdef HAVE_SSL if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { _sx_debug(ZONE, "they tried to do sasl, but they have to do starttls first, ignoring"); nad_free(nad); return 0; } #endif /* auth */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp("auth", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* require mechanism */ if((attr = nad_find_attr(nad, 0, -1, "mechanism", NULL)) < 0) { _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); nad_free(nad); return 0; } /* extract */ snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); /* go */ _sx_sasl_client_process(s, p, sd, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* response */ else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ _sx_sasl_client_process(s, p, sd, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* abort */ else if(NAD_ENAME_L(nad, 0) == 5 && strncmp("abort", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { _sx_debug(ZONE, "sasl handshake aborted"); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_ABORTED), 0); nad_free(nad); return 0; } } /* packets from the server */ else if(s->type == type_CLIENT) { if(sd == NULL) { _sx_debug(ZONE, "got sasl client packets, but they never started sasl, ignoring"); nad_free(nad); return 0; } /* challenge */ if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ _sx_sasl_server_process(s, p, sd, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* success */ else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("success", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { _sx_debug(ZONE, "sasl handshake completed, resetting"); nad_free(nad); /* save interesting bits */ flags = s->flags; if(s->ns != NULL) ns = strdup(s->ns); if(s->req_to != NULL) to = strdup(s->req_to); if(s->req_from != NULL) from = strdup(s->req_from); if(s->req_version != NULL) version = strdup(s->req_version); /* reset state */ _sx_reset(s); _sx_debug(ZONE, "restarting stream with sasl layer established"); /* second time round */ sx_client_init(s, flags, ns, to, from, version); /* free bits */ if(ns != NULL) free(ns); if(to != NULL) free(to); if(from != NULL) free(from); if(version != NULL) free(version); return 0; } /* failure */ else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("failure", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* fire the error */ _sx_gen_error(sxe, SX_ERR_AUTH, "Authentication failed", NULL); _sx_event(s, event_ERROR, (void *) &sxe); /* cleanup */ gsasl_finish(sd); s->plugin_data[p->index] = NULL; nad_free(nad); return 0; } } /* invalid sasl command, quietly drop it */ _sx_debug(ZONE, "unknown sasl command '%.*s', ignoring", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } /** cleanup */ static void _sx_sasl_free(sx_t s, sx_plugin_t p) { Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; _sx_sasl_sess_t sctx; if(sd == NULL) return; _sx_debug(ZONE, "cleaning up conn state"); /* we need to clean up our per session context but keep sasl ctx */ sctx = gsasl_session_hook_get(sd); if (sctx != NULL){ free(sctx); gsasl_session_hook_set(sd, (void *) NULL); } gsasl_finish(sd); s->plugin_data[p->index] = NULL; } static int _sx_sasl_gsasl_callback(Gsasl *gsasl_ctx, Gsasl_session *sd, Gsasl_property prop) { _sx_sasl_sess_t sctx = gsasl_session_hook_get(sd); _sx_sasl_t ctx = NULL; struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; char *value, *node, *host; int len, i; /* * session hook data is not always available while its being set up, * also not needed in many of the cases below. */ if(sctx != NULL) { ctx = sctx->ctx; } _sx_debug(ZONE, "in _sx_sasl_gsasl_callback, property: %d", prop); switch(prop) { case GSASL_PASSWORD: /* GSASL_AUTHID, GSASL_AUTHZID, GSASL_REALM */ assert((ctx->cb != NULL)); creds.authnid = gsasl_property_fast(sd, GSASL_AUTHID); creds.realm = gsasl_property_fast(sd, GSASL_REALM); if(!creds.authnid) return GSASL_NO_AUTHID; if(!creds.realm) return GSASL_NO_AUTHZID; if((ctx->cb)(sx_sasl_cb_GET_PASS, &creds, (void **)&value, sctx->s, ctx->cbarg) == sx_sasl_ret_OK) { gsasl_property_set(sd, GSASL_PASSWORD, value); } return GSASL_NEEDS_MORE; case GSASL_SERVICE: gsasl_property_set(sd, GSASL_SERVICE, "xmpp"); return GSASL_OK; case GSASL_HOSTNAME: { char hostname[256]; /* get hostname */ hostname[0] = '\0'; gethostname(hostname, 256); hostname[255] = '\0'; gsasl_property_set(sd, GSASL_HOSTNAME, hostname); } return GSASL_OK; case GSASL_VALIDATE_SIMPLE: /* GSASL_AUTHID, GSASL_AUTHZID, GSASL_PASSWORD */ assert((ctx->cb != NULL)); creds.authnid = gsasl_property_fast(sd, GSASL_AUTHID); creds.realm = gsasl_property_fast(sd, GSASL_REALM); creds.pass = gsasl_property_fast(sd, GSASL_PASSWORD); if(!creds.authnid) return GSASL_NO_AUTHID; if(!creds.realm) return GSASL_NO_AUTHZID; if(!creds.pass) return GSASL_NO_PASSWORD; if((ctx->cb)(sx_sasl_cb_CHECK_PASS, &creds, NULL, sctx->s, ctx->cbarg) == sx_sasl_ret_OK) return GSASL_OK; else return GSASL_AUTHENTICATION_ERROR; case GSASL_VALIDATE_GSSAPI: /* GSASL_AUTHZID, GSASL_GSSAPI_DISPLAY_NAME */ creds.authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME); if(!creds.authnid) return GSASL_NO_AUTHID; creds.authzid = gsasl_property_fast(sd, GSASL_AUTHZID); if(!creds.authzid) return GSASL_NO_AUTHZID; gsasl_property_set(sd, GSASL_AUTHID, creds.authnid); return GSASL_OK; case GSASL_VALIDATE_ANONYMOUS: /* GSASL_ANONYMOUS_TOKEN */ creds.authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN); if(!creds.authnid) return GSASL_NO_ANONYMOUS_TOKEN; /* set token as authid for later use */ gsasl_property_set(sd, GSASL_AUTHID, creds.authnid); return GSASL_OK; case GSASL_VALIDATE_EXTERNAL: /* GSASL_AUTHID */ creds.authzid = gsasl_property_fast(sd, GSASL_AUTHZID); _sx_debug(ZONE, "sasl external"); _sx_debug(ZONE, "sasl creds.authzid is '%s'", creds.authzid); for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) { if (ctx->ext_id[i] == NULL) break; _sx_debug(ZONE, "sasl ext_id(%d) is '%s'", i, ctx->ext_id[i]); /* XXX hackish.. detect c2s by existance of @ */ value = strstr(ctx->ext_id[i], "@"); if(value == NULL && creds.authzid != NULL && strcmp(ctx->ext_id[i], creds.authzid) == 0) { // s2s connection and it's valid /* TODO Handle wildcards and other thigs from XEP-0178 */ _sx_debug(ZONE, "sasl ctx->ext_id doesn't have '@' in it. Assuming s2s"); return GSASL_OK; } if(value != NULL && ((creds.authzid != NULL && strcmp(ctx->ext_id[i], creds.authzid) == 0) || (creds.authzid == NULL)) ) { // c2s connection // creds.authzid == NULL condition is from XEP-0178 '=' auth reply // This should be freed by gsasl_finish() but I'm not sure // node = authnid len = value - ctx->ext_id[i]; node = (char *) malloc(sizeof(char) * (len + 1)); // + null termination strncpy(node, ctx->ext_id[i], len); node[len] = '\0'; // null terminate the string // host = realm len = strlen(value) - 1 + 1; // - the @ + null termination host = (char *) malloc(sizeof(char) * (len)); strcpy(host, value + 1); // skip the @ gsasl_property_set(sd, GSASL_AUTHID, node); gsasl_property_set(sd, GSASL_REALM, host); return GSASL_OK; } } return GSASL_AUTHENTICATION_ERROR; default: break; } return GSASL_NO_CALLBACK; } static void _sx_sasl_unload(sx_plugin_t p) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; int i; if (ctx->gsasl_ctx != NULL) gsasl_done (ctx->gsasl_ctx); if (ctx->appname != NULL) free(ctx->appname); for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) if(ctx->ext_id[i] != NULL) free(ctx->ext_id[i]); else break; if (ctx != NULL) free(ctx); } /** args: appname, callback, cb arg */ int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) { const char *appname; sx_sasl_callback_t cb; void *cbarg; _sx_sasl_t ctx; int ret, i; _sx_debug(ZONE, "initialising sasl plugin"); appname = va_arg(args, const char *); if(appname == NULL) { _sx_debug(ZONE, "appname was NULL, failing"); return 1; } cb = va_arg(args, sx_sasl_callback_t); cbarg = va_arg(args, void *); ctx = (_sx_sasl_t) calloc(1, sizeof(struct _sx_sasl_st)); ctx->appname = strdup(appname); ctx->cb = cb; ctx->cbarg = cbarg; for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) ctx->ext_id[i] = NULL; ret = gsasl_init(&ctx->gsasl_ctx); if(ret != GSASL_OK) { _sx_debug(ZONE, "couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret)); free(ctx); return 1; } gsasl_callback_set (ctx->gsasl_ctx, &_sx_sasl_gsasl_callback); _sx_debug(ZONE, "sasl context initialised"); p->private = (void *) ctx; p->unload = _sx_sasl_unload; p->wio = _sx_sasl_wio; p->rio = _sx_sasl_rio; p->stream = _sx_sasl_stream; p->features = _sx_sasl_features; p->process = _sx_sasl_process; p->free = _sx_sasl_free; return 0; } /** kick off the auth handshake */ int sx_sasl_auth(sx_plugin_t p, sx_t s, const char *appname, const char *mech, const char *user, const char *pass) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; _sx_sasl_sess_t sctx = NULL; Gsasl_session *sd; char *buf = NULL, *out = NULL; char hostname[256]; int ret, ns; size_t buflen, outlen; nad_t nad; assert((p != NULL)); assert((s != NULL)); assert((appname != NULL)); assert((mech != NULL)); assert((user != NULL)); assert((pass != NULL)); if(s->type != type_CLIENT || s->state != state_STREAM) { _sx_debug(ZONE, "need client in stream state for sasl auth"); return 1; } /* handshake start */ ret = gsasl_client_start(ctx->gsasl_ctx, mech, &sd); if(ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret)); return 1; } /* get hostname */ hostname[0] = '\0'; gethostname(hostname, 256); hostname[255] = '\0'; /* cleanup any existing session context */ sctx = gsasl_session_hook_get(sd); if (sctx != NULL) free(sctx); /* allocate and initialize our per session context */ sctx = (_sx_sasl_sess_t) calloc(1, sizeof(struct _sx_sasl_sess_st)); sctx->s = s; sctx->ctx = ctx; /* set user data in session handle */ gsasl_session_hook_set(sd, (void *) sctx); gsasl_property_set(sd, GSASL_AUTHID, user); gsasl_property_set(sd, GSASL_PASSWORD, pass); gsasl_property_set(sd, GSASL_SERVICE, appname); gsasl_property_set(sd, GSASL_HOSTNAME, hostname); /* handshake step */ ret = gsasl_step(sd, NULL, 0, &out, &outlen); if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) { _sx_debug(ZONE, "gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret)); gsasl_finish(sd); return 1; } /* save userdata */ s->plugin_data[p->index] = (void *) sd; /* in progress */ _sx_debug(ZONE, "sending auth request to server, mech '%s': %.*s", mech, outlen, out); /* encode the challenge */ ret = gsasl_base64_to(out, outlen, &buf, &buflen); if(ret != GSASL_OK) { _sx_debug(ZONE, "gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret)); gsasl_finish(sd); if (out != NULL) free(out); return 1; } free(out); /* build the nad */ nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "auth", 0); nad_append_attr(nad, -1, "mechanism", mech); if(buf != NULL) { nad_append_cdata(nad, buf, buflen, 1); free(buf); } /* its away */ sx_nad_write(s, nad); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/sasl.h��������������������������������������������������������������������0000664�0000000�0000000�00000002742�12614627753�0016351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifndef INCL_SX_SASL_H #define INCL_SX_SASL_H /* RFC 3290 defines a number of failure messages */ #define _sasl_err_ABORTED "aborted" #define _sasl_err_INCORRECT_ENCODING "incorrect-encoding" #define _sasl_err_INVALID_AUTHZID "invalid-authzid" #define _sasl_err_INVALID_MECHANISM "invalid-mechanism" #define _sasl_err_MALFORMED_REQUEST "malformed-request" #define _sasl_err_MECH_TOO_WEAK "mechanism-too-weak" #define _sasl_err_NOT_AUTHORIZED "not-authorized" #define _sasl_err_TEMPORARY_FAILURE "temporary-auth-failure" #define _sasl_err_INTERNAL_SERVER_ERROR "internal-server-error" #endif ������������������������������jabberd2-jabberd-2.3.4/sx/server.c������������������������������������������������������������������0000664�0000000�0000000�00000021317�12614627753�0016707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" static void _sx_server_notify_header(sx_t s, void *arg) { int i, ns, len; nad_t nad; const char *c; sx_buf_t buf; _sx_debug(ZONE, "stream established"); /* get the plugins to setup */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->stream != NULL) (s->env->plugins[i]->stream)(s, s->env->plugins[i]); /* bump us to stream if a plugin didn't do it already */ if(s->state < state_STREAM) { _sx_state(s, state_STREAM); _sx_event(s, event_STREAM, NULL); } /* next, build the features */ if(s->req_version != NULL && strcmp(s->req_version, "1.0") == 0) { _sx_debug(ZONE, "building features nad"); nad = nad_new(); ns = nad_add_namespace(nad, uri_STREAMS, "stream"); nad_append_elem(nad, ns, "features", 0); /* get the plugins to populate it */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->features != NULL) (s->env->plugins[i]->features)(s, s->env->plugins[i], nad); /* new buffer for the nad */ nad_print(nad, 0, &c, &len); buf = _sx_buffer_new(c, len, NULL, NULL); nad_free(nad); /* send this off too */ /* !!! should this go via wnad/rnad? */ jqueue_push(s->wbufq, buf, 0); s->want_write = 1; } /* if they sent packets before the stream was established, process the now */ if(jqueue_size(s->rnadq) > 0 && (s->state == state_STREAM || s->state == state_OPEN)) { _sx_debug(ZONE, "processing packets sent before stream, naughty them"); _sx_process_read(s, _sx_buffer_new(c, 0, NULL, NULL)); } } static void _sx_server_element_start(void *arg, const char *name, const char **atts) { sx_t s = (sx_t) arg; int tflag = 0, fflag = 0, vflag = 0, len, i, r; const char **attr; char *c, id[41]; sx_buf_t buf; sx_error_t sxe; if(s->fail) return; /* check element and namespace */ if (s->flags & SX_WEBSOCKET_WRAPPER) { i = strlen(uri_XFRAMING) + 5; r = strlen(name) < i || strncmp(name, uri_XFRAMING "|open", i) != 0 || (name[i] != '\0' && name[i] != '|'); } else { i = strlen(uri_STREAMS) + 7; r = strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|'); } if (r) { /* throw an error */ _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream open"); _sx_event(s, event_ERROR, (void *) &sxe); _sx_error(s, stream_err_BAD_FORMAT, NULL); s->fail = 1; return; } /* pull interesting things out of the header */ attr = atts; while(attr[0] != NULL) { if(!tflag && strcmp(attr[0], "to") == 0) { if(s->req_to != NULL) free((void*)s->req_to); s->req_to = strdup(attr[1]); tflag = 1; } if(!fflag && strcmp(attr[0], "from") == 0) { s->req_from = strdup(attr[1]); fflag = 1; } if(!vflag && strcmp(attr[0], "version") == 0) { s->req_version = strdup(attr[1]); vflag = 1; } attr += 2; } _sx_debug(ZONE, "stream request: to %s from %s version %s", s->req_to, s->req_from, s->req_version); /* check version */ if(s->req_version != NULL && strcmp(s->req_version, "1.0") != 0) { /* throw an error */ _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Unsupported version"); _sx_event(s, event_ERROR, (void *) &sxe); _sx_error(s, stream_err_UNSUPPORTED_VERSION, NULL); s->fail = 1; return; } /* !!! get the app to verify this stuff? */ /* bump */ _sx_state(s, state_STREAM_RECEIVED); /* response attributes */ if(s->req_to != NULL) s->res_from = strdup(s->req_to); if(s->req_from != NULL) s->res_to = strdup(s->req_from); /* Only send 1.0 version if client has indicated a stream version - c/f XMPP 4.4.1 para 4 */ if(s->req_version != NULL) s->res_version = strdup("1.0"); /* stream id */ for(i = 0; i < 40; i++) { r = (int) (36.0 * rand() / RAND_MAX); id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); } id[40] = '\0'; s->id = strdup(id); _sx_debug(ZONE, "stream id is %s", id); /* build the response */ if (s->flags & SX_WEBSOCKET_WRAPPER) { len = 55; } else { len = strlen(uri_STREAMS) + 99; } if(s->ns != NULL) len += 9 + strlen(s->ns); if(s->res_to != NULL) len += 6 + strlen(s->res_to); if(s->res_from != NULL) len += 8 + strlen(s->res_from); if(s->res_version != NULL) len += 11 + strlen(s->res_version); buf = _sx_buffer_new(NULL, len, _sx_server_notify_header, NULL); c = buf->data; if (s->flags & SX_WEBSOCKET_WRAPPER) { strcpy(c, "<open"); } else { strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'"); } if(s->ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", s->ns); } if(s->res_to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", s->res_to); } if(s->res_from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", s->res_from); } if(s->res_version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", s->res_version); } c = strchr(c, '\0'); sprintf(c, " id='%s'", id); if (s->flags & SX_WEBSOCKET_WRAPPER) { c = strchr(c, '\0'); strcpy(c, " />"); } else { c = strchr(c, '\0'); strcpy(c, ">"); } assert(buf->len == strlen(buf->data) + 1); /* post-facto overrun detection */ buf->len --; /* plugins can mess with the header too */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->header != NULL) (s->env->plugins[i]->header)(s, s->env->plugins[i], buf); _sx_debug(ZONE, "prepared stream response: %.*s", buf->len, buf->data); /* off it goes */ jqueue_push(s->wbufq, buf, 0); s->depth++; /* we're alive */ XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end); XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata); XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start); /* we have stuff to write */ s->want_write = 1; } static void _sx_server_element_end(void *arg, const char *name) { sx_t s = (sx_t) arg; if(s->fail) return; s->depth--; } /** catch the application namespace so we can get the response right */ static void _sx_server_ns_start(void *arg, const char *prefix, const char *uri) { sx_t s = (sx_t) arg; /* only want the default namespace */ if(prefix != NULL) return; /* sanity; MSXML-based clients have been known to send xmlns='' from time to time */ if(uri == NULL) return; /* sanity check (should never happen if expat is doing its job) */ if(s->ns != NULL) return; s->ns = strdup(uri); /* done */ XML_SetStartNamespaceDeclHandler(s->expat, NULL); } void sx_server_init(sx_t s, unsigned int flags) { int i; assert((int) (s != NULL)); /* can't do anything if we're alive already */ if(s->state != state_NONE) return; s->type = type_SERVER; s->flags = flags; _sx_debug(ZONE, "doing server init for sx %d %s", s->tag, _sx_flags(s)); /* plugin */ if(s->env != NULL) for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->server != NULL) (s->env->plugins[i]->server)(s, s->env->plugins[i]); /* we want to read */ XML_SetElementHandler(s->expat, (void *) _sx_server_element_start, (void *) _sx_server_element_end); XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_server_ns_start); _sx_debug(ZONE, "waiting for stream header"); s->want_read = 1; _sx_event(s, event_WANT_READ, NULL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/ssl.c���������������������������������������������������������������������0000664�0000000�0000000�00000110707�12614627753�0016204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** * this plugin implements the traditional SSL "wrappermode" streams and * STARTTLS extension documented in xmpp-core */ #include "sx.h" #include <openssl/x509_vfy.h> #include <openssl/dh.h> #include <openssl/bn.h> /* code stolen from SSL_CTX_set_verify(3) */ static int _sx_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { char buf[256]; X509 *err_cert; int err, depth; err_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); /* * Ignore errors when we can't get CRLs in the certificate */ if (!preverify_ok && err == X509_V_ERR_UNABLE_TO_GET_CRL) { _sx_debug(ZONE, "ignoring verify error:num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf); preverify_ok = 1; } /* * Retrieve the pointer to the SSL of the connection currently treated * and the application specific data stored into the SSL object. */ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); if (!preverify_ok) { _sx_debug(ZONE, "verify error:num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf); } else { _sx_debug(ZONE, "OK! depth=%d:%s", depth, buf); } /* * At this point, err contains the last verification error. We can use * it for something special */ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) { X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); _sx_debug(ZONE, "issuer= %s\n", buf); } return preverify_ok; } static int _sx_pem_passwd_callback(char *buf, int size, int rwflag, void *password) { strncpy(buf, (char *)(password), size); buf[size - 1] = '\0'; return(strlen(buf)); } #define DECLARE_sx_ssl_getparams(name, type) \ static type *sx_ssl_get_##name(const char *file) { \ type *ret; \ BIO *bio; \ if ((bio = BIO_new_file(file, "r")) == NULL) \ return NULL; \ ret = PEM_read_bio_##name(bio, NULL, NULL, NULL); \ BIO_free(bio); \ return ret; \ } DECLARE_sx_ssl_getparams(DHparams, DH) DECLARE_sx_ssl_getparams(ECPKParameters, EC_GROUP) static struct { BIGNUM *(*const get_prime)(BIGNUM *); DH *dh; const unsigned minlen; } dhparams[] = { { get_rfc3526_prime_8192, NULL, 6145 }, { get_rfc3526_prime_6144, NULL, 4097 }, { get_rfc3526_prime_4096, NULL, 3073 }, { get_rfc3526_prime_3072, NULL, 2049 }, { get_rfc3526_prime_2048, NULL, 1025 }, { get_rfc2409_prime_1024, NULL, 0 } }; static DH *sx_ssl_make_dh_params(BIGNUM *(*const get_prime)(BIGNUM *), const char *gen) { DH *dh = DH_new(); if (!dh) return NULL; dh->p = get_prime(NULL); BN_dec2bn(&dh->g, gen); if (!dh->p || !dh->g) { DH_free(dh); return NULL; } return dh; } static void sx_ssl_free_dh_params(void) { unsigned i; for (i = 0; i < sizeof(dhparams)/sizeof(dhparams[0]); i++) { DH_free(dhparams[i].dh); dhparams[i].dh = NULL; } } static DH *_sx_ssl_tmp_dh_callback(SSL *ssl, int export, int keylen) { EVP_PKEY *pkey = SSL_get_privatekey(ssl); int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; unsigned i; if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) keylen = EVP_PKEY_bits(pkey); for (i = 0; i < sizeof(dhparams)/sizeof(dhparams[0]); i++) { if (keylen >= dhparams[i].minlen) { if (dhparams[i].dh == NULL) dhparams[i].dh = sx_ssl_make_dh_params(dhparams[i].get_prime, "2"); return dhparams[i].dh; } } return NULL; } static void _sx_ssl_starttls_notify_proceed(sx_t s, void *arg) { char *to = NULL; _sx_debug(ZONE, "preparing for starttls"); /* store the destination so we can select an ssl context */ if(s->req_to != NULL) to = strdup(s->req_to); _sx_reset(s); /* restore destination */ if(s->req_to == NULL) s->req_to = to; else /* ? */ free(to); /* start listening */ sx_server_init(s, s->flags | SX_SSL_WRAPPER); } static int _sx_ssl_process(sx_t s, sx_plugin_t p, nad_t nad) { int flags; char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; sx_error_t sxe; /* not interested if we're a server and we never offered it */ if(s->type == type_SERVER && !(s->flags & SX_SSL_STARTTLS_OFFER)) return 1; /* only want tls packets */ if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_TLS) || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_TLS, strlen(uri_TLS)) != 0) return 1; /* starttls from client */ if(s->type == type_SERVER) { if(NAD_ENAME_L(nad, 0) == 8 && strncmp(NAD_ENAME(nad, 0), "starttls", 8) == 0) { nad_free(nad); /* can't go on if we've been here before */ if(s->ssf > 0) { _sx_debug(ZONE, "starttls requested on already encrypted channel, dropping packet"); return 0; } /* can't go on if we're on compressed stream */ if(s->flags & SX_COMPRESS_WRAPPER) { _sx_debug(ZONE, "starttls requested on already compressed channel, dropping packet"); return 0; } _sx_debug(ZONE, "starttls requested, setting up"); /* go ahead */ jqueue_push(s->wbufq, _sx_buffer_new("<proceed xmlns='" uri_TLS "'/>", strlen(uri_TLS) + 19, _sx_ssl_starttls_notify_proceed, NULL), 0); s->want_write = 1; /* handled the packet */ return 0; } } else if(s->type == type_CLIENT) { /* kick off the handshake */ if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "proceed", 7) == 0) { nad_free(nad); /* save interesting bits */ flags = s->flags; if(s->ns != NULL) ns = strdup(s->ns); if(s->req_to != NULL) to = strdup(s->req_to); if(s->req_from != NULL) from = strdup(s->req_from); if(s->req_version != NULL) version = strdup(s->req_version); /* reset state */ _sx_reset(s); _sx_debug(ZONE, "server ready for ssl, starting"); /* second time round */ sx_client_init(s, flags | SX_SSL_WRAPPER, ns, to, from, version); /* free bits */ if(ns != NULL) free(ns); if(to != NULL) free(to); if(from != NULL) free(from); if(version != NULL) free(version); return 0; } /* busted server */ if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "failure", 7) == 0) { nad_free(nad); /* free the pemfile arg */ if(s->plugin_data[p->index] != NULL) { if( ((_sx_ssl_conn_t)s->plugin_data[p->index])->pemfile != NULL ) free(((_sx_ssl_conn_t)s->plugin_data[p->index])->pemfile); if( ((_sx_ssl_conn_t)s->plugin_data[p->index])->private_key_password != NULL ) free(((_sx_ssl_conn_t)s->plugin_data[p->index])->private_key_password); free(s->plugin_data[p->index]); s->plugin_data[p->index] = NULL; } _sx_debug(ZONE, "server can't handle ssl, business as usual"); _sx_gen_error(sxe, SX_ERR_STARTTLS_FAILURE, "STARTTLS failure", "Server was unable to prepare for the TLS handshake"); _sx_event(s, event_ERROR, (void *) &sxe); return 0; } } _sx_debug(ZONE, "unknown starttls namespace element '%.*s', dropping packet", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } static void _sx_ssl_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; /* if the session is already encrypted, or the app told us not to, * or session is compressed then we don't offer anything */ if(s->state > state_STREAM || s->ssf > 0 || !(s->flags & SX_SSL_STARTTLS_OFFER) || (s->flags & SX_COMPRESS_WRAPPER)) return; _sx_debug(ZONE, "offering starttls"); ns = nad_add_namespace(nad, uri_TLS, NULL); nad_append_elem(nad, ns, "starttls", 1); if(s->flags & SX_SSL_STARTTLS_REQUIRE) nad_append_elem(nad, ns, "required", 2); } /* Extract id-on-xmppAddr from the certificate */ static void _sx_ssl_get_external_id(sx_t s, _sx_ssl_conn_t sc) { X509 *cert; X509_NAME *name; X509_NAME_ENTRY *entry; // subjectAltName parsing X509_EXTENSION *extension; STACK_OF(GENERAL_NAME) *altnames; GENERAL_NAME *altname; OTHERNAME *othername; char * buff; // new object identifiers int id_on_xmppAddr_nid; ASN1_OBJECT *id_on_xmppAddr_obj; // iterators int i, j, count, id = 0, len; /* If there's not peer cert, quit */ if ((cert = SSL_get_peer_certificate(sc->ssl) ) == NULL) return; _sx_debug(ZONE, "external_id: Got peer certificate"); /* Allocate new id-on-xmppAddr object. See rfc3921bis 15.2.1.2 */ id_on_xmppAddr_nid = OBJ_create("1.3.6.1.5.5.7.8.5", "id-on-xmppAddr", "XMPP Address Identity"); id_on_xmppAddr_obj = OBJ_nid2obj(id_on_xmppAddr_nid); _sx_debug(ZONE, "external_id: Created id-on-xmppAddr SSL object"); /* Iterate through all subjectAltName x509v3 extensions. Get id-on-xmppAddr and dDnsName */ for (i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); i != -1; i = X509_get_ext_by_NID(cert, NID_subject_alt_name, i)) { // Get this subjectAltName x509v3 extension if ((extension = X509_get_ext(cert, i)) == NULL) { _sx_debug(ZONE, "external_id: Can't get subjectAltName. Possibly malformed cert."); goto end; } // Get the collection of AltNames if ((altnames = X509V3_EXT_d2i(extension)) == NULL) { _sx_debug(ZONE, "external_id: Can't get all AltNames. Possibly malformed cert."); goto end; } /* Iterate through all altNames and get id-on-xmppAddr and dNSName */ count = sk_GENERAL_NAME_num(altnames); for (j = 0; j < count; j++) { if ((altname = sk_GENERAL_NAME_value(altnames, j)) == NULL) { _sx_debug(ZONE, "external_id: Can't get AltName. Possibly malformed cert."); goto end; } /* Check if its otherName id-on-xmppAddr */ if (altname->type == GEN_OTHERNAME && OBJ_cmp(altname->d.otherName->type_id, id_on_xmppAddr_obj) == 0) { othername = altname->d.otherName; len = ASN1_STRING_to_UTF8((unsigned char **) &buff, othername->value->value.utf8string); if (len <= 0) continue; sc->external_id[id] = (char *) malloc(sizeof(char) * (len + 1)); memcpy(sc->external_id[id], buff, len); sc->external_id[id][len] = '\0'; // just to make sure _sx_debug(ZONE, "external_id: Found(%d) subjectAltName/id-on-xmppAddr: '%s'", id, sc->external_id[id]); id++; OPENSSL_free(buff); } else if (altname->type == GEN_DNS) { len = ASN1_STRING_length(altname->d.dNSName); sc->external_id[id] = (char *) malloc(sizeof(char) * (len + 1)); memcpy(sc->external_id[id], ASN1_STRING_data(altname->d.dNSName), len); sc->external_id[id][len] = '\0'; // just to make sure _sx_debug(ZONE, "external_id: Found(%d) subjectAltName/dNSName: '%s'", id, sc->external_id[id]); id++; } /* Check if we're not out of space */ if (id == SX_CONN_EXTERNAL_ID_MAX_COUNT) { sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free); goto end; } } sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free); } /* Get CNs */ name = X509_get_subject_name(cert); for (i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); i != -1; i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) { // Get the commonName entry if ((entry = X509_NAME_get_entry(name, i)) == NULL) { _sx_debug(ZONE, "external_id: Can't get commonName(%d). Possibly malformed cert. Continuing.", i); continue; } // Get the commonName as UTF8 string len = ASN1_STRING_to_UTF8((unsigned char **) &buff, X509_NAME_ENTRY_get_data(entry)); if (len <= 0) { continue; } sc->external_id[id] = (char *) malloc(sizeof(char) * (len + 1)); memcpy(sc->external_id[id], buff, len); sc->external_id[id][len] = '\0'; // just to make sure _sx_debug(ZONE, "external_id: Found(%d) commonName: '%s'", id, sc->external_id[id]); OPENSSL_free(buff); /* Check if we're not out of space */ if (id == SX_CONN_EXTERNAL_ID_MAX_COUNT) goto end; } end: X509_free(cert); return; } static int _sx_ssl_handshake(sx_t s, _sx_ssl_conn_t sc) { int ret, err; char *errstring; sx_error_t sxe; /* work on establishing the channel */ while(!SSL_is_init_finished(sc->ssl)) { _sx_debug(ZONE, "secure channel not established, handshake in progress"); /* we can't handshake if they want to read, but there's nothing to read */ if(sc->last_state == SX_SSL_STATE_WANT_READ && BIO_pending(sc->rbio) == 0) return 0; /* more handshake */ if(s->type == type_CLIENT) ret = SSL_connect(sc->ssl); else ret = SSL_accept(sc->ssl); /* check if we're done */ if(ret == 1) { _sx_debug(ZONE, "secure channel established"); sc->last_state = SX_SSL_STATE_NONE; s->ssf = SSL_get_cipher_bits(sc->ssl, NULL); _sx_debug(ZONE, "using cipher %s (%d bits)", SSL_get_cipher_name(sc->ssl), s->ssf); _sx_ssl_get_external_id(s, sc); return 1; } /* error checking */ else if(ret <= 0) { err = SSL_get_error(sc->ssl, ret); if(err == SSL_ERROR_WANT_READ) sc->last_state = SX_SSL_STATE_WANT_READ; else if(err == SSL_ERROR_WANT_WRITE) sc->last_state = SX_SSL_STATE_WANT_WRITE; else { /* fatal error */ sc->last_state = SX_SSL_STATE_ERROR; errstring = ERR_error_string(ERR_get_error(), NULL); _sx_debug(ZONE, "openssl error: %s", errstring); /* do not throw an error if in wrapper mode and pre-stream */ if(!(s->state < state_STREAM && s->flags & SX_SSL_WRAPPER)) { _sx_gen_error(sxe, SX_ERR_SSL, "SSL handshake error", errstring); _sx_event(s, event_ERROR, (void *) &sxe); sx_error(s, stream_err_UNDEFINED_CONDITION, errstring); } sx_close(s); /* !!! drop queue */ return -1; } } } return 1; } static int _sx_ssl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_ssl_conn_t sc = (_sx_ssl_conn_t) s->plugin_data[p->index]; int est, ret, err; sx_buf_t wbuf; char *errstring; sx_error_t sxe; /* do not encrypt when error */ if(sc->last_state == SX_SSL_STATE_ERROR) return 1; _sx_debug(ZONE, "in _sx_ssl_wio"); /* queue the buffer */ if(buf->len > 0) { _sx_debug(ZONE, "queueing buffer for write"); jqueue_push(sc->wq, _sx_buffer_new(buf->data, buf->len, buf->notify, buf->notify_arg), 0); _sx_buffer_clear(buf); buf->notify = NULL; buf->notify_arg = NULL; } /* handshake */ est = _sx_ssl_handshake(s, sc); if(est < 0) return -2; /* fatal error */ /* channel established, do some real writing */ wbuf = NULL; if(est > 0 && jqueue_size(sc->wq) > 0) { _sx_debug(ZONE, "preparing queued buffer for write"); wbuf = jqueue_pull(sc->wq); ret = SSL_write(sc->ssl, wbuf->data, wbuf->len); if(ret <= 0) { /* something's wrong */ _sx_debug(ZONE, "write failed, requeuing buffer"); /* requeue the buffer */ jqueue_push(sc->wq, wbuf, (sc->wq->front != NULL) ? sc->wq->front->priority + 1 : 0); /* error checking */ err = SSL_get_error(sc->ssl, ret); if(err == SSL_ERROR_ZERO_RETURN) { /* ssl channel closed, we're done */ _sx_close(s); } if(err == SSL_ERROR_WANT_READ) { /* we'll be renegotiating next time */ _sx_debug(ZONE, "renegotiation started"); sc->last_state = SX_SSL_STATE_WANT_READ; } else { sc->last_state = SX_SSL_STATE_ERROR; /* something very bad */ errstring = ERR_error_string(ERR_get_error(), NULL); _sx_debug(ZONE, "openssl error: %s", errstring); /* do not throw an error if in wrapper mode and pre-stream */ if(!(s->state < state_STREAM && s->flags & SX_SSL_WRAPPER)) { _sx_gen_error(sxe, SX_ERR_SSL, "SSL handshake error", errstring); _sx_event(s, event_ERROR, (void *) &sxe); sx_error(s, stream_err_UNDEFINED_CONDITION, errstring); } sx_close(s); /* !!! drop queue */ return -2; /* fatal */ } } } /* prepare the buffer with stuff to write */ if(BIO_pending(sc->wbio) > 0) { int bytes_pending = BIO_pending(sc->wbio); assert(buf->len == 0); _sx_buffer_alloc_margin(buf, 0, bytes_pending); BIO_read(sc->wbio, buf->data, bytes_pending); buf->len += bytes_pending; /* restore notify and clean up */ if(wbuf != NULL) { buf->notify = wbuf->notify; buf->notify_arg = wbuf->notify_arg; _sx_buffer_free(wbuf); } _sx_debug(ZONE, "prepared %d ssl bytes for write", buf->len); } /* flag if we want to read */ if(sc->last_state == SX_SSL_STATE_WANT_READ || sc->last_state == SX_SSL_STATE_NONE) s->want_read = 1; return 1; } static int _sx_ssl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_ssl_conn_t sc = (_sx_ssl_conn_t) s->plugin_data[p->index]; int est, ret, err, pending; char *errstring; sx_error_t sxe; /* sanity */ if(sc->last_state == SX_SSL_STATE_ERROR) return -1; _sx_debug(ZONE, "in _sx_ssl_rio"); /* move the data into the ssl read buffer */ if(buf->len > 0) { _sx_debug(ZONE, "loading %d bytes into ssl read buffer", buf->len); BIO_write(sc->rbio, buf->data, buf->len); _sx_buffer_clear(buf); } /* handshake */ est = _sx_ssl_handshake(s, sc); if(est < 0) return -1; /* fatal error */ /* channel is up, slurp up the read buffer */ if(est > 0) { pending = SSL_pending(sc->ssl); if(pending == 0) pending = BIO_pending(sc->rbio); /* get it all */ while((pending = SSL_pending(sc->ssl)) > 0 || (pending = BIO_pending(sc->rbio)) > 0) { _sx_buffer_alloc_margin(buf, 0, pending); ret = SSL_read(sc->ssl, &(buf->data[buf->len]), pending); if (ret == 0) { /* ret will equal zero if the SSL stream was closed. (See the SSL_read manpage.) */ /* If the SSL Shutdown happened properly, (i.e. we got an SSL "close notify") then proccess the last packet recieved. */ if (SSL_get_shutdown(sc->ssl) == SSL_RECEIVED_SHUTDOWN) { _sx_close(s); break; } /* If the SSL stream was just closed and not shutdown, drop the last packet recieved. WARNING: This may cause clients that use SSLv2 and earlier to not log out properly. */ err = SSL_get_error(sc->ssl, ret); _sx_buffer_clear(buf); if(err == SSL_ERROR_ZERO_RETURN) { /* ssl channel closed, we're done */ _sx_close(s); } return -1; } else if(ret < 0) { /* ret will be negative if the SSL stream needs more data, or if there was a SSL error. (See the SSL_read manpage.) */ err = SSL_get_error(sc->ssl, ret); /* ssl block incomplete, need more */ if(err == SSL_ERROR_WANT_READ) { sc->last_state = SX_SSL_STATE_WANT_READ; break; } /* something's wrong */ _sx_buffer_clear(buf); /* !!! need checks for renegotiation */ sc->last_state = SX_SSL_STATE_ERROR; errstring = ERR_error_string(ERR_get_error(), NULL); _sx_debug(ZONE, "openssl error: %s", errstring); /* do not throw an error if in wrapper mode and pre-stream */ if(!(s->state < state_STREAM && s->flags & SX_SSL_WRAPPER)) { _sx_gen_error(sxe, SX_ERR_SSL, "SSL handshake error", errstring); _sx_event(s, event_ERROR, (void *) &sxe); sx_error(s, stream_err_UNDEFINED_CONDITION, errstring); } sx_close(s); /* !!! drop queue */ return -1; } buf->len += ret; } } /* flag if stuff to write */ if(BIO_pending(sc->wbio) > 0 || (est > 0 && jqueue_size(sc->wq) > 0)) s->want_write = 1; /* flag if we want to read */ if(sc->last_state == SX_SSL_STATE_WANT_READ || sc->last_state == SX_SSL_STATE_NONE) s->want_read = 1; if(buf->len == 0) return 0; return 1; } static void _sx_ssl_client(sx_t s, sx_plugin_t p) { _sx_ssl_conn_t sc; SSL_CTX *ctx; char *pemfile = NULL; int ret, i; char *pemfile_password = NULL; /* only bothering if they asked for wrappermode */ if(!(s->flags & SX_SSL_WRAPPER) || s->ssf > 0) return; _sx_debug(ZONE, "preparing for ssl connect for %d from %s", s->tag, s->req_from); /* find the ssl context for this source */ ctx = xhash_get((xht) p->private, s->req_from); if(ctx == NULL) { _sx_debug(ZONE, "using default ssl context for %d", s->tag); ctx = xhash_get((xht) p->private, "*"); } else { _sx_debug(ZONE, "using configured ssl context for %d", s->tag); } assert((int) (ctx != NULL)); sc = (_sx_ssl_conn_t) calloc(1, sizeof(struct _sx_ssl_conn_st)); /* create the buffers */ sc->rbio = BIO_new(BIO_s_mem()); sc->wbio = BIO_new(BIO_s_mem()); /* new ssl conn */ sc->ssl = SSL_new(ctx); SSL_set_bio(sc->ssl, sc->rbio, sc->wbio); SSL_set_connect_state(sc->ssl); SSL_set_options(sc->ssl, SSL_OP_NO_TICKET); #ifdef ENABLE_EXPERIMENTAL SSL_set_ssl_method(sc->ssl, TLSv1_2_client_method()); #else SSL_set_ssl_method(sc->ssl, TLSv1_client_method()); #endif /* empty external_id */ for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) sc->external_id[i] = NULL; /* alternate pemfile */ /* !!! figure out how to error correctly here - just returning will cause * us to send a normal unencrypted stream start while the server is * waiting for ClientHelo. the server will flag an error, but it won't * help the admin at all to figure out what happened */ if(s->plugin_data[p->index] != NULL) { pemfile = ((_sx_ssl_conn_t)s->plugin_data[p->index])->pemfile; pemfile_password = ((_sx_ssl_conn_t)s->plugin_data[p->index])->private_key_password; free(s->plugin_data[p->index]); s->plugin_data[p->index] = NULL; } if(pemfile != NULL) { /* load the certificate */ ret = SSL_use_certificate_file(sc->ssl, pemfile, SSL_FILETYPE_PEM); if(ret != 1) { _sx_debug(ZONE, "couldn't load alternate certificate from %s", pemfile); SSL_free(sc->ssl); free(sc); free(pemfile); return; } /* set callback giving a password for pemfile */ SSL_CTX_set_default_passwd_cb_userdata(sc->ssl->ctx, (void *)pemfile_password); SSL_CTX_set_default_passwd_cb(sc->ssl->ctx, &_sx_pem_passwd_callback); /* load the private key */ ret = SSL_use_PrivateKey_file(sc->ssl, pemfile, SSL_FILETYPE_PEM); if(ret != 1) { _sx_debug(ZONE, "couldn't load alternate private key from %s", pemfile); SSL_free(sc->ssl); free(sc); free(pemfile); return; } /* check the private key matches the certificate */ ret = SSL_check_private_key(sc->ssl); if(ret != 1) { _sx_debug(ZONE, "private key does not match certificate public key"); SSL_free(sc->ssl); free(sc); free(pemfile); return; } _sx_debug(ZONE, "loaded alternate pemfile %s", pemfile); free(pemfile); } /* buffer queue */ sc->wq = jqueue_new(); s->plugin_data[p->index] = (void *) sc; /* bring the plugin online */ _sx_chain_io_plugin(s, p); } static void _sx_ssl_server(sx_t s, sx_plugin_t p) { _sx_ssl_conn_t sc; SSL_CTX *ctx; int i; /* only bothering if they asked for wrappermode */ if(!(s->flags & SX_SSL_WRAPPER) || s->ssf > 0) return; _sx_debug(ZONE, "preparing for ssl accept for %d to %s", s->tag, s->req_to); /* find the ssl context for this destination */ ctx = xhash_get((xht) p->private, s->req_to); if(ctx == NULL) { _sx_debug(ZONE, "using default ssl context for %d", s->tag); ctx = xhash_get((xht) p->private, "*"); } else { _sx_debug(ZONE, "using configured ssl context for %d", s->tag); } assert((int) (ctx != NULL)); sc = (_sx_ssl_conn_t) calloc(1, sizeof(struct _sx_ssl_conn_st)); /* create the buffers */ sc->rbio = BIO_new(BIO_s_mem()); sc->wbio = BIO_new(BIO_s_mem()); /* new ssl conn */ sc->ssl = SSL_new(ctx); SSL_set_bio(sc->ssl, sc->rbio, sc->wbio); SSL_set_accept_state(sc->ssl); SSL_set_options(sc->ssl, SSL_OP_NO_SSLv3); /* empty external_id */ for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) sc->external_id[i] = NULL; /* buffer queue */ sc->wq = jqueue_new(); s->plugin_data[p->index] = (void *) sc; /* bring the plugin online */ _sx_chain_io_plugin(s, p); } /** cleanup */ static void _sx_ssl_free(sx_t s, sx_plugin_t p) { _sx_ssl_conn_t sc = (_sx_ssl_conn_t) s->plugin_data[p->index]; sx_buf_t buf; int i; if(sc == NULL) return; log_debug(ZONE, "cleaning up conn state"); if(s->type == type_NONE) { free(sc); return; } for (i = 0; i < SX_CONN_EXTERNAL_ID_MAX_COUNT; i++) if(sc->external_id[i] != NULL) free(sc->external_id[i]); else break; if(sc->pemfile != NULL) free(sc->pemfile); if(sc->private_key_password != NULL) free(sc->private_key_password); if(sc->ssl != NULL) SSL_free(sc->ssl); /* frees wbio and rbio too */ if(sc->wq != NULL) { while((buf = jqueue_pull(sc->wq)) != NULL) _sx_buffer_free(buf); jqueue_free(sc->wq); } free(sc); s->plugin_data[p->index] = NULL; } static void _sx_ssl_unload(sx_plugin_t p) { xht contexts = (xht) p->private; void *ctx; if(xhash_iter_first(contexts)) do { xhash_iter_get(contexts, NULL, NULL, &ctx); SSL_CTX_free((SSL_CTX *) ctx); } while(xhash_iter_next(contexts)); xhash_free(contexts); sx_ssl_free_dh_params(); } int sx_openssl_initialized = 0; /** args: name, pemfile, cachain, mode */ int sx_ssl_init(sx_env_t env, sx_plugin_t p, va_list args) { const char *name, *pemfile, *cachain, *password, *ciphers; int ret; int mode; _sx_debug(ZONE, "initialising ssl plugin"); name = va_arg(args, const char *); pemfile = va_arg(args, const char *); if(pemfile == NULL) return 1; if(p->private != NULL) return 1; cachain = va_arg(args, const char *); mode = va_arg(args, int); password = va_arg(args, char *); ciphers = va_arg(args, char *); /* !!! output openssl error messages to the debug log */ /* openssl startup */ if(!sx_openssl_initialized) { SSL_library_init(); SSL_load_error_strings(); } sx_openssl_initialized = 1; ret = sx_ssl_server_addcert(p, name, pemfile, cachain, mode, password, ciphers); if(ret) return 1; p->magic = SX_SSL_MAGIC; p->unload = _sx_ssl_unload; p->client = _sx_ssl_client; p->server = _sx_ssl_server; p->rio = _sx_ssl_rio; p->wio = _sx_ssl_wio; p->features = _sx_ssl_features; p->process = _sx_ssl_process; p->free = _sx_ssl_free; return 0; } /** args: name, pemfile, cachain, mode */ int sx_ssl_server_addcert(sx_plugin_t p, const char *name, const char *pemfile, const char *cachain, int mode, const char *password, const char *ciphers) { xht contexts = (xht) p->private; SSL_CTX *ctx; SSL_CTX *tmp; STACK_OF(X509_NAME) *cert_names; X509_STORE * store; DH *dhparams; EC_GROUP *ecparams; EC_KEY *eckey = NULL; int ret, nid; if(!sx_openssl_initialized) { _sx_debug(ZONE, "ssl plugin not initialised"); return 1; } if(name == NULL) name = "*"; if(pemfile == NULL) return 1; /* begin with fresh error stack */ ERR_clear_error(); /* create the context */ #ifdef ENABLE_EXPERIMENTAL ctx = SSL_CTX_new(TLSv1_2_method()); #else ctx = SSL_CTX_new(SSLv23_method()); #endif if(ctx == NULL) { _sx_debug(ZONE, "ssl context creation failed; %s", ERR_error_string(ERR_get_error(), NULL)); return 1; } // Set allowed ciphers. if non set, at least always disable NULL and export if (!ciphers) ciphers = "!aNULL:!eNULL:!EXP:" SSL_DEFAULT_CIPHER_LIST; _sx_debug(ZONE, "Restricting TLS ciphers to %s", ciphers); if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) { _sx_debug(ZONE, "Can't set cipher list for SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); return 1; } /* Load the CA chain, if configured */ if (cachain != NULL) { ret = SSL_CTX_load_verify_locations (ctx, cachain, NULL); if(ret != 1) { _sx_debug(ZONE, "WARNING: couldn't load CA chain: %s; %s", cachain, ERR_error_string(ERR_get_error(), NULL)); } else { _sx_debug(ZONE, "Loaded CA verify location chain: %s", cachain); } cert_names = SSL_load_client_CA_file(cachain); if (cert_names != NULL) { SSL_CTX_set_client_CA_list(ctx, cert_names); _sx_debug(ZONE, "Loaded client CA chain: %s", cachain); } else { _sx_debug(ZONE, "WARNING: couldn't load client CA chain: %s", cachain); } } else { /* Load the default OpenlSSL certs from /etc/ssl/certs We must assume that the client certificate's CA is there Note: We don't send client_CA_list here. Will possibly break some clients. */ SSL_CTX_set_default_verify_paths(ctx); _sx_debug(ZONE, "No CA chain specified. Loading SSL default CA certs: /etc/ssl/certs"); } /* Add server CRL verificaition */ store = SSL_CTX_get_cert_store(ctx); // Not sure if this should be X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL // or only X509_V_FLAG_CRL_CHECK X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); /* load the certificate */ ret = SSL_CTX_use_certificate_chain_file(ctx, pemfile); if(ret != 1) { _sx_debug(ZONE, "couldn't load certificate from %s; %s", pemfile, ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); return 1; } /* set callback giving a password for pemfile */ SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)password); SSL_CTX_set_default_passwd_cb(ctx, &_sx_pem_passwd_callback); /* load the private key */ ret = SSL_CTX_use_PrivateKey_file(ctx, pemfile, SSL_FILETYPE_PEM); if(ret != 1) { _sx_debug(ZONE, "couldn't load private key from %s; %s", pemfile, ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); return 1; } /* check the private key matches the certificate */ ret = SSL_CTX_check_private_key(ctx); if(ret != 1) { _sx_debug(ZONE, "private key does not match certificate public key; %s", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); return 1; } _sx_debug(ZONE, "setting ssl context '%s' verify mode to %02x", name, mode); SSL_CTX_set_verify(ctx, mode, _sx_ssl_verify_callback); SSL_CTX_set_tmp_dh_callback(ctx, _sx_ssl_tmp_dh_callback); /* try to read DH params from pem file */ if((dhparams = sx_ssl_get_DHparams(pemfile))) { SSL_CTX_set_tmp_dh(ctx, dhparams); _sx_debug(ZONE, "custom DH parameters loaded from certificate", BN_num_bits(dhparams->p)); } /* try to read ECDH params from pem file */ if((ecparams = sx_ssl_get_ECPKParameters(pemfile)) && (nid = EC_GROUP_get_curve_name(ecparams)) && (eckey = EC_KEY_new_by_curve_name(nid))) { SSL_CTX_set_tmp_ecdh(ctx, eckey); _sx_debug(ZONE, "custom ECDH curve %s loaded from certificate", OBJ_nid2sn(nid)); } else { #if defined(SSL_set_ecdh_auto) /* otherwise configure auto curve */ SSL_CTX_set_ecdh_auto(ctx, 1); #else /* ..or NIST P-256 */ _sx_debug(ZONE, "nist curve enabled"); eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); SSL_CTX_set_tmp_ecdh(ctx, eckey); #endif } EC_KEY_free(eckey); /* create hash and create default context */ if(contexts == NULL) { contexts = xhash_new(1021); p->private = (void *) contexts; /* this is the first context, if it's not the default then make a copy of it as the default */ if(!(name[0] == '*' && name[1] == 0)) { int ret = sx_ssl_server_addcert(p, "*", pemfile, cachain, mode, password, NULL); if(ret) { /* uh-oh */ xhash_free(contexts); p->private = NULL; return 1; } } } _sx_debug(ZONE, "ssl context '%s' initialised; certificate and key loaded from %s", name, pemfile); /* remove an existing context with the same name before replacing it */ tmp = xhash_get(contexts, name); if(tmp != NULL) SSL_CTX_free((SSL_CTX *) tmp); xhash_put(contexts, name, ctx); return 0; } int sx_ssl_client_starttls(sx_plugin_t p, sx_t s, const char *pemfile, const char *private_key_password) { assert((int) (p != NULL)); assert((int) (s != NULL)); /* sanity */ if(s->type != type_CLIENT || s->state != state_STREAM) { _sx_debug(ZONE, "wrong conn type or state for client starttls"); return 1; } /* check if we're already encrypted or compressed */ if(s->ssf > 0 || (s->flags & SX_COMPRESS_WRAPPER)) { _sx_debug(ZONE, "encrypted channel already established"); return 1; } _sx_debug(ZONE, "initiating starttls sequence"); /* save the given pemfile for later */ if(pemfile != NULL) { s->plugin_data[p->index] = (_sx_ssl_conn_t) calloc(1, sizeof(struct _sx_ssl_conn_st)); ((_sx_ssl_conn_t)s->plugin_data[p->index])->pemfile = strdup(pemfile); /* save the given password for later */ if(private_key_password != NULL) ((_sx_ssl_conn_t)s->plugin_data[p->index])->private_key_password = strdup(private_key_password); } /* go */ jqueue_push(s->wbufq, _sx_buffer_new("<starttls xmlns='" uri_TLS "'/>", strlen(uri_TLS) + 20, NULL, NULL), 0); s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); return 0; } ���������������������������������������������������������jabberd2-jabberd-2.3.4/sx/sx.c����������������������������������������������������������������������0000664�0000000�0000000�00000023752�12614627753�0016040�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "sx.h" sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg) { sx_t s; int i; assert((int) (cb != NULL)); s = (sx_t) calloc(1, sizeof(struct _sx_st)); s->env = env; s->tag = tag; s->cb = cb; s->cb_arg = arg; s->expat = XML_ParserCreateNS(NULL, '|'); XML_SetReturnNSTriplet(s->expat, 1); XML_SetUserData(s->expat, (void *) s); /* Prevent the "billion laughs" attack against expat by disabling * internal entity expansion. With 2.x, forcibly stop the parser * if an entity is declared - this is safer and a more obvious * failure mode. With older versions, simply prevent expenansion * of such entities. */ #ifdef HAVE_XML_STOPPARSER XML_SetEntityDeclHandler(s->expat, (void *) _sx_entity_declaration); #else XML_SetDefaultHandler(s->expat, NULL); #endif #ifdef HAVE_XML_SETHASHSALT XML_SetHashSalt(s->expat, rand()); #endif s->wbufq = jqueue_new(); s->rnadq = jqueue_new(); if(env != NULL) { s->plugin_data = (void **) calloc(1, sizeof(void *) * env->nplugins); for(i = 0; i < env->nplugins; i++) if(env->plugins[i]->new != NULL) (env->plugins[i]->new)(s, env->plugins[i]); } _sx_debug(ZONE, "allocated new sx for %d", tag); return s; } void sx_free(sx_t s) { sx_buf_t buf; nad_t nad; int i; _sx_chain_t scan, next; if (s == NULL) return; /* we are not reentrant */ assert(!s->reentry); _sx_debug(ZONE, "freeing sx for %d", s->tag); if(s->ns != NULL) free((void*)s->ns); if(s->req_to != NULL) free((void*)s->req_to); if(s->req_from != NULL) free((void*)s->req_from); if(s->req_version != NULL) free((void*)s->req_version); if(s->res_to != NULL) free((void*)s->res_to); if(s->res_from != NULL) free((void*)s->res_from); if(s->res_version != NULL) free((void*)s->res_version); if(s->id != NULL) free((void*)s->id); while((buf = jqueue_pull(s->wbufq)) != NULL) _sx_buffer_free(buf); if (s->wbufpending != NULL) _sx_buffer_free(s->wbufpending); while((nad = jqueue_pull(s->rnadq)) != NULL) nad_free(nad); jqueue_free(s->wbufq); jqueue_free(s->rnadq); XML_ParserFree(s->expat); if(s->nad != NULL) nad_free(s->nad); if(s->auth_method != NULL) free((void*)s->auth_method); if(s->auth_id != NULL) free((void*)s->auth_id); if(s->env != NULL) { _sx_debug(ZONE, "freeing %d env plugins", s->env->nplugins); for(i = 0; i < s->env->nplugins; i++) if(s->env->plugins[i]->free != NULL) (s->env->plugins[i]->free)(s, s->env->plugins[i]); scan = s->wio; while(scan != NULL) { next = scan->wnext; free(scan); scan = next; } scan = s->wnad; while(scan != NULL) { next = scan->wnext; free(scan); scan = next; } free(s->plugin_data); } free(s); } /** force advance into auth state */ void sx_auth(sx_t s, const char *auth_method, const char *auth_id) { assert((int) (s != NULL)); _sx_debug(ZONE, "authenticating stream (method=%s; id=%s)", auth_method, auth_id); if(auth_method != NULL) s->auth_method = strdup(auth_method); if(auth_id != NULL) s->auth_id = strdup(auth_id); _sx_state(s, state_OPEN); _sx_event(s, event_OPEN, NULL); } /** utility; reset stream state */ void _sx_reset(sx_t s) { struct _sx_st temp; sx_t new; _sx_debug(ZONE, "resetting stream state"); /* we want to reset the contents of s, but we can't free s because * the caller (and others) hold references. so, we make a new sx_t, * copy the contents (only pointers), free it (which will free strings * and queues), then make another new one, and copy the contents back * into s */ temp.env = s->env; temp.tag = s->tag; temp.cb = s->cb; temp.cb_arg = s->cb_arg; temp.ip = s->ip; temp.port = s->port; temp.flags = s->flags; temp.reentry = s->reentry; temp.ssf = s->ssf; temp.wio = s->wio; temp.rio = s->rio; temp.wnad = s->wnad; temp.rnad = s->rnad; temp.rbytesmax = s->rbytesmax; temp.plugin_data = s->plugin_data; s->reentry = 0; s->env = NULL; /* we get rid of this, because we don't want plugin data to be freed */ new = (sx_t) malloc(sizeof(struct _sx_st)); memcpy(new, s, sizeof(struct _sx_st)); sx_free(new); new = sx_new(NULL, temp.tag, temp.cb, temp.cb_arg); memcpy(s, new, sizeof(struct _sx_st)); free(new); /* massaged expat into shape */ XML_SetUserData(s->expat, (void *) s); s->env = temp.env; s->ip = temp.ip; s->port = temp.port; s->flags = temp.flags; s->reentry = temp.reentry; s->ssf = temp.ssf; s->wio = temp.wio; s->rio = temp.rio; s->wnad = temp.wnad; s->rnad = temp.rnad; s->rbytesmax = temp.rbytesmax; s->plugin_data = temp.plugin_data; s->has_reset = 1; _sx_debug(ZONE, "finished resetting stream state"); } /** utility: make a new buffer if len>0 but data is NULL, the buffer will contain that many bytes of garbage, to be overwritten by caller. otherwise, data pointed to by 'data' will be copied into buf */ sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg) { sx_buf_t buf; buf = (sx_buf_t) calloc(1, sizeof(struct _sx_buf_st)); if (len <= 0) { buf->data = buf->heap = NULL; buf->len = 0; } else { buf->data = buf->heap = (char *) malloc(sizeof(char) * len); if(data != NULL) memcpy(buf->data, data, len); else memset(buf->data, '$', len); /* catch uninitialized use */ buf->len = len; } buf->notify = notify; buf->notify_arg = notify_arg; return buf; } /** utility: kill a buffer */ void _sx_buffer_free(sx_buf_t buf) { if(buf->heap != NULL) free(buf->heap); free(buf); } /** utility: clear out a buffer, but don't deallocate it */ void _sx_buffer_clear(sx_buf_t buf) { if(buf->heap != NULL) { free(buf->heap); buf->heap = NULL; } buf->data = NULL; buf->len = 0; } /** utility: ensure a certain amount of allocated space adjacent to buf->data */ void _sx_buffer_alloc_margin(sx_buf_t buf, int before, int after) { char *new_heap; assert( before >= 0 ); assert( after >= 0 ); /* If there wasn't any data in the buf, we can just allocate space for the margins */ if (buf->data == NULL || buf->len == 0) { if (buf->heap != NULL) buf->heap = realloc(buf->heap, before+after); else buf->heap = malloc(before+after); buf->data = buf->heap + before; return; } if (buf->heap != NULL) { int old_leader = buf->data - buf->heap; /* Hmmm, maybe we can just call realloc() ? */ if (old_leader >= before && old_leader <= (before * 4)) { buf->heap = realloc(buf->heap, before + buf->len + after); buf->data = buf->heap + old_leader; return; } } /* Most general case --- allocate a new buffer, copy stuff over, free the old one. */ new_heap = malloc(before + buf->len + after); memcpy(new_heap + before, buf->data, buf->len); if (buf->heap != NULL) free(buf->heap); buf->heap = new_heap; buf->data = new_heap + before; } /** utility: reset a sx_buf_t's contents. If newheap is non-NULL it is assumed to be 'data's malloc block and ownership of the block is taken by the buffer. If newheap is NULL then the data is copied. */ void _sx_buffer_set(sx_buf_t buf, char* newdata, int newlength, char* newheap) { if (newheap == NULL) { buf->len = 0; _sx_buffer_alloc_margin(buf, 0, newlength); if (newlength > 0) memcpy(buf->data, newdata, newlength); buf->len = newlength; return; } _sx_buffer_clear(buf); buf->data = newdata; buf->len = newlength; buf->heap = newheap; } /** debug macro helpers */ void __sx_debug(const char *file, int line, const char *msgfmt, ...) { va_list ap; char *pos, message[MAX_DEBUG]; int sz; /* insert the header */ snprintf(message, MAX_DEBUG, "sx (%s:%d) ", file, line); /* find the end and attach the rest of the msg */ for (pos = message; *pos != '\0'; pos++); /*empty statement */ sz = pos - message; va_start(ap, msgfmt); vsnprintf(pos, MAX_DEBUG - sz, msgfmt, ap); va_end(ap); fprintf(stderr,"%s", message); fprintf(stderr, "\n"); fflush(stderr); } int __sx_event(const char *file, int line, sx_t s, sx_event_t e, void *data) { int ret; _sx_debug(file, line, "tag %d event %d data 0x%x", s->tag, e, data); s->reentry++; ret = (s->cb)(s, e, data, s->cb_arg); s->reentry--; return ret; } /** show sx flags as string - for logging */ char *_sx_flags(sx_t s) { static char flags[256]; flags[1] = '\0'; snprintf(flags, sizeof(flags), "%s%s%s", s->ssf ? ",TLS" : "", (s->flags & SX_COMPRESS_WRAPPER) ? ",ZLIB" : "", (s->flags & SX_WEBSOCKET_WRAPPER) ? ",WS" : "" ); return flags + 1; } ����������������������jabberd2-jabberd-2.3.4/sx/sx.h����������������������������������������������������������������������0000664�0000000�0000000�00000036427�12614627753�0016050�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifndef INCL_SX_H #define INCL_SX_H #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "ac-stdint.h" #include <expat.h> #include <util/util.h> /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifdef __cplusplus extern "C" { #endif /* forward declarations */ typedef struct _sx_st *sx_t; typedef struct _sx_env_st *sx_env_t; typedef struct _sx_plugin_st *sx_plugin_t; /** things that can happen */ typedef enum { event_WANT_READ, /* we want read actions */ event_WANT_WRITE, /* we want write actions */ event_READ, /* read some stuff for me */ event_WRITE, /* write this to the fd */ event_STREAM, /* stream is ready to go */ event_OPEN, /* normal operation */ event_PACKET, /* got a packet */ event_CLOSED, /* its over */ event_ERROR /* something's wrong */ } sx_event_t; /** connection states */ typedef enum { state_NONE, /* pre-init */ state_STREAM_RECEIVED, /* stream start received (server) */ state_STREAM_SENT, /* stream start sent (client) */ state_STREAM, /* stream established */ state_OPEN, /* auth completed (normal stream operation) */ state_CLOSING, /* ready to close (send event_CLOSED to app) */ state_CLOSED /* closed (same as NONE, but can't be used any more) */ } _sx_state_t; /** connection types */ typedef enum { type_NONE, type_CLIENT, /* we initiated the connection */ type_SERVER /* they initiated */ } _sx_type_t; /** event callback */ typedef int (*sx_callback_t)(sx_t s, sx_event_t e, void *data, void *arg); /** plugin init */ typedef int (*sx_plugin_init_t)(sx_env_t env, sx_plugin_t p, va_list args); /* errors */ #define SX_SUCCESS (0x00) #define SX_ERR_STREAM (0x01) #define SX_ERR_AUTH (0x02) #define SX_ERR_XML_PARSE (0x03) /** error info for event_ERROR */ typedef struct _sx_error_st { int code; const char *generic; const char *specific; } sx_error_t; /** helper macro to populate this struct */ #define _sx_gen_error(e,c,g,s) do { e.code = c; e.generic = g; e.specific = s; } while(0); /** prototype for the write notify function */ typedef void (*_sx_notify_t)(sx_t s, void *arg); /** utility: buffer */ typedef struct _sx_buf_st *sx_buf_t; struct _sx_buf_st { char *data; /* pointer to buffer's data */ unsigned int len; /* length of buffer's data */ char *heap; /* beginning of malloc() block containing data, if non-NULL */ /* function to call when this buffer gets written */ _sx_notify_t notify; void *notify_arg; }; /* stream errors */ #define stream_err_BAD_FORMAT (0) #define stream_err_BAD_NAMESPACE_PREFIX (1) #define stream_err_CONFLICT (2) #define stream_err_CONNECTION_TIMEOUT (3) #define stream_err_HOST_GONE (4) #define stream_err_HOST_UNKNOWN (5) #define stream_err_IMPROPER_ADDRESSING (6) #define stream_err_INTERNAL_SERVER_ERROR (7) #define stream_err_INVALID_FROM (8) #define stream_err_INVALID_ID (9) #define stream_err_INVALID_NAMESPACE (10) #define stream_err_INVALID_XML (11) #define stream_err_NOT_AUTHORIZED (12) #define stream_err_POLICY_VIOLATION (13) #define stream_err_REMOTE_CONNECTION_FAILED (14) #define stream_err_RESTRICTED_XML (15) #define stream_err_RESOURCE_CONSTRAINT (16) #define stream_err_SEE_OTHER_HOST (17) #define stream_err_SYSTEM_SHUTDOWN (18) #define stream_err_UNDEFINED_CONDITION (19) #define stream_err_UNSUPPORTED_ENCODING (20) #define stream_err_UNSUPPORTED_STANZA_TYPE (21) #define stream_err_UNSUPPORTED_VERSION (22) #define stream_err_XML_NOT_WELL_FORMED (23) #define stream_err_LAST (24) /* exported functions */ /* make/break */ JABBERD2_API sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg); JABBERD2_API void sx_free(sx_t s); /* get things ready */ JABBERD2_API void sx_client_init(sx_t s, unsigned int flags, const char *ns, const char *to, const char *from, const char *version); JABBERD2_API void sx_server_init(sx_t s, unsigned int flags); /* activity on socket, do stuff! (returns 1 if more read/write actions wanted, 0 otherwise) */ JABBERD2_API int sx_can_read(sx_t s); JABBERD2_API int sx_can_write(sx_t s); /** sending a nad */ JABBERD2_API void sx_nad_write_elem(sx_t s, nad_t nad, int elem); #define sx_nad_write(s,nad) sx_nad_write_elem(s, nad, 0) /** sending raw data */ JABBERD2_API void sx_raw_write(sx_t s, const char *buf, int len); /** authenticate the stream and move to the auth'd state */ JABBERD2_API void sx_auth(sx_t s, const char *auth_method, const char *auth_id); /* make/break an environment */ JABBERD2_API sx_env_t sx_env_new(void); JABBERD2_API void sx_env_free(sx_env_t env); /** load a plugin into the environment */ JABBERD2_API sx_plugin_t sx_env_plugin(sx_env_t env, sx_plugin_init_t init, ...); /* send errors and close stuff */ JABBERD2_API void sx_error(sx_t s, int err, const char *text); JABBERD2_API void sx_error_extended(sx_t s, int err, const char *content); JABBERD2_API void sx_close(sx_t s); JABBERD2_API void sx_kill(sx_t s); /* helper functions */ JABBERD2_API char* _sx_flags(sx_t s); /* primary expat callbacks */ JABBERD2_API void _sx_element_start(void *arg, const char *name, const char **atts); JABBERD2_API void _sx_element_end(void *arg, const char *name); JABBERD2_API void _sx_cdata(void *arg, const char *str, int len); JABBERD2_API void _sx_namespace_start(void *arg, const char *prefix, const char *uri); #ifdef HAVE_XML_STOPPARSER JABBERD2_API void _sx_entity_declaration(void *arg, const char *entityName, int is_parameter_entity, const char *value, int value_length, const char *base, const char *systemId, const char *publicId, const char *notationName); #endif /** processor for incoming wire data */ JABBERD2_API void _sx_process_read(sx_t s, sx_buf_t buf); /** main nad processor */ JABBERD2_API void _sx_nad_process(sx_t s, nad_t nad); /* chain management */ JABBERD2_API void _sx_chain_io_plugin(sx_t s, sx_plugin_t p); JABBERD2_API void _sx_chain_nad_plugin(sx_t s, sx_plugin_t p); /* chain running */ JABBERD2_API int _sx_chain_io_write(sx_t s, sx_buf_t buf); JABBERD2_API int _sx_chain_io_read(sx_t s, sx_buf_t buf); JABBERD2_API int _sx_chain_nad_write(sx_t s, nad_t nad, int elem); JABBERD2_API int _sx_chain_nad_read(sx_t s, nad_t nad); /* buffer utilities */ JABBERD2_API sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg); JABBERD2_API void _sx_buffer_free(sx_buf_t buf); JABBERD2_API void _sx_buffer_clear(sx_buf_t buf); JABBERD2_API void _sx_buffer_alloc_margin(sx_buf_t buf, int before, int after); JABBERD2_API void _sx_buffer_set(sx_buf_t buf, char *newdata, int newlength, char *newheap); /** sending a nad (internal) */ JABBERD2_API int _sx_nad_write(sx_t s, nad_t nad, int elem); /** sending raw data (internal) */ JABBERD2_API void sx_raw_write(sx_t s, const char *buf, int len); /** reset stream state without informing the app */ JABBERD2_API void _sx_reset(sx_t s); /* send errors and close stuff */ JABBERD2_API void _sx_error(sx_t s, int err, const char *text); JABBERD2_API void _sx_error_extended(sx_t s, int err, const char *content); JABBERD2_API void _sx_close(sx_t s); /** read/write plugin chain */ typedef struct _sx_chain_st *_sx_chain_t; struct _sx_chain_st { sx_plugin_t p; _sx_chain_t wnext; /* -> write */ _sx_chain_t rnext; /* <- read */ }; /** holds the state for a single stream */ struct _sx_st { /* environment */ sx_env_t env; /* tag, for logging */ int tag; /* IP address of the connection */ /* pointing to sess.ip and owned by sess structure */ const char *ip; /* TCP port of the connection */ /* pointing to sess.port and owned by sess structure */ int port; /* callback */ sx_callback_t cb; void *cb_arg; /* type */ _sx_type_t type; /* flags */ unsigned int flags; /* application namespace */ const char *ns; /* requested stream properties */ const char *req_to; const char *req_from; const char *req_version; /* responded stream properties */ const char *res_to; const char *res_from; const char *res_version; /* stream id */ const char *id; /* io chain */ _sx_chain_t wio, rio; /* nad chain */ _sx_chain_t wnad, rnad; /* internal queues */ jqueue_t wbufq; /* buffers waiting to go to wio */ sx_buf_t wbufpending; /* buffer passed through wio but not written yet */ jqueue_t rnadq; /* completed nads waiting to go to rnad */ /* do we want to read or write? */ int want_read, want_write; /* bytes read from socket */ int rbytes; int rbytes_total; /* read bytes maximum */ int rbytesmax; /* current state */ _sx_state_t state; /* parser */ XML_Parser expat; int depth; int fail; /* nad currently being built */ nad_t nad; /* plugin storage */ void **plugin_data; /* type and id of auth */ const char *auth_method; const char *auth_id; /* if true, then we were called from the callback */ int reentry; /* this is true after a stream resets - applications should check this before doing per-stream init */ int has_reset; /* security strength factor (in sasl parlance) - roughly equivalent to key strength */ int ssf; }; /** a plugin */ struct _sx_plugin_st { sx_env_t env; int magic; /* unique id so that plugins can find each other */ int index; void *private; void (*new)(sx_t s, sx_plugin_t p); /* pre-run init */ void (*free)(sx_t s, sx_plugin_t p); /* conn being freed */ void (*client)(sx_t s, sx_plugin_t p); /* client init */ void (*server)(sx_t s, sx_plugin_t p); /* server init */ /* return -2 == failed (permanent), -1 == failed (temporary), 0 == handled, 1 == pass */ int (*wio)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* before being written */ int (*rio)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* after being read */ /* return 0 == handled, 1 == pass */ int (*wnad)(sx_t s, sx_plugin_t p, nad_t nad, int elem); /* before being written */ int (*rnad)(sx_t s, sx_plugin_t p, nad_t nad); /* after being read */ void (*header)(sx_t s, sx_plugin_t p, sx_buf_t buf); /* before header req/res write */ void (*stream)(sx_t s, sx_plugin_t p); /* after-stream init */ void (*features)(sx_t s, sx_plugin_t p, nad_t nad); /* offer features */ /* return 0 == handled, 1 == pass */ int (*process)(sx_t s, sx_plugin_t p, nad_t nad); /* process completed nads */ void (*unload)(sx_plugin_t p); /* plugin unloading */ }; /** an environment */ struct _sx_env_st { sx_plugin_t *plugins; int nplugins; }; /** debugging macros */ #define ZONE __FILE__,__LINE__ /** helper functions for macros when we're debugging */ JABBERD2_API void __sx_debug(const char *file, int line, const char *msgfmt, ...); /** helper and internal macro for firing the callback */ JABBERD2_API int __sx_event(const char *file, int line, sx_t s, sx_event_t e, void *data); #define _sx_event(s,e,data) __sx_event(ZONE, s, e, data) #ifdef SX_DEBUG /** print debug output */ #define _sx_debug if(get_debug_flag()) __sx_debug /** state changes with output */ #define _sx_state(s,st) do { _sx_debug(ZONE, "%d state change from %d to %d", s->tag, s->state, st); s->state = st; } while(0) #else /* clean and efficient versions */ #define _sx_debug if(0) __sx_debug #define _sx_state(s,st) s->state = st #endif #ifdef __cplusplus } #endif /* now include sx envplugins datatypes */ #include "plugins.h" #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/sx/websocket.c���������������������������������������������������������������0000664�0000000�0000000�00000050560�12614627753�0017371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2015 Tomasz Sterna * * 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; version 2 of the License. * * 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, MA02111-1307USA */ /** * this plugin implements WebSocket C2S access * RFC 7395 : An Extensible Messaging and Presence Protocol (XMPP) Subprotocol for WebSocket * http://tools.ietf.org/html/rfc7395 */ #include "sx.h" #include <stdarg.h> #include <string.h> static const char websocket_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static http_parser_settings settings; /* parts of github.com/payden src/websock.c by Payden Sutherland follow */ #define MASK_LENGTH 4 #define FRAME_CHUNK_LENGTH 1024 #define WS_OPCODE_CONTINUE 0x0 #define WS_OPCODE_TEXT 0x1 #define WS_OPCODE_BINARY 0x2 #define WS_OPCODE_CLOSE 0x8 #define WS_OPCODE_PING 0x9 #define WS_OPCODE_PONG 0xa #define WS_FRAGMENT_FIN (1 << 7) #define WS_CLOSE_NORMAL 1000 #define WS_CLOSE_GOING_AWAY 1001 #define WS_CLOSE_PROTOCOL_ERROR 1002 #define WS_CLOSE_NOT_ALLOWED 1003 #define WS_CLOSE_RESERVED 1004 #define WS_CLOSE_NO_CODE 1005 #define WS_CLOSE_DIRTY 1006 #define WS_CLOSE_WRONG_TYPE 1007 #define WS_CLOSE_POLICY_VIOLATION 1008 #define WS_CLOSE_MESSAGE_TOO_BIG 1009 #define WS_CLOSE_UNEXPECTED_ERROR 1011 enum WS_FRAME_STATE { sw_start = 0, sw_got_two, sw_got_short_len, sw_got_full_len, sw_loaded_mask }; typedef struct _libwebsock_frame { unsigned int fin; unsigned int opcode; unsigned int mask_offset; unsigned int payload_offset; unsigned int rawdata_idx; unsigned int rawdata_sz; unsigned int size; unsigned int payload_len_short; unsigned int payload_len; char *rawdata; unsigned char mask[4]; enum WS_FRAME_STATE state; } libwebsock_frame; static inline int libwebsock_read_header(libwebsock_frame *frame) { int i, new_size; enum WS_FRAME_STATE state; state = frame->state; switch (state) { case sw_start: if (frame->rawdata_idx < 2) { return 0; } frame->state = sw_got_two; case sw_got_two: frame->mask_offset = 2; frame->fin = (*(frame->rawdata) & 0x80) == 0x80 ? 1 : 0; frame->opcode = *(frame->rawdata) & 0xf; frame->payload_len_short = *(frame->rawdata + 1) & 0x7f; frame->state = sw_got_short_len; case sw_got_short_len: switch (frame->payload_len_short) { case 126: if (frame->rawdata_idx < 4) { return 0; } frame->mask_offset += 2; frame->payload_offset = frame->mask_offset + MASK_LENGTH; frame->payload_len = ntohs( *((unsigned short int *) (frame->rawdata + 2))); frame->state = sw_got_full_len; break; case 127: if (frame->rawdata_idx < 10) { return 0; } frame->mask_offset += 8; frame->payload_offset = frame->mask_offset + MASK_LENGTH; frame->payload_len = ntohl(*((unsigned int *) (frame->rawdata + 6))); frame->state = sw_got_full_len; break; default: frame->payload_len = frame->payload_len_short; frame->payload_offset = frame->mask_offset + MASK_LENGTH; frame->state = sw_got_full_len; break; } case sw_got_full_len: if (frame->rawdata_idx < frame->payload_offset) { return 0; } for (i = 0; i < MASK_LENGTH; i++) { frame->mask[i] = *(frame->rawdata + frame->mask_offset + i) & 0xff; } frame->state = sw_loaded_mask; frame->size = frame->payload_offset + frame->payload_len; if (frame->size > frame->rawdata_sz) { new_size = frame->size; new_size--; new_size |= new_size >> 1; new_size |= new_size >> 2; new_size |= new_size >> 4; new_size |= new_size >> 8; new_size |= new_size >> 16; new_size++; frame->rawdata_sz = new_size; frame->rawdata = (char *) realloc(frame->rawdata, new_size); } return 1; case sw_loaded_mask: return 1; } return 0; } sx_buf_t libwebsock_fragment_buffer(const char *data, unsigned int len, int flags) { unsigned int *payload_len_32_be; unsigned short int *payload_len_short_be; unsigned char finNopcode, payload_len_small; unsigned int payload_offset = 2; unsigned int frame_size; char *frame; finNopcode = flags & 0xff; if (len <= 125) { frame_size = 2 + len; payload_len_small = len & 0xff; } else if (len > 125 && len <= 0xffff) { frame_size = 4 + len; payload_len_small = 126; payload_offset += 2; } else if (len > 0xffff && len <= 0xfffffff0) { frame_size = 10 + len; payload_len_small = 127; payload_offset += 8; } else { _sx_debug(ZONE, "libwebsock does not support frame payload sizes over %u bytes long\n", 0xfffffff0); return NULL; } sx_buf_t buf = _sx_buffer_new(NULL, frame_size, NULL, NULL); frame = buf->data; payload_len_small &= 0x7f; *frame = finNopcode; *(frame + 1) = payload_len_small; if (payload_len_small == 126) { len &= 0xffff; payload_len_short_be = (unsigned short *) ((char *) frame + 2); *payload_len_short_be = htons(len); } if (payload_len_small == 127) { payload_len_32_be = (unsigned int *) ((char *) frame + 2); *payload_len_32_be++ = 0; *payload_len_32_be = htonl(len); } memcpy(frame + payload_offset, data, len); return buf; } int libwebsock_close_with_reason(sx_t s, _sx_websocket_conn_t sc, unsigned short code, const char *reason); int libwebsock_send_fragment(sx_t s, _sx_websocket_conn_t sc, const char *data, unsigned int len, int flags) { sx_buf_t buf = libwebsock_fragment_buffer(data, len, flags); if (buf == NULL) { return libwebsock_close_with_reason(s, sc, WS_CLOSE_UNEXPECTED_ERROR, "Internal server error"); } jqueue_push(s->wbufq, buf, 0); s->want_write = 1; return _sx_event(s, event_WANT_WRITE, NULL); } int libwebsock_close_with_reason(sx_t s, _sx_websocket_conn_t sc, unsigned short code, const char *reason) { unsigned int len; unsigned short code_be; char buf[128]; //w3 spec on WebSockets API (http://dev.w3.org/html5/websockets/) says reason shouldn't be over 123 bytes. I concur. len = 2; code_be = htobe16(code); memcpy(buf, &code_be, 2); if (reason) { len += snprintf(buf + 2, 124, "%s", reason); } sc->state = websocket_CLOSING; int ret = libwebsock_send_fragment(s, sc, buf, len, WS_FRAGMENT_FIN | WS_OPCODE_CLOSE); sx_close(s); return ret; } int libwebsock_close(sx_t s, _sx_websocket_conn_t sc) { return libwebsock_close_with_reason(s, sc, WS_CLOSE_NORMAL, NULL); } void libwebsock_fail_connection(sx_t s, _sx_websocket_conn_t sc, unsigned short close_code) { char close_frame[4] = { 0x88, 0x02, 0x00, 0x00 }; unsigned short *code_be = (unsigned short *) &close_frame[2]; *code_be = htobe16(WS_CLOSE_PROTOCOL_ERROR); sx_buf_t buf = _sx_buffer_new(NULL, sizeof(close_frame), NULL, NULL); memcpy(buf->data, close_frame, buf->len); sc->state = websocket_CLOSING; s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); sx_close(s); } static int _sx_websocket_http_header_field(http_parser *parser, const char *chars, size_t length) { _sx_debug(ZONE, "HTTP header field '%.*s'", length, chars); _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data; if(sc->header_value) { // new field incoming xhash_put(sc->headers, strunescape(sc->p, spool_print(sc->field)), strunescape(sc->p, spool_print(sc->value))); sc->header_value = 0; sc->field = spool_new(sc->p); } spool_escape(sc->field, chars, length); return 0; } static int _sx_websocket_http_header_value(http_parser *parser, const char *chars, size_t length) { _sx_debug(ZONE, "HTTP header value '%.*s'", length, chars); _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data; if(!sc->header_value) { // field name complete sc->header_value = 1; sc->value = spool_new(sc->p); } spool_escape(sc->value, chars, length); return 0; } static int _sx_websocket_http_headers_complete(http_parser *parser) { _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data; _sx_debug(ZONE, "HTTP headers complete: %d %s HTTP/%d.%d", parser->status_code, http_method_str(parser->method), parser->http_major, parser->http_minor); if (sc->header_value) { /* pull last value by switching to field parser */ _sx_websocket_http_header_field(parser, "", 0); } return 1; } static void _sx_websocket_http_return(sx_t s, char *status, char *headers_format, ...) { char* http = "HTTP/1.1 %s\r\n" "%s" "Server: " PACKAGE_STRING "\r\n" "Expires: Fri, 10 Oct 1997 10:10:10 GMT\r\n" "Pragma: no-cache\r\n" "Cache-control: private\r\n" "\r\n"; /* build additional headers */ char headers[1024]; va_list args; va_start(args, headers_format); vsnprintf(headers, sizeof(headers), headers_format, args); va_end(args); /* build HTTP answer */ sx_buf_t buf = _sx_buffer_new(NULL, j_strlen(http) + j_strlen(status) + j_strlen(headers), NULL, NULL); buf->len = sprintf(buf->data, http, status, headers); jqueue_push(s->wbufq, buf, 0); /* stuff to write */ s->want_write = 1; _sx_event(s, event_WANT_WRITE, NULL); } static int _sx_websocket_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index]; int i, ret, err; sha1_state_t sha1; unsigned char hash[20]; /* if not wrapped yet */ if(!(s->flags & SX_WEBSOCKET_WRAPPER)) { /* look for HTTP handshake */ if(s->state == state_NONE && sc->state == websocket_PRE && buf->len >= 5 && strncmp("GET /", buf->data, 5) == 0) { _sx_debug(ZONE, "got HTTP handshake"); sc->state = websocket_HEADERS; } /* pass buffers through http_parser */ if(s->state == state_NONE && sc->state == websocket_HEADERS) { _sx_debug(ZONE, "parsing HTTP headers"); if(buf->len > 0) { _sx_debug(ZONE, "loading %d bytes into http_parser %.*s", buf->len, buf->len, buf->data); ret = http_parser_execute(&sc->parser, &settings, buf->data, buf->len); if (sc->parser.upgrade) { /* check for required websocket upgrade headers */ char *upgrade = xhash_get(sc->headers, "Upgrade"); char *connection = xhash_get(sc->headers, "Connection"); char *key = xhash_get(sc->headers, "Sec-WebSocket-Key"); char *proto = xhash_get(sc->headers, "Sec-WebSocket-Protocol"); int version = j_atoi(xhash_get(sc->headers, "Sec-WebSocket-Version"), -1); if(j_strcmp(upgrade, "websocket") || j_strcmp(connection, "Upgrade") || j_strcmp(proto, "xmpp") || version != 13) { _sx_debug(ZONE, "Upgrade: %s", upgrade); _sx_debug(ZONE, "Connection: %s", connection); _sx_debug(ZONE, "Sec-WebSocket-Key: %s", key); _sx_debug(ZONE, "Sec-WebSocket-Protocol: %s", proto); _sx_debug(ZONE, "Sec-WebSocket-Version: %d", version); _sx_websocket_http_return(s, "400 Bad Request", ""); sx_close(s); return -2; } /* we're good to go */ sha1_init(&sha1); sha1_append(&sha1, key, j_strlen(key)); sha1_append(&sha1, websocket_guid, sizeof(websocket_guid) -1); sha1_finish(&sha1, hash); char * accept = b64_encode(hash, sizeof(hash)); /* switch protocols */ _sx_websocket_http_return(s, "101 Switching Protocols", "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n" "Sec-WebSocket-Protocol: xmpp\r\n", accept); free(accept); /* and move past headers */ sc->state = websocket_ACTIVE; s->flags |= SX_WEBSOCKET_WRAPPER; return 0; } else if (ret != buf->len) { /* throw an error */ sx_error(s, stream_err_BAD_FORMAT, http_errno_description(sc->parser.http_errno)); sx_close(s); return -2; } else if (p->private) { char *http_forward = p->private; _sx_debug(ZONE, "bouncing HTTP request to %s", http_forward); _sx_websocket_http_return(s, "301 Found", "Location: %s\r\nConnection: close\r\n", http_forward); sx_close(s); return -1; } _sx_debug(ZONE, "unhandling HTTP request"); sx_kill(s); return -2; } _sx_buffer_clear(buf); /* flag we want to read */ s->want_read = 1; return 0; } } /* only bothering if it is active websocket */ if(!(s->flags & SX_WEBSOCKET_WRAPPER) || sc->state != websocket_ACTIVE) return 1; _sx_debug(ZONE, "Unwraping WebSocket frame"); char *data = buf->data; for (i = 0; i < buf->len;) { libwebsock_frame *frame; if (sc->frame == NULL) { frame = (libwebsock_frame *) calloc(1, sizeof(libwebsock_frame)); frame->payload_len = -1; frame->rawdata_sz = FRAME_CHUNK_LENGTH; frame->rawdata = (char *) malloc(FRAME_CHUNK_LENGTH); sc->frame = frame; } else { frame = sc->frame; } *(frame->rawdata + frame->rawdata_idx++) = *data++; i++; if (frame->state != sw_loaded_mask) { err = libwebsock_read_header(frame); if (err == -1) { if (sc->state != websocket_CLOSING) { libwebsock_fail_connection(s, sc, WS_CLOSE_PROTOCOL_ERROR); } return -2; } if (err == 0) { continue; } } if (frame->rawdata_idx < frame->size) { if (buf->len - i >= frame->size - frame->rawdata_idx) { //remaining in current vector completes frame. Copy remaining frame size memcpy(frame->rawdata + frame->rawdata_idx, data, frame->size - frame->rawdata_idx); data += frame->size - frame->rawdata_idx; i += frame->size - frame->rawdata_idx; frame->rawdata_idx = frame->size; } else { //not complete frame, copy the rest of this vector into frame. memcpy(frame->rawdata + frame->rawdata_idx, data, buf->len - i); frame->rawdata_idx += buf->len - i; i = buf->len; continue; } } //have full frame at this point _sx_debug(ZONE, "FIN: %d", frame->fin); _sx_debug(ZONE, "Opcode: %d", frame->opcode); _sx_debug(ZONE, "mask_offset: %d", frame->mask_offset); _sx_debug(ZONE, "payload_offset: %d", frame->payload_offset); _sx_debug(ZONE, "rawdata_idx: %d", frame->rawdata_idx); _sx_debug(ZONE, "rawdata_sz: %d", frame->rawdata_sz); _sx_debug(ZONE, "payload_len: %u", frame->payload_len); switch (frame->opcode) { case WS_OPCODE_TEXT: _sx_buffer_set(buf, frame->rawdata + frame->payload_offset, frame->payload_len, frame->rawdata); frame->rawdata = NULL; /* unmask content */ for (i = 0; i < buf->len; i++) buf->data[i] ^= frame->mask[i % 4]; _sx_debug(ZONE, "payload: %.*s", buf->len, buf->data); /* hack unclosed stream */ if (buf->len >= 7 && strncmp(buf->data, "<open", 5) == 0 && strncmp(buf->data + buf->len - 2, "/>", 2) == 0) { buf->len--; buf->data[buf->len - 1] = '>'; } break; case WS_OPCODE_CLOSE: libwebsock_close(s, sc); break; case WS_OPCODE_PING: libwebsock_send_fragment(s, sc, frame->rawdata + frame->payload_offset, frame->payload_len, WS_FRAGMENT_FIN | WS_OPCODE_PONG); _sx_buffer_clear(buf); break; case WS_OPCODE_PONG: _sx_buffer_clear(buf); s->want_read = 1; return 0; default: libwebsock_fail_connection(s, sc, WS_CLOSE_PROTOCOL_ERROR); break; } free(frame->rawdata); free(frame); sc->frame = NULL; if (sc->state == websocket_CLOSING) { _sx_buffer_clear(buf); return 0; } } return 1; } static int _sx_websocket_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index]; /* only bothering if it is active websocket */ if(!(s->flags & SX_WEBSOCKET_WRAPPER)) return 1; _sx_debug(ZONE, "in _sx_websocket_wio"); if(buf->len > 0) { _sx_debug(ZONE, "wrapping %d bytes in WebSocket frame", buf->len); sx_buf_t frame = libwebsock_fragment_buffer(buf->data, buf->len, WS_FRAGMENT_FIN | WS_OPCODE_TEXT); if (frame == NULL) { return libwebsock_close_with_reason(s, sc, WS_CLOSE_UNEXPECTED_ERROR, "Internal server error"); } _sx_buffer_set(buf, frame->data, frame->len, frame->data); free(frame); } _sx_debug(ZONE, "passing %d bytes frame", buf->len); return 1; } static void _sx_websocket_new(sx_t s, sx_plugin_t p) { _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index]; if(sc != NULL) return; _sx_debug(ZONE, "preparing for HTTP websocket connect for %d", s->tag); sc = (_sx_websocket_conn_t) calloc(1, sizeof(struct _sx_websocket_conn_st)); sc->state = websocket_PRE; sc->p = pool_new(); sc->field = spool_new(sc->p); sc->value = spool_new(sc->p); sc->headers = xhash_new(11); sc->parser.data = sc; /* initialize parser */ http_parser_init(&sc->parser, HTTP_REQUEST); s->plugin_data[p->index] = (void *) sc; /* bring the plugin online */ _sx_chain_io_plugin(s, p); } /** cleanup */ static void _sx_websocket_free(sx_t s, sx_plugin_t p) { _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index]; if(sc == NULL) return; log_debug(ZONE, "cleaning up websocket state"); pool_free(sc->p); if (sc->frame) free(((libwebsock_frame *)sc->frame)->rawdata); free(sc->frame); free(sc); s->plugin_data[p->index] = NULL; } /** args: none */ int sx_websocket_init(sx_env_t env, sx_plugin_t p, va_list args) { _sx_debug(ZONE, "initialising websocket plugin"); p->server = _sx_websocket_new; p->rio = _sx_websocket_rio; p->wio = _sx_websocket_wio; p->free = _sx_websocket_free; char *http_forward = va_arg(args, char*); p->private = http_forward; settings.on_headers_complete = _sx_websocket_http_headers_complete; settings.on_header_field = _sx_websocket_http_header_field; settings.on_header_value = _sx_websocket_http_header_value; return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015741�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/Makefile.am������������������������������������������������������������0000664�0000000�0000000�00000000650�12614627753�0017776�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet AM_CPPFLAGS = -I@top_srcdir@ EXTRA_DIST = *.xml subdir TESTS = check_nad check_config check_PROGRAMS = check_nad check_config check_nad_SOURCES = check_nad.c check_nad_CFLAGS = $(CHECK_CFLAGS) check_nad_LDADD = $(top_builddir)/util/libutil.la $(CHECK_LIBS) check_config_SOURCES = check_config.c check_config_CFLAGS = $(CHECK_CFLAGS) check_config_LDADD = $(top_builddir)/util/libutil.la $(CHECK_LIBS) ����������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/check_config.c���������������������������������������������������������0000664�0000000�0000000�00000014744�12614627753�0020521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <check.h> #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "util/util.h" #ifdef CONFIGEXPAND_GUARDED #define GUARD(S) (S + strlen(S) + 1) #else #define GUARD(S) "deadbeaf" #endif START_TEST (check_config_parse) { config_t c = config_new(); fail_unless (c != 0); int r = config_load_with_id(c, "test_config.xml", "test_id"); ck_assert_int_eq (0, r); // Do not place config_load into ck_assert_xxxx othewise it is called twice !!! ck_assert_str_eq ("test_id", config_get_one(c, "id", 0)); ck_assert_str_eq ("value if id is test_id", config_get_one(c, "value_with_id", 0)); ck_assert_str_eq ("1", config_get_one(c, "simple_value", 0)); ck_assert_int_eq (0, config_count(c, "does_not_exists")); ck_assert_int_eq (1, config_count(c, "simple_value")); ck_assert_int_eq (3, config_count(c, "multiple.val")); ck_assert_int_eq (4, config_count(c, "multiple.simple")); ck_assert_str_eq ("val1", config_get_attr(c, "simple_value_with_attr", 0, "attr1")); ck_assert_str_eq ("val2", config_get_attr(c, "simple_value_with_attr", 0, "attr2")); fail_unless ((char*)0 == config_get_attr(c, "simple_value_with_attr", 100, "attr1")); fail_unless ((char*)0 == config_get_attr(c, "simple_value_with_attr", 1, "does_not_exists")); fail_unless ((char*)0 == config_get_attr(c, "simple_value_with_attr", 0, "does_not_exists")); config_free(c); } END_TEST START_TEST (check_config_expand) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "test_config.xml"); ck_assert_int_eq (0, r); ck_assert_ptr_eq ((config_elem_t)0, config_get(c, "non.existing.key")); fail_unless ((const char*)0 == config_get_one(c, "non.existing.key", 0)); ck_assert_str_eq ("qwerty", config_get_one(c, "test_key", 0)); fail_unless ((const char*)0 == config_get_one(c, "test_key", 1)); ck_assert_str_eq ("qwerty", config_get_one_default(c, "test_key", 0, "not_this_value")); ck_assert_str_eq ("asdfg", config_get_one_default(c, "non.existing.key", 0, "asdfg")); char *s = config_expand(c, "qwerty"); fail_unless (s != 0); ck_assert_str_eq ("qwerty", s); s = config_expand(c, "${wrong_var}asdfgh"); fail_unless (s == 0); s = config_expand(c, "${test_key}asdfgh"); fail_unless (s != 0); ck_assert_str_eq ("qwertyasdfgh", s); ck_assert_str_eq ("deadbeaf", GUARD(s)); s = config_expand(c, "qqq${test_key}asdfgh"); fail_unless (s != 0); ck_assert_str_eq ("qqqqwertyasdfgh", s); ck_assert_str_eq ("deadbeaf", GUARD(s)); s = config_expand(c, "${test_key}qqq${test_key}asdfgh"); fail_unless (s != 0); ck_assert_str_eq ("qwertyqqqqwertyasdfgh", s); ck_assert_str_eq ("deadbeaf", GUARD(s)); s = config_expand(c, "qqq${test_key}asdfgh${test_key}"); fail_unless (s != 0); ck_assert_str_eq ("qqqqwertyasdfghqwerty", s); ck_assert_str_eq ("deadbeaf", GUARD(s)); s = config_expand(c, "qqq${test_key}asdfgh${invalid}"); fail_unless (s == 0); ck_assert_str_eq ("asdfghqwertyzxcvbn", config_get_one(c, "test_key_expanded", 0)); // ck_assert_str_eq ((const char*)0, config_get_one(c, "test_key_expanded_no_var", 0)); // ck_assert_str_eq ((const char*)0, config_get_one(c, "use_defined_later", 0)); ck_assert_str_eq ("asdfghqwertyzxcvbn", config_get_one(c, "use_defined_above", 0)); ck_assert_str_eq ("1111234567222", config_get_one(c, "another.test.value", 0)); s = config_expand(c, "qqq${test_key"); fail_unless (s == 0); s = config_expand(c, "qqq${test_key_____${second}"); fail_unless (s == 0); config_free(c); } END_TEST START_TEST (check_config_missing) { config_t c = config_new(); fail_unless (c != 0); int load_result = config_load(c, "no_file.xml"); ck_assert_int_eq (1, load_result); config_free(c); } END_TEST START_TEST (check_config_empty) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "empty.xml"); ck_assert_int_eq (0, r); config_free(c); } END_TEST START_TEST (check_config_include) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "test_include.xml"); ck_assert_int_eq (0, r); config_free(c); } END_TEST START_TEST (check_config_fail_002) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "failed_to_load_002.xml"); ck_assert_int_eq (1, r); config_free(c); } END_TEST START_TEST (check_config_fail_003) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "failed_to_load_003.xml"); ck_assert_int_eq (1, r); config_free(c); } END_TEST START_TEST (check_config_fail_004) { config_t c = config_new(); fail_unless (c != 0); int r = config_load(c, "failed_to_load_004.xml"); ck_assert_int_eq (1, r); config_free(c); } END_TEST const char *generated_configs[] = { "../etc/s2s.xml.dist", "../etc/sm.xml.dist", "../etc/router.xml.dist", "../etc/router-filter.xml.dist", "../etc/templates/roster.xml.dist", "../etc/c2s.xml.dist", "../etc/router-users.xml.dist" }; START_TEST (test_generated_config) { char msg[1000]; snprintf(msg, 1000, "Faled to load config %d: %s", _i, generated_configs[_i]); config_t c = config_new(); fail_unless (c != 0, msg); fail_unless (0 == config_load(c, generated_configs[_i]), msg); config_free(c); } END_TEST Suite* config_test_suite (void) { Suite *s = suite_create ("XML configuration"); TCase *tc_def = tcase_create ("Default generated configs"); tcase_add_loop_test (tc_def, test_generated_config, 0, sizeof(generated_configs) / sizeof(generated_configs[0])); suite_add_tcase (s, tc_def); TCase *tc_parsing = tcase_create ("Parsing"); tcase_add_test (tc_parsing, check_config_parse); tcase_add_test (tc_parsing, check_config_expand); tcase_add_test (tc_parsing, check_config_missing); tcase_add_test (tc_parsing, check_config_empty); tcase_add_test (tc_parsing, check_config_include); tcase_add_test (tc_parsing, check_config_fail_002); tcase_add_test (tc_parsing, check_config_fail_003); tcase_add_test (tc_parsing, check_config_fail_004); suite_add_tcase (s, tc_parsing); return s; } int main (void) { // set_debug_flag(1); int number_failed; Suite *s = config_test_suite (); SRunner *sr = srunner_create (s); srunner_run_all (sr, CK_NORMAL); number_failed = srunner_ntests_failed (sr); srunner_free (sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } ����������������������������jabberd2-jabberd-2.3.4/tests/check_nad.c������������������������������������������������������������0000664�0000000�0000000�00000041365�12614627753�0020015�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <check.h> #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdlib.h> #include "util/util.h" #define NADTXT_COUNT 4 char *nadtxt[NADTXT_COUNT] = { "<presence to='test@chrome.pl' from='test%gmail.com@jabber.chrome.pl/gmail.EBAFDAF7'>" "<priority>24</priority>" "<caps:c xmlns:caps='http://jabber.org/protocol/caps' xmlns='jabber:client' node='http://mail.google.com/xmpp/client/caps' ext='pmuc-v1 sms-v1 vavinvite-v1' ver='1.1'/>" "<status>Your faith is what you believe, not what you know.</status>" "<x xmlns='vcard-temp:x:update'><photo>f272aa57eae74d4be9f99758d2fed636c30548cb</photo></x>" "</presence>", "<message type='chat' to='test@chrome.pl' from='update@identi.ca/xmpp001daemon'><body>magicdrums: RT @mateamargonerds: Cursos !Linux avanzado http://twitpic.com/2c3lnj !mateamargonerds | jajajaj !fb [45259404]</body><html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'><a href='http://identi.ca/magicdrums'>magicdrums</a>: RT @<span class='vcard'><a title='Mate Amargo {Nerds}' class='url' href='http://identi.ca/user/119986'><span class='fn nickname'>mateamargonerds</span></a></span>: Cursos !<span class='vcard'><a title='GNU/Linux (linux)' class='url' href='http://identi.ca/group/56/id'><span class='fn nickname'>Linux</span></a></span> avanzado <a rel='external' title='http://twitpic.com/2c3lnj' href='http://twitpic.com/2c3lnj'>http://twitpic.com/2c3lnj</a> !mateamargonerds | jajajaj !fb <a href='http://identi.ca/conversation/44928627#notice-45259404'>[45259404]</a></body></html> <entry xmlns='http://www.w3.org/2005/Atom'>" "<source>" "<id>http://identi.ca/magicdrums</id>" "<title>magicdrums - Identi.ca</title>" "<link href='http://identi.ca/magicdrums'/>" "<link rel='self' type='application/atom+xml' href='http://identi.ca/magicdrums'/>" "<link rel='license' href='http://creativecommons.org/licenses/by/3.0/'/>" "<icon>http://avatar.identi.ca/46122-96-20100607195425.png</icon>" "<updated>2010-08-06T13:52:15+00:00</updated>" "</source>" "<title>RT @mateamargonerds: Cursos !Linux avanzado http://twitpic.com/2c3lnj !mateamargonerds | jajajaj !fb</title>" "<author>" "<name>magicdrums</name>" "<uri>http://identi.ca/user/46122</uri>" "</author>" "<actor xmlns='http://activitystrea.ms/spec/1.0/'>" "<object-type>http://activitystrea.ms/schema/1.0/person</object-type>" "<id xmlns='http://www.w3.org/2005/Atom'>http://identi.ca/user/46122</id>" "<title xmlns='http://www.w3.org/2005/Atom'>Victor Pereira</title>" "<link rel='alternate' type='text/html' href='http://identi.ca/magicdrums' xmlns='http://www.w3.org/2005/Atom'/>" "<link rel='avatar' type='image/png' xmlns:ns1='http://purl.org/syndication/atommedia' ns1:height='163' xmlns:ns2='http://purl.org/syndication/atommedia' ns2:width='163' href='http://avatar.identi.ca/46122-163-20100607195425.png' xmlns='http://www.w3.org/2005/Atom'/>" "<link rel='avatar' type='image/png' xmlns:ns1='http://purl.org/syndication/atommedia' ns1:height='96' xmlns:ns2='http://purl.org/syndication/atommedia' ns2:width='96' href='http://avatar.identi.ca/46122-96-20100607195425.png' xmlns='http://www.w3.org/2005/Atom'/>" "<link rel='avatar' type='image/png' xmlns:ns1='http://purl.org/syndication/atommedia' ns1:height='48' xmlns:ns2='http://purl.org/syndication/atommedia' ns2:width='48' href='http://avatar.identi.ca/46122-48-20100607195425.png' xmlns='http://www.w3.org/2005/Atom'/>" "<link rel='avatar' type='image/png' xmlns:ns1='http://purl.org/syndication/atommedia' ns1:height='24' xmlns:ns2='http://purl.org/syndication/atommedia' ns2:width='24' href='http://avatar.identi.ca/46122-24-20100607195425.png' xmlns='http://www.w3.org/2005/Atom'/>" "<point xmlns='http://www.georss.org/georss'>-33.4262838 -70.5665588</point>" "<preferredUsername xmlns='http://portablecontacts.net/spec/1.0'>magicdrums</preferredUsername>" "<displayName xmlns='http://portablecontacts.net/spec/1.0'>Victor Pereira</displayName>" "<note xmlns='http://portablecontacts.net/spec/1.0'>Padre, Esposo, IT Support, Intento de Geek, Hard Core, Ubuntero, Batero Frustado Linuxcero, Amante de mi Señora...</note>" "<address xmlns='http://portablecontacts.net/spec/1.0'>" "<formatted>ÜT: -33.527926,-70.655237</formatted>" "</address>" "<urls xmlns='http://portablecontacts.net/spec/1.0'>" "<type>homepage</type>" "<value>http://magicdrums.gnu-linux.cl</value>" "<primary>true</primary>" "</urls>" "</actor>" "<link rel='alternate' type='text/html' href='http://identi.ca/notice/45259404'/>" "<id>http://identi.ca/notice/45259404</id>" "<published>2010-08-06T13:52:15+00:00</published>" "<updated>2010-08-06T13:52:15+00:00</updated>" "<notice_info local_id='45259404' source='Viigo' xmlns='http://status.net/schema/api/1/'/>" "<link rel='related' href='http://identi.ca/notice/45255203'/>" "<in-reply-to ref='http://identi.ca/notice/45255203' href='http://identi.ca/notice/45255203' xmlns='http://purl.org/syndication/thread/1.0'/>" "<link rel='ostatus:conversation' href='http://identi.ca/conversation/44928627'/>" "<link rel='ostatus:attention' href='http://identi.ca/user/119986'/>" "<link rel='ostatus:attention' href='http://identi.ca/group/56/id'/>" "<content type='html'>RT @&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://identi.ca/user/119986&quot; class=&quot;url&quot; title=&quot;Mate Amargo {Nerds}&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;mateamargonerds&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;: Cursos !&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://identi.ca/group/56/id&quot; class=&quot;url&quot; title=&quot;GNU/Linux (linux)&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;Linux&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; avanzado &lt;a href=&quot;http://twitpic.com/2c3lnj&quot; title=&quot;http://twitpic.com/2c3lnj&quot; rel=&quot;external&quot;&gt;http://twitpic.com/2c3lnj&lt;/a&gt; !mateamargonerds | jajajaj !fb</content>" "<category term='fb'/>" "<category term='linux'/>" "<category term='mateamargonerds'/>" "<point xmlns='http://www.georss.org/georss'>-33.4262838 -70.5665588</point>" "</entry>" "</message>", "<message xmlns='jabber:server' from='blip@blip.pl/blip' to='test@chrome.pl' xml:lang='en' type='chat'>" "<body>Proponuję zmianę tematu. Porozmawiajmy o dinazaurach.</body>" "</message>", "<presence xmlns='jabber:client' to='test@chrome.pl' from='anon%majesticmedia.ca@gtalk.jrudevels.org/gmail.E1D35514'>" "<status/><show>away</show><priority>0</priority>" "<caps:c xmlns:caps='http://jabber.org/protocol/caps' xmlns='jabber:client' ver='1.1' ext='pmuc-v1 sms-v1 vavinvite-v1' node='http://mail.google.com/xmpp/client/caps'/>" "<x xmlns='vcard-temp:x:update'><photo>86f065b95e82036afa1eb2180f846e60085f3138</photo></x>" "</presence>" }; char *nadmangled[NADTXT_COUNT] = { "<route xmlns='http://jabberd.jabberstudio.org/ns/component/1.0' from='s2s' to='sm'><presence xmlns='jabber:client' from='test%gmail.com@jabber.chrome.pl/gmail.EBAFDAF7' to='test@chrome.pl'><priority>24</priority><caps:c xmlns:caps='http://jabber.org/protocol/caps' ver='1.1' ext='pmuc-v1 sms-v1 vavinvite-v1' node='http://mail.google.com/xmpp/client/caps'/><status>Your faith is what you believe, not what you know.</status><x xmlns='vcard-temp:x:update'><photo>f272aa57eae74d4be9f99758d2fed636c30548cb</photo></x></presence></route>", "<route xmlns='http://jabberd.jabberstudio.org/ns/component/1.0' from='s2s' to='sm'><message xmlns='jabber:client' from='update@identi.ca/xmpp001daemon' to='test@chrome.pl' type='chat'><body>magicdrums: RT @mateamargonerds: Cursos !Linux avanzado http://twitpic.com/2c3lnj !mateamargonerds | jajajaj !fb [45259404]</body><html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'><a href='http://identi.ca/magicdrums'>magicdrums</a>: RT @<span class='vcard'><a href='http://identi.ca/user/119986' class='url' title='Mate Amargo {Nerds}'><span class='fn nickname'>mateamargonerds</span></a></span>: Cursos !<span class='vcard'><a href='http://identi.ca/group/56/id' class='url' title='GNU/Linux (linux)'><span class='fn nickname'>Linux</span></a></span> avanzado <a href='http://twitpic.com/2c3lnj' title='http://twitpic.com/2c3lnj' rel='external'>http://twitpic.com/2c3lnj</a> !mateamargonerds | jajajaj !fb <a href='http://identi.ca/conversation/44928627#notice-45259404'>[45259404]</a></body></html> <entry xmlns='http://www.w3.org/2005/Atom'><source><id>http://identi.ca/magicdrums</id><title>magicdrums - Identi.ca</title><link href='http://identi.ca/magicdrums'/><link href='http://identi.ca/magicdrums' type='application/atom+xml' rel='self'/><link href='http://creativecommons.org/licenses/by/3.0/' rel='license'/><icon>http://avatar.identi.ca/46122-96-20100607195425.png</icon><updated>2010-08-06T13:52:15+00:00</updated></source><title>RT @mateamargonerds: Cursos !Linux avanzado http://twitpic.com/2c3lnj !mateamargonerds | jajajaj !fb</title><author><name>magicdrums</name><uri>http://identi.ca/user/46122</uri></author><actor xmlns='http://activitystrea.ms/spec/1.0/'><object-type>http://activitystrea.ms/schema/1.0/person</object-type><id xmlns='http://www.w3.org/2005/Atom'>http://identi.ca/user/46122</id><title xmlns='http://www.w3.org/2005/Atom'>Victor Pereira</title><link xmlns='http://www.w3.org/2005/Atom' href='http://identi.ca/magicdrums' type='text/html' rel='alternate'/><link xmlns:ns1='http://purl.org/syndication/atommedia' xmlns='http://www.w3.org/2005/Atom' href='http://avatar.identi.ca/46122-163-20100607195425.png' ns1:width='163' ns1:height='163' type='image/png' rel='avatar'/><link xmlns:ns1='http://purl.org/syndication/atommedia' xmlns='http://www.w3.org/2005/Atom' href='http://avatar.identi.ca/46122-96-20100607195425.png' ns1:width='96' ns1:height='96' type='image/png' rel='avatar'/><link xmlns:ns1='http://purl.org/syndication/atommedia' xmlns='http://www.w3.org/2005/Atom' href='http://avatar.identi.ca/46122-48-20100607195425.png' ns1:width='48' ns1:height='48' type='image/png' rel='avatar'/><link xmlns:ns1='http://purl.org/syndication/atommedia' xmlns='http://www.w3.org/2005/Atom' href='http://avatar.identi.ca/46122-24-20100607195425.png' ns1:width='24' ns1:height='24' type='image/png' rel='avatar'/><point xmlns='http://www.georss.org/georss'>-33.4262838 -70.5665588</point><preferredUsername xmlns='http://portablecontacts.net/spec/1.0'>magicdrums</preferredUsername><displayName xmlns='http://portablecontacts.net/spec/1.0'>Victor Pereira</displayName><note xmlns='http://portablecontacts.net/spec/1.0'>Padre, Esposo, IT Support, Intento de Geek, Hard Core, Ubuntero, Batero Frustado Linuxcero, Amante de mi Señora...</note><address xmlns='http://portablecontacts.net/spec/1.0'><formatted>ÜT: -33.527926,-70.655237</formatted></address><urls xmlns='http://portablecontacts.net/spec/1.0'><type>homepage</type><value>http://magicdrums.gnu-linux.cl</value><primary>true</primary></urls></actor><link href='http://identi.ca/notice/45259404' type='text/html' rel='alternate'/><id>http://identi.ca/notice/45259404</id><published>2010-08-06T13:52:15+00:00</published><updated>2010-08-06T13:52:15+00:00</updated><notice_info xmlns='http://status.net/schema/api/1/' source='Viigo' local_id='45259404'/><link href='http://identi.ca/notice/45255203' rel='related'/><in-reply-to xmlns='http://purl.org/syndication/thread/1.0' href='http://identi.ca/notice/45255203' ref='http://identi.ca/notice/45255203'/><link href='http://identi.ca/conversation/44928627' rel='ostatus:conversation'/><link href='http://identi.ca/user/119986' rel='ostatus:attention'/><link href='http://identi.ca/group/56/id' rel='ostatus:attention'/><content type='html'>RT @&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://identi.ca/user/119986&quot; class=&quot;url&quot; title=&quot;Mate Amargo {Nerds}&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;mateamargonerds&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;: Cursos !&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://identi.ca/group/56/id&quot; class=&quot;url&quot; title=&quot;GNU/Linux (linux)&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;Linux&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; avanzado &lt;a href=&quot;http://twitpic.com/2c3lnj&quot; title=&quot;http://twitpic.com/2c3lnj&quot; rel=&quot;external&quot;&gt;http://twitpic.com/2c3lnj&lt;/a&gt; !mateamargonerds | jajajaj !fb</content><category term='fb'/><category term='linux'/><category term='mateamargonerds'/><point xmlns='http://www.georss.org/georss'>-33.4262838 -70.5665588</point></entry></message></route>", "<route xmlns='http://jabberd.jabberstudio.org/ns/component/1.0' from='s2s' to='sm'><message xmlns='jabber:client' type='chat' xml:lang='en' to='test@chrome.pl' from='blip@blip.pl/blip'><body>Proponuję zmianę tematu. Porozmawiajmy o dinazaurach.</body></message></route>", "<route xmlns='http://jabberd.jabberstudio.org/ns/component/1.0' from='s2s' to='sm'><presence xmlns='jabber:client' from='anon%majesticmedia.ca@gtalk.jrudevels.org/gmail.E1D35514' to='test@chrome.pl'><status/><show>away</show><priority>0</priority><caps:c xmlns:caps='http://jabber.org/protocol/caps' xmlns='jabber:client' node='http://mail.google.com/xmpp/client/caps' ext='pmuc-v1 sms-v1 vavinvite-v1' ver='1.1'/><x xmlns='vcard-temp:x:update'><photo>86f065b95e82036afa1eb2180f846e60085f3138</photo></x></presence></route>" }; START_TEST (check_s2s_wrap) { const char *buf; int len, ns, sns, elem; nad_t nad = nad_parse(nadtxt[_i], 0); fprintf(stdout, "Original:\n%s\n", nadtxt[_i]); nad_print(nad, 0, &buf, &len); fprintf(stdout, "Parsed:\n%.*s\n", len, buf); /* rewrite server packets into client packets */ ns = nad_find_namespace(nad, 0, uri_SERVER, NULL); if(ns >= 0) { if(nad->elems[0].ns == ns) nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; else { for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; } nad_print(nad, 0, &buf, &len); fprintf(stdout, "Removed "uri_SERVER" namespace:\n%.*s\n", len, buf); } /* * If stanza is not in any namespace (either because we removed the * jabber:server namespace above or because it's in the default * namespace for this stream) then this packet is intended to be * handled by sm (and not just routed through the server), so set the * jabber:client namespace. */ if(ns >= 0 || nad->elems[0].ns < 0) { ns = nad_add_namespace(nad, uri_CLIENT, NULL); for(elem = 0; elem < nad->ecur; elem++) if(nad->elems[elem].ns == ns) nad->elems[elem].ns = nad->nss[nad->elems[elem].ns].next; nad->nss[ns].next = nad->elems[0].ns; nad->elems[0].ns = ns; nad->scope = -1; nad_print(nad, 0, &buf, &len); fprintf(stdout, "Added "uri_CLIENT" namespace:\n%.*s\n", len, buf); } nad->elems[0].my_ns = nad->elems[0].ns; nad_print(nad, 0, &buf, &len); fprintf(stdout, "Changed my_ns:\n%.*s\n", len, buf); /* wrap up the packet */ ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_print(nad, 0, &buf, &len); fprintf(stdout, "Added "uri_COMPONENT" namespace:\n%.*s\n", len, buf); nad_wrap_elem(nad, 0, ns, "route"); nad_print(nad, 0, &buf, &len); fprintf(stdout, "Wrapped in 'route' element:\n%.*s\n", len, buf); nad_set_attr(nad, 0, -1, "to", "sm", 0); nad_set_attr(nad, 0, -1, "from", "s2s", 0); nad_print(nad, 0, &buf, &len); fprintf(stdout, "Mangled packet:\n%.*s\n", len, buf); fprintf(stdout, "--------------------------------------------------------------\n"); ck_assert_int_eq (strlen(nadmangled[_i]), len); fail_if (strncmp(nadmangled[_i], buf, len)); nad_free(nad); } END_TEST START_TEST (check_leaf_path) { const char *buf; int len, elem; const char *nad_test = "<iq type='set'>\n\ <pubsub node='node1' b='2'>\n\ <options/>\n\ </pubsub>\n\ <test d='3'/>\n\ </iq>"; nad_t nad = nad_parse(nad_test, 0); fprintf(stdout, "Original:\n%s\n", nad_test); nad_print(nad, 0, &buf, &len); fprintf(stdout, "Parsed:\n%.*s\n", len, buf); elem = nad_find_elem_path(nad, 0, -1, "pubsub/options"); ck_assert_int_eq(2, elem); nad_free(nad); } END_TEST Suite* s2s_wrapper_suite (void) { Suite *s = suite_create ("s2s incoming packet wrapper"); TCase *tc_wrapper = tcase_create ("Wrapper"); tcase_add_loop_test (tc_wrapper, check_s2s_wrap, 0, NADTXT_COUNT); suite_add_tcase (s, tc_wrapper); TCase *tc_nad_find_elem_path = tcase_create ("nad_find_elem_path"); tcase_add_test (tc_nad_find_elem_path, check_leaf_path); suite_add_tcase (s, tc_nad_find_elem_path); return s; } int main (void) { int number_failed; Suite *s = s2s_wrapper_suite (); SRunner *sr = srunner_create (s); srunner_run_all (sr, CK_NORMAL); number_failed = srunner_ntests_failed (sr); srunner_free (sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/empty.xml��������������������������������������������������������������0000664�0000000�0000000�00000000010�12614627753�0017610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<empty/>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/failed_to_load_002.xml�������������������������������������������������0000664�0000000�0000000�00000000017�12614627753�0021767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<failed_to_load�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/failed_to_load_003.xml�������������������������������������������������0000664�0000000�0000000�00000000160�12614627753�0021767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_test> <test_key_expanded_no_var>asdfgh${invalid}zxcvbn</test_key_expanded_no_var> --> </config_test>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/failed_to_load_004.xml�������������������������������������������������0000664�0000000�0000000�00000000172�12614627753�0021773�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_test> <use_defined_later>asdfgh${later}zxcvbn</use_defined_later> --> <later>qwerty</later> </config_test>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/include_me.xml���������������������������������������������������������0000664�0000000�0000000�00000000024�12614627753�0020563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_in_subdir/> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/includeme2.xml���������������������������������������������������������0000664�0000000�0000000�00000000024�12614627753�0020506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_in_subdir/> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/subdir/����������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017231�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/subdir/includeme.xml���������������������������������������������������0000664�0000000�0000000�00000000024�12614627753�0021714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_in_subdir/> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/test_config.xml��������������������������������������������������������0000664�0000000�0000000�00000001513�12614627753�0020767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<config_test> <id>id_from_config</id> <value_with_id>value if id is ${id}</value_with_id> <test> <value>1234567</value> </test> <another> <test> <value>111${test.value}222</value> </test> </another> <test_key>qwerty</test_key> <test_key_expanded>asdfgh${test_key}zxcvbn</test_key_expanded> <!-- <test_key_expanded_no_var>asdfgh${invalid}zxcvbn</test_key_expanded_no_var> --> <!-- <use_defined_later>asdfgh${later}zxcvbn</use_defined_later> --> <later>qwerty</later> <use_defined_above>asdfgh${later}zxcvbn</use_defined_above> <simple_value/> <multiple> <val>1</val> <val>2</val> <val>3</val> <simple/> <simple/> <simple/> <simple/> </multiple> <simple_value_with_attr attr1='val1' attr2='val2' /> <simple_value_with_attr/> </config_test>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tests/test_include.xml�������������������������������������������������������0000664�0000000�0000000�00000000142�12614627753�0021142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<test_cfg> <include>includeme2.xml</include> <include>subdir/includeme.xml</include> </test_cfg>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015737�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/Makefile.am������������������������������������������������������������0000664�0000000�0000000�00000001306�12614627753�0017773�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet bin_SCRIPTS = jabberd EXTRA_DIST = db-setup.mysql db-update.mysql db-setup.pgsql db-update.pgsql db-setup.oracle db-setup.sqlite db-update.sqlite \ jabberd.in jabberd.rc pipe-auth.pl jabberd-authpipe-pam-0.1.pl pam_jabberd jabberd2.schema \ db-jd14-2-jd2.sql migrate-jd14dir-2-sqlite.pl migrate.pl \ bdb2mysql.rb bdbdump.pl edit = sed \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@VERSION\@,$(VERSION),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@libexecdir\@,$(libexecdir),g' $(bin_SCRIPTS): $(EXTRA_DIST) @echo "generating $@ from $@.in"; \ rm -f $@ $@.tmp; \ $(edit) < @srcdir@/$@.in > $@.tmp; \ chmod +x $@.tmp; \ mv $@.tmp $@ clean-local: rm -f $(bin_SCRIPTS) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/bdb2mysql.rb�����������������������������������������������������������0000664�0000000�0000000�00000010656�12614627753�0020173�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/ruby # bdb2msql.rb - Migrate the jabberd2 data in sm.db and authreg.db to MySQL # # Warning! This tool has not widely been tested! Use at your own risk # # Copyright (C) 2007 by Daniel Willmann <daniel@totalueberwachung.de> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Public License as published by # the Free Software Foundation; version 2 of the license. # # 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 Lesser Public License for more details. require 'optparse' require 'mysql' require 'bdb' class Table def initialize(name) @table = name @map = Array.new() end def name @table end def self.FORMAT return @FORMAT end def FORMAT return self.class.FORMAT end def self.FIELDS return @FIELDS end def FIELDS return self.class.FIELDS end def feeddb(db) db.each_key { |dbkey| map = Hash.new() list = db[dbkey].unpack(self.class.FORMAT) list.each_index { |index| map[self.FIELDS[index]] = list[index] } @map << map } end def to_sql def escape(str) if (str.class == String) "'" + Mysql.quote(str) + "'" else str end end tmplist = [ ] @map.each { |row| tmplist << "INSERT INTO `#{@table}` (`#{row.keys.join('`, `')}`) VALUES (#{row.values.collect{|str| escape(str)}.join(', ')})" } return tmplist end end class Authreg <Table @FIELDS = ["username", "realm", "password"] @FORMAT = "A257 A257 A257" # xx for padding so that the integer is aligned # @FIELDS = ["username", "realm", "password", "token", "sequence", "hash"] # @FORMAT = "A257 A257 A257 A11 xxi A41" # xx for padding so that the integer is aligned end class Sm <Table def feeddb(db) db.each { |colown, pairs| map = { } map['collection-owner'] = colown if (pairs == nil) # puts "No entry for collection-owner == #{colown}" next end while (pairs.length > 0) key = pairs[0...pairs.index(0)] pairs = pairs[pairs.index(0)+1..-1] vtype = pairs.unpack('i')[0] pairs = pairs[4..-1] case vtype when 0,1 value = pairs.unpack('i') pairs = pairs[4..-1] when 2,3 value = pairs[0...pairs.index(0)] pairs = pairs[pairs.index(0)+1..-1] else raise "Invalid type encountered #{vtype}! Key was #{key}" end map[key] = value # puts "Key #{key}" # puts "Type #{vtype}" # puts "Value #{value}" end # puts map.inspect @map << map } end end options = {:user => 'jabberd2', :host => 'localhost', :db => 'jabberd2', :apply => false} opts = OptionParser.new do |opts| opts.banner = "Usage: #{$0} [options] <bdbdir>" opts.on("-a", "--apply", "Modify the mysql database") do |v| options[:apply] = v end opts.on("-u", "--user <username>", "Mysql username") do |v| options[:user] = v end opts.on("-p", "--password <password>", "Mysql password") do |v| options[:password] = v end opts.on("-h", "--host <hostname>", "Host the mysql server runs on") do |v| options[:host] = v end opts.on("-d", "--db <database>", "Which database to use") do |v| options[:db] = v end end opts.parse! if (ARGV.length == 0) puts opts.help exit 1 end authregfile = ARGV[0] + "authreg.db" smfile = ARGV[0] + "sm.db" tables = [ ] puts "Looking for authreg.db in #{authregfile}" db = BDB::Btree.open(authregfile, nil, BDB::RDONLY) authreg = Authreg.new('authreg') db.each_key { |sub| subdb = BDB::Hash.open(authregfile, sub, BDB::RDONLY) authreg.feeddb(subdb) } tables << authreg puts "Looking for sm.db in #{smfile}" db = BDB::Btree.open(smfile, nil, BDB::RDONLY) db.each_key { |sub| # puts "Found Table #{sub}" sm = Sm.new(sub) subdb = BDB::Hash.open(smfile, sub, BDB::RDONLY) sm.feeddb(subdb) tables << sm } if (options[:apply]) mydb = Mysql.real_connect(options[:host], options[:user], options[:password], options[:db]) end tables.each { |tbl| if (!options[:apply]) puts "Table #{tbl.name}" tbl.to_sql.each {|statement| puts statement } else puts "Adding statements for table #{tbl.name}" tbl.to_sql.each {|statement| mydb.query(statement) } end } if (options[:apply]) puts "Database updated" else puts "Not modified the database" end ����������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/bdbdump.pl�������������������������������������������������������������0000664�0000000�0000000�00000011442�12614627753�0017713�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w ################################################################################ # dumpbdb.pl # # Dump a Jabberd2 SM BerkeleyDB. # # The DB file given on the command line is dumped as an XML file to stdout. # # NB: # - integer types are hard-coded to be 4 bytes LSB # # (c) 2007 Harald Braumann <harry@unheit.net> # # This software 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 3 of the License, or # (at your option) any later version. # # This package 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 can view the GNU General Public License at # http://www.gnu.org/licenses/gpl.html. # ################################################################################ use BerkeleyDB; # set to one to enable debug output $DEBUG = 1; # berkeleydb file $db_file = ""; # object type identifiers %db_object_types = (0 => "boolean", 1 => "integer", 2 => "string", 3 => "nad", 4 => "unknown"); # used for the print_ident function $indent = 0; $inc_indent = 2; sub trc { $0 =~ s,.*/,,; print STDERR "$0: @_\n"; } sub trcdebug { trc("@_") if $DEBUG; } sub error { trc("@_"); exit 1; } sub usage { trc <<EOF usage dumpdb <db file> EOF } sub options { $db_file = shift(@ARGV) || usage() && error; } #print_indent $str sub print_indent { my $str = shift; printf("%*s%s", $indent, "", $str); } # get_string $value # $value is an array ref # strings are delimited by a binary 0 sub get_string { my $value = shift; my $pos; for ($pos = 0; ord($value->[$pos]) != 0; $pos++) {} my @str_arr = splice(@$value, 0, $pos); splice(@$value, 0, 1); # remove the 0 return join('', @str_arr); } # get_int $value # $value is an array ref # int is encoded 4 bytes LSB sub get_int { my $value = shift; my $int = ord($value->[3]) << 24 | ord($value->[2]) << 16 | ord($value->[1]) << 8 | ord($value->[0]); splice(@$value, 0, 4); return $int; } #dump_fields $value sub dump_fields { my @value = split(//, shift); my $cur = 0; while ($#value > 0) { my $field = get_string(\@value); my $type_id = get_int(\@value); my $type = $db_object_types{$type_id}; defined $type || error("error: undefined type id: $type_id"); print_indent("<$field type=\"$type\">"); if ($type eq "integer") { printf("%i", get_int(\@value)); } elsif ($type eq "boolean") { printf("%s", get_int(\@value) > 0 ? "1" : "0"); } elsif ($type eq "string") { print("<![CDATA[".get_string(\@value)."]]>"); } elsif ($type eq "nad") { print("<![CDATA[".get_string(\@value)."]]>"); } elsif ($type eq "unknown") { trc("warn: `unknown\' type found. don't know how to parse!"); print("<![CDATA[".join('', @value)."]]>"); $#value = 0; } else { trc("warn: unknown type found!"); print("<![CDATA[".join('', @value)."]]>"); $#value = 0; } printf("</$field>\n"); } } #dump_db $db_name sub dump_db { my $db_name = shift; my $db; my $cursor; my ($key, $value) = ("", ""); trcdebug("dump db $db_name ..."); $db = new BerkeleyDB::Hash -Filename => $db_file, -Subname => $db_name, -Flags => DB_RDONLY || error("Error opening $db_file/$db_name: $BerkeleyDB::Error"); defined $db || error("Error opening $db_file/$db_name: $BerkeleyDB::Error"); $cursor = $db->db_cursor() || error "could not get cursor: $BerkeleyDB::Error" ; print_indent("<$db_name>\n"); $indent += $inc_indent; while ($cursor->c_get($key, $value, DB_NEXT) == 0) { print_indent("<entry key=\"$key\">\n"); $indent += $inc_indent; dump_fields($value); $indent -= $inc_indent; print_indent("</entry>\n"); } $indent -= $inc_indent; print_indent("</$db_name>\n"); trcdebug("dump db $db_name OK"); } options(); trcdebug("open db $db_file ..."); $db = new BerkeleyDB::Unknown -Filename => $db_file, -Flags => DB_RDONLY || error "error opening $db_file: $BerkeleyDB::Error"; defined $db || error "error opening $db_file: $BerkeleyDB::Error"; trcdebug("OK"); trcdebug("walking sub dbs ..."); $cursor = $db->db_cursor() || error "could not get cursor: $BerkeleyDB::Error" ; ($k, $v) = ("", "") ; print_indent("<sm-bdb>\n"); $indent += $inc_indent; while ($cursor->c_get($k, $v, DB_NEXT) == 0) { trcdebug("found sub db $k"); dump_db($k); } $indent -= $inc_indent; print_indent("</sm-bdb>\n"); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-jd14-2-jd2.sql������������������������������������������������������0000775�0000000�0000000�00000006104�12614627753�0020425�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This script migrates jabberd14 xdb_sql postgresql data -- to jabberd2 postgres storage -- -- \i db-setup.pgsql -- notatki: -- wszystko pozostale skonwertowac konwerterem jajcusia -- zmodyfikowac formularz modyfikacji danych usera -- zmodyfikowac proces odzyskiwania hasla ALTER TABLE recovery RENAME COLUMN mailaddress TO email; ALTER TABLE recovery ADD COLUMN "collection-owner" text; UPDATE recovery SET "collection-owner" = username || '@' || realm; ALTER TABLE recovery ALTER COLUMN "collection-owner" SET not null; ALTER TABLE recovery DROP COLUMN username; ALTER TABLE recovery DROP COLUMN realm; CREATE TABLE userdata ( "collection-owner" text PRIMARY KEY, lastmodified timestamp not null default current_timestamp, name varchar(256), email varchar(512), wwwstatus boolean not null default false, profilesearch boolean not null default true ); INSERT INTO userdata ("collection-owner",lastmodified,name,email,wwwstatus,profilesearch) SELECT u.username || '@' || u.realm, COALESCE(lastmodified,now()), name, mailaddress, wwwstatus, profilesearch FROM useroptions AS u LEFT JOIN mailaddresses AS m ON (u.username = m.username AND u.realm = m.realm); DROP TABLE mailaddresses; DROP TABLE useroptions; -- -- Drop unconvertable and unused tables first -- DROP TABLE presence; DROP TABLE roster; -- It's support is buggy in jabberd14 so I haven't used it. -- -- Convert user data -- ALTER TABLE authreg ADD COLUMN created timestamp DEFAULT current_timestamp; INSERT INTO authreg (username,realm,password) SELECT username,realm,password FROM users; DROP TABLE users; -- -- Convert offline storage -- ALTER TABLE queue ADD COLUMN storetime timestamp not null default current_timestamp; INSERT INTO queue ("collection-owner",xml,storetime) SELECT username || '@' || realm, xml, storetime FROM messages WHERE xml != ''; DROP TABLE messages; -- -- Convert vCard data -- INSERT INTO vcard ("collection-owner", "fn","nickname","url","tel","email","title","role", "bday","tz", "n-family","n-given","n-middle","n-prefix","n-suffix", "adr-street","adr-extadd","adr-pobox","adr-locality","adr-region","adr-pcode","adr-country", "geo-lat","geo-lon","org-orgname","org-orgunit","agent-extval","sort-string","desc","note", "photo-type","photo-binval","photo-extval","logo-type","logo-binval","logo-extval", "sound-phonetic","sound-binval","sound-extval","key-type","key-cred","rev" ) SELECT username || '@' || realm, display_name,nickname,homepage,landline,email,job_title,org_role, TRIM(TO_CHAR(birth_year,'0000'))||'-'||TRIM(TO_CHAR(birth_month,'00'))||'-'||TRIM(TO_CHAR(birth_dayofmonth,'00')),'', family_name,given_name,middle_name,name_prefix,name_suffix, street,building || ' / ' || room,postalbox,locality,region,postalcode,country, lat,lon,org_name,org_unit,'','',description,'JEP-0054 vcard-temp', photo_data_mime,photo_data,photo_url,'','','', '','','','',pgpkey,timestamp FROM userprofile; DROP TABLE userprofile; -- -- Convert iq-last data -- INSERT INTO logout ("collection-owner",time) SELECT username || '@' || realm, (substring(substring(xml from 'last=.[0-9]+') from '[0-9]+'))::integer FROM last; DROP TABLE last; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-setup.mysql���������������������������������������������������������0000664�0000000�0000000�00000013102�12614627753�0020546�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This is the required schema for MySQL. Load this into the database -- using the mysql interactive terminal: -- -- mysql> \. db-setup.mysql -- CREATE DATABASE jabberd2; USE jabberd2; -- -- c2s authentication/registration table -- CREATE TABLE `authreg` ( `username` TEXT, KEY `username` (`username`(255)), `realm` TINYTEXT, KEY `realm` (`realm`(255)), `password` TINYTEXT ) DEFAULT CHARSET=UTF8; -- -- Session manager tables -- -- -- Active (seen) users -- Used by: core -- CREATE TABLE `active` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `time` INT ) DEFAULT CHARSET=UTF8; -- -- Logout times -- Used by: mod_iq_last -- CREATE TABLE `logout` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `time` INT ) DEFAULT CHARSET=UTF8; -- -- Roster items -- Used by: mod_roster -- CREATE TABLE `roster-items` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `jid` TEXT, `name` TEXT, `to` TINYINT, `from` TINYINT, `ask` INT ) DEFAULT CHARSET=UTF8; -- -- Roster groups -- Used by: mod_roster -- CREATE TABLE `roster-groups` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `jid` TEXT, `group` TEXT ) DEFAULT CHARSET=UTF8; -- -- vCard (user profile information) -- Used by: mod_iq_vcard -- CREATE TABLE `vcard` ( `collection-owner` VARCHAR(255) NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `fn` VARCHAR(255), `nickname` VARCHAR(255), `url` VARCHAR(255), `tel` VARCHAR(255), `email` VARCHAR(255), `jabberid` VARCHAR(3071), `mailer` VARCHAR(1023), `title` VARCHAR(255), `role` VARCHAR(255), `bday` VARCHAR(255), # Shouldn't this be a DATE? `tz` VARCHAR(7), `n-family` VARCHAR(255), `n-given` VARCHAR(255), `n-middle` VARCHAR(255), `n-prefix` VARCHAR(255), `n-suffix` VARCHAR(255), `adr-street` VARCHAR(255), `adr-extadd` VARCHAR(255), `adr-pobox` VARCHAR(15), `adr-locality` VARCHAR(255), `adr-region` VARCHAR(255), `adr-pcode` VARCHAR(31), `adr-country` VARCHAR(63), `geo-lat` VARCHAR(255), `geo-lon` VARCHAR(255), `org-orgname` VARCHAR(255), `org-orgunit` VARCHAR(255), `agent-extval` VARCHAR(255), `sort-string` VARCHAR(255), `desc` TEXT, `note` TEXT, `uid` VARCHAR(255), `photo-type` VARCHAR(127), `photo-binval` TEXT, `photo-extval` VARCHAR(255), `logo-type` VARCHAR(127), `logo-binval` TEXT, `logo-extval` VARCHAR(255), `sound-phonetic` VARCHAR(255), `sound-binval` TEXT, `sound-extval` VARCHAR(255), `key-type` VARCHAR(127), `key-cred` TEXT, `rev` VARCHAR(255) ) DEFAULT CHARSET=UTF8; -- -- Offline message queue -- Used by: mod_offline -- CREATE TABLE `queue` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `xml` MEDIUMTEXT ) DEFAULT CHARSET=UTF8; -- -- Private XML storage -- Used by: mod_iq_private -- CREATE TABLE `private` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `ns` TEXT, `xml` MEDIUMTEXT ) DEFAULT CHARSET=UTF8; -- -- Message Of The Day (MOTD) messages (announcements) -- Used by: mod_announce -- CREATE TABLE `motd-message` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `xml` TEXT ) DEFAULT CHARSET=UTF8; -- -- Times of last MOTD message for each user -- Used by: mod_announce -- CREATE TABLE `motd-times` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `time` INT ) DEFAULT CHARSET=UTF8; -- -- Default privacy list -- Used by: mod_privacy -- CREATE TABLE `privacy-default` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `default` text ) DEFAULT CHARSET=UTF8; -- -- Privacy lists -- Used by: mod_privacy -- CREATE TABLE `privacy-items` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `list` TEXT, `type` TEXT, `value` TEXT, `deny` TINYINT, `order` INT, `block` INT ) DEFAULT CHARSET=UTF8; -- -- Vacation settings -- Used by: mod_vacation -- CREATE TABLE `vacation-settings` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`), `start` INT, `end` INT, `message` TEXT ) DEFAULT CHARSET=UTF8; -- -- Users statuses -- Used by: mod_status -- CREATE TABLE `status` ( `collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)), `object-sequence` BIGINT NOT NULL AUTO_INCREMENT, KEY(`object-sequence`), `status` TEXT NOT NULL, `show` TEXT NOT NULL, `last-login` INT DEFAULT '0', `last-logout` INT DEFAULT '0', `xml` TEXT ) DEFAULT CHARSET=UTF8; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-setup.oracle��������������������������������������������������������0000664�0000000�0000000�00000023622�12614627753�0020656�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************ * This is the schema for Oracle. * * To make it actually work, you need: * - create database with UTF8 as default charsets, * both for NLS_CHARACTERSET and NLS_NCHAR_CHARACTERSET * - set environment variable NLS_LANG to .UTF8 * $ export NLS_LANG=.UTF8 * for the user the server is running as * * The following code is used to remove the tables: * * DROP TABLE "authreg" CASCADE CONSTRAINTS; * DROP TABLE "active" CASCADE CONSTRAINTS; * DROP TABLE "logout" CASCADE CONSTRAINTS; * DROP TABLE "roster-items" CASCADE CONSTRAINTS; * DROP TABLE "roster-groups" CASCADE CONSTRAINTS; * DROP TABLE "vcard" CASCADE CONSTRAINTS; * DROP TABLE "queue" CASCADE CONSTRAINTS; * DROP TABLE "private" CASCADE CONSTRAINTS; * DROP TABLE "motd-message" CASCADE CONSTRAINTS; * DROP TABLE "motd-times" CASCADE CONSTRAINTS; * DROP TABLE "disco-items" CASCADE CONSTRAINTS; * DROP TABLE "privacy-default" CASCADE CONSTRAINTS; * DROP TABLE "privacy-items" CASCADE CONSTRAINTS; * DROP TABLE "vacation-settings" CASCADE CONSTRAINTS; * DROP SEQUENCE "seq-active"; * DROP SEQUENCE "seq-logout"; * DROP SEQUENCE "seq-roster-items"; * DROP SEQUENCE "seq-roster-groups"; * DROP SEQUENCE "seq-vcard"; * DROP SEQUENCE "seq-queue"; * DROP SEQUENCE "seq-private"; * DROP SEQUENCE "seq-motd-message"; * DROP SEQUENCE "seq-motd-times"; * DROP SEQUENCE "seq-disco-items"; * DROP SEQUENCE "seq-privacy-default"; * DROP SEQUENCE "seq-privacy-items"; * DROP SEQUENCE "seq-vacation-settings"; */ CREATE TABLE "authreg" ( "username" varchar2(256), "realm" varchar2(256), "password" varchar2(256) ); CREATE SEQUENCE "seq-active" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-logout" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-roster-items" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-roster-groups" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-vcard" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-queue" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-private" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-motd-message" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-motd-times" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-disco-items" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-privacy-default" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-privacy-items" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; CREATE SEQUENCE "seq-vacation-settings" INCREMENT BY 1 START WITH 1 MINVALUE 1 NOCYCLE NOCACHE NOORDER; /* * Session manager tables * * * Active (seen) users * Used by: core */ CREATE TABLE "active" ( "collection-owner" varchar2(4000), "object-sequence" number, "time" number ); CREATE OR REPLACE TRIGGER "active-object-sequence" BEFORE INSERT ON "active" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-active".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "active" ADD ( PRIMARY KEY ("collection-owner")); /* * Logout times * Used by: mod_iq_last */ CREATE TABLE "logout" ( "collection-owner" varchar2(4000), "object-sequence" number, "time" number ); CREATE OR REPLACE TRIGGER "logout-object-sequence" BEFORE INSERT ON "logout" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-logout".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "logout" ADD ( PRIMARY KEY ("collection-owner")); /* * Roster items * Used by: mod_roster */ CREATE TABLE "roster-items" ( "collection-owner" varchar2(4000), "object-sequence" number, "jid" varchar2(4000), "name" varchar2(4000), "to" char(1), "from" char(1), "ask" number ); CREATE OR REPLACE TRIGGER "roster-items-object-sequence" BEFORE INSERT ON "roster-items" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-roster-items".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "roster-items-collection-owner" ON "roster-items"("collection-owner"); CREATE INDEX "roster-items-jid" ON "roster-items"("jid"); /* * Roster groups * Used by: mod_roster */ CREATE TABLE "roster-groups" ( "collection-owner" varchar2(4000), "object-sequence" number, "jid" varchar2(4000), "group" varchar2(4000) ); CREATE OR REPLACE TRIGGER "roster-groups-object-sequence" BEFORE INSERT ON "roster-groups" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-roster-groups".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "roster-groups-collection-owner" ON "roster-groups"("collection-owner"); CREATE INDEX "roster-groups-jid" ON "roster-groups"("jid"); /* * vCard (user profile information) * Used by: mod_iq_vcard */ CREATE TABLE "vcard" ( "collection-owner" varchar2(4000), "object-sequence" number, "fn" varchar2(4000), "nickname" varchar2(4000), "url" varchar2(4000), "tel" varchar2(4000), "email" varchar2(4000), "jabberid" varchar2(4000), "mailer" varchar2(4000), "title" varchar2(4000), "role" varchar2(4000), "bday" varchar2(4000), "desc" varchar2(4000), "n-given" varchar2(4000), "n-family" varchar2(4000), "adr-street" varchar2(4000), "adr-extadd" varchar2(4000), "adr-locality" varchar2(4000), "adr-region" varchar2(4000), "adr-pcode" varchar2(4000), "adr-country" varchar2(4000), "org-orgname" varchar2(4000), "org-orgunit" varchar2(4000), "uid" varchar2(4000) ); CREATE OR REPLACE TRIGGER "vcard-object-sequence" BEFORE INSERT ON "vcard" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-vcard".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "vcard-collection-owner" ON "vcard"("collection-owner"); /* * Offline message queue * Used by: mod_offline */ CREATE TABLE "queue" ( "collection-owner" varchar2(4000), "object-sequence" number, "xml" varchar2(4000) ); CREATE OR REPLACE TRIGGER "queue-object-sequence" BEFORE INSERT ON "queue" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-queue".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "queue-collection-owner" ON "queue"("collection-owner"); /* * Private XML storage * Used by: mod_iq_private */ CREATE TABLE "private" ( "collection-owner" varchar2(4000), "object-sequence" number, "ns" varchar2(4000), "xml" varchar2(4000) ); CREATE OR REPLACE TRIGGER "private-object-sequence" BEFORE INSERT ON "private" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-private".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "private-collection-owner" ON "private"("collection-owner"); /* * Message Of The Day (MOTD) messages (announcements) * Used by: mod_announce */ CREATE TABLE "motd-message" ( "collection-owner" varchar2(4000), "object-sequence" number, "xml" varchar2(4000) ); CREATE OR REPLACE TRIGGER "motd-message-object-sequence" BEFORE INSERT ON "motd-message" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-motd-message".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "motd-message" ADD ( PRIMARY KEY ("collection-owner")); /* * Times of last MOTD message for each user * Used by: mod_announce */ CREATE TABLE "motd-times" ( "collection-owner" varchar2(4000), "object-sequence" number, "time" number ); CREATE OR REPLACE TRIGGER "motd-times-object-sequence" BEFORE INSERT ON "motd-times" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-motd-times".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "motd-times" ADD ( PRIMARY KEY ("collection-owner")); /* * Default privacy list * Used by: mod_privacy */ CREATE TABLE "privacy-default" ( "collection-owner" varchar2(4000), "object-sequence" number, "default" varchar2(4000) ); CREATE OR REPLACE TRIGGER "privacy-default-object-seq" BEFORE INSERT ON "privacy-default" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-privacy-default".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "privacy-default" ADD ( PRIMARY KEY ("collection-owner")); /* * Privacy lists * Used by: mod_privacy */ CREATE TABLE "privacy-items" ( "collection-owner" varchar2(4000), "object-sequence" number, "list" varchar2(4000), "type" varchar2(4000), "value" varchar2(4000), "deny" char(1), "order" number, "block" number ); CREATE OR REPLACE TRIGGER "privacy-items-object-sequence" BEFORE INSERT ON "privacy-items" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-privacy-items".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; CREATE INDEX "privacy-items-collection-owner" ON "privacy-items"("collection-owner"); /* * Vacation settings * Used by: mod_vacation */ CREATE TABLE "vacation-settings" ( "collection-owner" varchar2(4000), "object-sequence" number, "start" number, "end" number, "message" varchar2(4000) ); CREATE OR REPLACE TRIGGER "vacation-settings-object-seq" BEFORE INSERT ON "vacation-settings" FOR EACH ROW BEGIN IF :NEW."object-sequence" IS NULL THEN SELECT "seq-vacation-settings".NextVal INTO :NEW."object-sequence" FROM dual; END IF; END; / SHOW ERRORS; ALTER TABLE "vacation-settings" ADD ( PRIMARY KEY ("collection-owner")); ��������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-setup.pgsql���������������������������������������������������������0000664�0000000�0000000�00000012226�12614627753�0020535�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This is the required schema for PostgreSQL. Load this into the -- database using the psql interactive terminal: -- -- template1=> \i db-setup.pgsql -- -- CREATE DATABASE jabberd2; -- \c jabberd2 CREATE SEQUENCE "object-sequence"; -- -- c2s authentication/registration table -- CREATE TABLE "authreg" ( "username" varchar(1023) NOT NULL, "realm" varchar(1023) NOT NULL, "password" varchar(256), PRIMARY KEY ("username", "realm") ); CREATE INDEX i_authreg_username ON "authreg"("username"); CREATE INDEX i_authreg_realm ON "authreg"("realm"); -- -- Session manager tables -- -- -- Active (seen) users -- Used by: core -- CREATE TABLE "active" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "time" integer NOT NULL DEFAULT 0 ); -- -- Logout times -- Used by: mod_iq_last -- CREATE TABLE "logout" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "time" integer NOT NULL DEFAULT 0 ); -- -- Roster items -- Used by: mod_roster -- CREATE TABLE "roster-items" ( "collection-owner" text NOT NULL, "object-sequence" bigint DEFAULT nextval('object-sequence'), "jid" text NOT NULL, "name" text, "to" boolean NOT NULL, "from" boolean NOT NULL, "ask" integer NOT NULL, PRIMARY KEY ("collection-owner", "jid") ); CREATE INDEX i_rosteri_owner ON "roster-items"("collection-owner"); -- -- Roster groups -- Used by: mod_roster -- CREATE TABLE "roster-groups" ( "collection-owner" text NOT NULL, "object-sequence" bigint DEFAULT nextval('object-sequence'), "jid" text NOT NULL, "group" text NOT NULL, PRIMARY KEY ("collection-owner", "jid", "group") ); CREATE INDEX i_rosterg_owner ON "roster-groups"("collection-owner"); CREATE INDEX i_rosterg_owner_jid ON "roster-groups"("collection-owner", "jid"); -- -- vCard (user profile information) -- Used by: mod_iq_vcard -- CREATE TABLE "vcard" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "fn" text, "nickname" text, "url" text, "tel" text, "email" text, "jabberid" text, "mailer" text, "title" text, "role" text, "bday" text, "tz" text, "n-family" text, "n-given" text, "n-middle" text, "n-prefix" text, "n-suffix" text, "adr-street" text, "adr-extadd" text, "adr-pobox" text, "adr-locality" text, "adr-region" text, "adr-pcode" text, "adr-country" text, "geo-lat" text, "geo-lon" text, "org-orgname" text, "org-orgunit" text, "agent-extval" text, "sort-string" text, "desc" text, "note" text, "uid" text, "photo-type" text, "photo-binval" text, "photo-extval" text, "logo-type" text, "logo-binval" text, "logo-extval" text, "sound-phonetic" text, "sound-binval" text, "sound-extval" text, "key-type" text, "key-cred" text, "rev" text ); -- -- Offline message queue -- Used by: mod_offline -- CREATE TABLE "queue" ( "collection-owner" text NOT NULL, "object-sequence" bigint DEFAULT nextval('object-sequence'), "xml" text NOT NULL ); CREATE INDEX i_queue_owner ON "queue"("collection-owner"); -- -- Private XML storage -- Used by: mod_iq_private -- CREATE TABLE "private" ( "collection-owner" text NOT NULL, "object-sequence" bigint DEFAULT nextval('object-sequence'), "ns" text, "xml" text, PRIMARY KEY ("collection-owner", "ns") ); CREATE INDEX i_private_owner ON "private"("collection-owner"); -- -- Message Of The Day (MOTD) messages (announcements) -- Used by: mod_announce -- CREATE TABLE "motd-message" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "xml" text NOT NULL); -- -- Times of last MOTD message for each user -- Used by: mod_announce -- CREATE TABLE "motd-times" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "time" integer NOT NULL); -- -- Default privacy list -- Used by: mod_privacy -- CREATE TABLE "privacy-default" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "default" text ); -- -- Privacy lists -- Used by: mod_privacy -- CREATE TABLE "privacy-items" ( "collection-owner" text NOT NULL, "object-sequence" bigint DEFAULT nextval('object-sequence'), "list" text NOT NULL, "type" text, "value" text, "deny" boolean, "order" integer, "block" integer ); CREATE INDEX i_privacyi_owner ON "privacy-items"("collection-owner"); -- -- Vacation settings -- Used by: mod_vacation -- CREATE TABLE "vacation-settings" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint DEFAULT nextval('object-sequence'), "start" integer, "end" integer, "message" text ); -- -- User status information -- Used by: mod_status -- CREATE TABLE "status" ( "collection-owner" text PRIMARY KEY, "object-sequence" bigint, "status" text NOT NULL, "show" text, "last-login" int DEFAULT '0', "last-logout" int DEFAULT '0', "xml" text ); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-setup.sqlite��������������������������������������������������������0000664�0000000�0000000�00000012445�12614627753�0020713�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This is the required schema for sqlite. -- -- sqlite3 db/sqlite.db < tools/db-setup.sqlite -- -- -- c2s authentication/registration table -- CREATE TABLE "authreg" ( "username" TEXT NOT NULL, "realm" TEXT NOT NULL, "password" TEXT ); CREATE INDEX i_authreg_username ON "authreg"("username"); CREATE INDEX i_authreg_realm ON "authreg"("realm"); -- -- Session manager tables -- -- -- Active (seen) users -- Used by: core -- CREATE TABLE "active" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "time" INTEGER NOT NULL DEFAULT 0 ); -- -- Logout times -- Used by: mod_iq_last -- CREATE TABLE "logout" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "time" INTEGER NOT NULL DEFAULT 0 ); -- -- Roster items -- Used by: mod_roster -- CREATE TABLE "roster-items" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "jid" TEXT NOT NULL, "name" TEXT, "to" BOOLEAN NOT NULL, "from" BOOLEAN NOT NULL, "ask" INTEGER NOT NULL ); CREATE INDEX i_rosteri_owner ON "roster-items"("collection-owner"); -- -- Roster groups -- Used by: mod_roster -- CREATE TABLE "roster-groups" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "jid" TEXT NOT NULL, "group" TEXT NOT NULL ); CREATE INDEX i_rosterg_owner ON "roster-groups"("collection-owner"); CREATE INDEX i_rosterg_owner_jid ON "roster-groups"("collection-owner", "jid"); -- -- Published roster items -- Used by: mod_roster_publish -- CREATE TABLE "published-roster" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "jid" TEXT NOT NULL, "group" TEXT, "name" TEXT, "to" BOOLEAN NOT NULL, "from" BOOLEAN NOT NULL, "ask" INTEGER NOT NULL ); CREATE INDEX i_pubrosteri_owner ON "published-roster"("collection-owner"); -- -- Published roster groups -- Used by: mod_roster_publish -- CREATE TABLE "published-roster-groups" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "groupname" TEXT NOT NULL ); CREATE INDEX i_pubrosterg_owner ON "published-roster-groups"("collection-owner"); -- -- vCard (user profile information) -- Used by: mod_iq_vcard -- CREATE TABLE "vcard" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "fn" TEXT, "nickname" TEXT, "url" TEXT, "tel" TEXT, "email" TEXT, "jabberid" TEXT, "mailer" TEXT, "title" TEXT, "role" TEXT, "bday" TEXT, "tz" TEXT, "n-family" TEXT, "n-given" TEXT, "n-middle" TEXT, "n-prefix" TEXT, "n-suffix" TEXT, "adr-street" TEXT, "adr-extadd" TEXT, "adr-pobox" TEXT, "adr-locality" TEXT, "adr-region" TEXT, "adr-pcode" TEXT, "adr-country" TEXT, "geo-lat" TEXT, "geo-lon" TEXT, "org-orgname" TEXT, "org-orgunit" TEXT, "agent-extval" TEXT, "sort-string" TEXT, "desc" TEXT, "note" TEXT, "uid" TEXT, "photo-type" TEXT, "photo-binval" TEXT, "photo-extval" TEXT, "logo-type" TEXT, "logo-binval" TEXT, "logo-extval" TEXT, "sound-phonetic" TEXT, "sound-binval" TEXT, "sound-extval" TEXT, "key-type" TEXT, "key-cred" TEXT, "rev" TEXT ); CREATE INDEX i_vcard_owner ON "vcard"("collection-owner"); -- -- Offline message queue -- Used by: mod_offline -- CREATE TABLE "queue" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "xml" TEXT NOT NULL ); CREATE INDEX i_queue_owner ON "queue"("collection-owner"); -- -- Private XML storage -- Used by: mod_iq_private -- CREATE TABLE "private" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "ns" TEXT, "xml" TEXT ); CREATE INDEX i_private_owner ON "private"("collection-owner"); -- -- Message Of The Day (MOTD) messages (announcements) -- Used by: mod_announce -- CREATE TABLE "motd-message" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "xml" TEXT NOT NULL ); -- -- Times of last MOTD message for each user -- Used by: mod_announce -- CREATE TABLE "motd-times" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "time" INTEGER NOT NULL ); -- -- Default privacy list -- Used by: mod_privacy -- CREATE TABLE "privacy-default" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "default" TEXT ); -- -- Privacy lists -- Used by: mod_privacy -- CREATE TABLE "privacy-items" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "list" TEXT NOT NULL, "type" TEXT, "value" TEXT, "deny" BOOL, "order" INTEGER, "block" INTEGER ); CREATE INDEX i_privacyi_owner ON "privacy-items"("collection-owner"); -- -- Vacation settings -- Used by: mod_vacation -- CREATE TABLE "vacation-settings" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "start" INTEGER, "end" INTEGER, "message" TEXT ); -- -- User status information -- Used by: mod_status -- CREATE TABLE "status" ( "collection-owner" text NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "status" TEXT NOT NULL, "show" TEXT, "last-login" INTEGER DEFAULT '0', "last-logout" INTEGER DEFAULT '0', "xml" TEXT ); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-update.mysql��������������������������������������������������������0000664�0000000�0000000�00000006717�12614627753�0020706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This updates and creates indexes for jabberd2 mysql databases created prior to 2.0s6. -- Run this using the mysql interactive terminal: -- -- mysql> \. db-update.mysql -- USE jabberd2; -- Change the primary keys on collection-owner to normal indexes so as not to -- enforce uniqueness on the first 255 chars of otherwise different JIDs ALTER TABLE `active` DROP PRIMARY KEY; ALTER TABLE `active` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `logout` DROP PRIMARY KEY; ALTER TABLE `logout` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `vcard` DROP PRIMARY KEY; ALTER TABLE `vcard` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `motd-message` DROP PRIMARY KEY; ALTER TABLE `motd-message` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `motd-times` DROP PRIMARY KEY; ALTER TABLE `motd-times` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `privacy-default` DROP PRIMARY KEY; ALTER TABLE `privacy-default` ADD INDEX ( `collection-owner` ( 255 ) ); -- Add indexes on collection-owner for tables that should have them ALTER TABLE `disco-items` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `roster-items` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `roster-groups` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `privacy-items` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `private` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `queue` ADD INDEX ( `collection-owner` ( 255 ) ); ALTER TABLE `vacation-settings` ADD INDEX ( `collection-owner` ( 255 ) ); -- Add indexes on username and realm for authreg ALTER TABLE `authreg` ADD INDEX ( `username` ( 255 ) ); ALTER TABLE `authreg` ADD INDEX ( `realm` ( 255 ) ); -- Change the field type of xml in queue and private to allow storage > 64K -- (MEDIUMTEXT will allow up to 16M) ALTER TABLE `queue` CHANGE `xml` `xml` MEDIUMTEXT DEFAULT NULL; ALTER TABLE `private` CHANGE `xml` `xml` MEDIUMTEXT DEFAULT NULL; -- Remove 256-char limit on username in authreg table ALTER TABLE `authreg` CHANGE `username` `username` TEXT DEFAULT NULL; --- Change keys on object-sequence to primary keys - note that mysql's index --- limit of 255 characters prevents the possibility of using collection-owner --- as the primary key (as a JID can be longer than that) ALTER TABLE `active` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `disco-items` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `logout` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `motd-message` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `motd-times` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `privacy-default` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `privacy-items` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `private` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `queue` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `roster-groups` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `roster-items` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `vacation-settings` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); ALTER TABLE `vcard` DROP INDEX `object-sequence` , ADD PRIMARY KEY ( `object-sequence` ); �������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-update.pgsql��������������������������������������������������������0000664�0000000�0000000�00000015111�12614627753�0020653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- upgrade script for jabberd2 -- \c jabberd2 -- ################################################################# -- changes from svn r2 -> r11 -- ################################################################# -- -- TABLE authreg ALTER TABLE "authreg" ALTER COLUMN "username" TYPE varchar(1023); ALTER TABLE "authreg" ALTER COLUMN "username" SET NOT NULL; ALTER TABLE "authreg" ALTER COLUMN "realm" TYPE varchar(1023); ALTER TABLE "authreg" ALTER COLUMN "realm" SET NOT NULL; -- -- TABLE logout ALTER TABLE "logout" ALTER COLUMN "time" SET NOT NULL; -- -- TABLE roster-items ALTER TABLE "roster-items" ALTER COLUMN "jid" SET NOT NULL; ALTER TABLE "roster-items" ADD PRIMARY KEY ("collection-owner", "jid"); ALTER TABLE "roster-items" ALTER COLUMN "to" SET NOT NULL; ALTER TABLE "roster-items" ALTER COLUMN "from" SET NOT NULL; ALTER TABLE "roster-items" ALTER COLUMN "ask" SET NOT NULL; ALTER TABLE "authreg" ADD PRIMARY KEY ("username", "realm"); -- -- TABLE roster-groups ALTER TABLE "roster-groups" ALTER COLUMN "jid" SET NOT NULL; ALTER TABLE "roster-groups" ALTER COLUMN "group" SET NOT NULL; ALTER TABLE "roster-groups" ADD PRIMARY KEY ("collection-owner", "jid", "group"); CREATE INDEX i_rosterg_owner ON "roster-groups"("collection-owner"); CREATE INDEX i_rosterg_owner_jid ON "roster-groups"("collection-owner", "jid"); -- -- TABLE vcard ALTER TABLE "vcard" ADD PRIMARY KEY ("collection-owner"); ALTER TABLE "vcard" ADD COLUMN "tz" TEXT; ALTER TABLE "vcard" ADD COLUMN "n-middle" TEXT; ALTER TABLE "vcard" ADD COLUMN "n-prefix" TEXT; ALTER TABLE "vcard" ADD COLUMN "n-suffix" TEXT; ALTER TABLE "vcard" ADD COLUMN "adr-pobox" TEXT; ALTER TABLE "vcard" ADD COLUMN "geo-lat" TEXT; ALTER TABLE "vcard" ADD COLUMN "geo-lon" TEXT; ALTER TABLE "vcard" ADD COLUMN "agent-extval" TEXT; ALTER TABLE "vcard" ADD COLUMN "sort-string" TEXT; ALTER TABLE "vcard" ADD COLUMN "note" TEXT; ALTER TABLE "vcard" ADD COLUMN "photo-type" TEXT; ALTER TABLE "vcard" ADD COLUMN "photo-binval" TEXT; ALTER TABLE "vcard" ADD COLUMN "photo-extval" TEXT; ALTER TABLE "vcard" ADD COLUMN "logo-type" TEXT; ALTER TABLE "vcard" ADD COLUMN "logo-binval" TEXT; ALTER TABLE "vcard" ADD COLUMN "logo-extval" TEXT; ALTER TABLE "vcard" ADD COLUMN "key-type" TEXT; ALTER TABLE "vcard" ADD COLUMN "key-cred" TEXT; ALTER TABLE "vcard" ADD COLUMN "rev" TEXT; -- -- TABLE queue ALTER TABLE "queue" ALTER COLUMN "xml" SET NOT NULL; CREATE INDEX i_queue_owner ON "queue"("collection-owner"); -- -- TABLE private ALTER TABLE "private" ALTER COLUMN "xml" SET NOT NULL; ALTER TABLE "private" ADD PRIMARY KEY ("collection-owner", "ns"); CREATE INDEX i_private_owner ON "private"("collection-owner"); -- -- TABLE motd-message ALTER TABLE "motd-message" ALTER COLUMN "xml" SET NOT NULL; -- -- TABLE motd-times ALTER TABLE "motd-times" ALTER COLUMN "time" SET NOT NULL; -- -- TABLE disco-items CREATE INDEX i_discoi_owner ON "disco-items"("collection-owner"); -- -- TABLE privacy-items ALTER TABLE "privacy-items" ALTER COLUMN "list" SET NOT NULL; CREATE INDEX i_privacyi_owner ON "privacy-items"("collection-owner"); -- -- TABLE status (new) CREATE TABLE "status" ( "collection-owner" TEXT PRIMARY KEY, "object-sequence" BIGINT, "status" TEXT NOT NULL, "show" TEXT, "last-login" INTEGER DEFAULT '0', "last-logout" INTEGER DEFAULT '0'); -- ################################################################# -- changes from svn r11 -> r16 -- tag: release_2_1 -- ################################################################# -- -- TABLE authreg ALTER TABLE "authreg" ADD PRIMARY KEY ("username", "realm"); CREATE INDEX i_authreg_username ON "authreg"("username"); CREATE INDEX i_authreg_realm ON "authreg"("realm"); -- -- TABLE active ALTER TABLE "active" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "active" ALTER COLUMN "time" SET NOT NULL; -- -- TABLE logout ALTER TABLE "logout" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "logout" ALTER COLUMN "time" SET NOT NULL; -- -- TABLE roster-items ALTER TABLE "roster-items" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "roster-items" ALTER COLUMN "collection-owner" SET NOT NULL; CREATE INDEX i_rosteri_owner ON "roster-items"("collection-owner"); -- -- TABLE roster-groups ALTER TABLE "roster-groups" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "roster-groups" ALTER COLUMN "collection-owner" SET NOT NULL; -- -- TABLE "vcard" ALTER TABLE "roster-groups" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); -- -- TABLE queue ALTER TABLE "queue" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "queue" ALTER COLUMN "collection-owner" SET NOT NULL; -- -- TABLE private ALTER TABLE "private" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "private" ALTER COLUMN "collection-owner" SET NOT NULL; -- -- TABLE motd-times ALTER TABLE "motd-times" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "motd-times" ALTER COLUMN "time" SET NOT NULL; -- -- TABLE disco-items ALTER TABLE "disco-items" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "disco-items" ALTER COLUMN "collection-owner" SET NOT NULL; -- -- TABLE privacy-default ALTER TABLE "privacy-default" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); -- -- TABLE privacy-items ALTER TABLE "privacy-items" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); ALTER TABLE "privacy-items" ALTER COLUMN "collection-owner" SET NOT NULL; -- -- TABLE vacation-settings ALTER TABLE "vacation-settings" ALTER COLUMN "object-sequence" SET DEFAULT NEXTVAL('object-sequence'); -- ##################################################################### -- changes from svn r16 -> r251 -- ##################################################################### ALTER TABLE "authreg" DROP COLUMN "token"; ALTER TABLE "authreg" DROP COLUMN "sequence"; ALTER TABLE "authreg" DROP COLUMN "hash"; -- ##################################################################### -- changes from svn r251 -> r431 -- ##################################################################### ALTER TABLE "status" ADD COLUMN "xml" TEXT; -- ##################################################################### -- changes from svn r431 -> r464 -- ##################################################################### ALTER TABLE "vcard" ADD COLUMN "jabberid" TEXT; ALTER TABLE "vcard" ADD COLUMN "mailer" TEXT; ALTER TABLE "vcard" ADD COLUMN "uid" TEXT; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/db-update.sqlite�������������������������������������������������������0000664�0000000�0000000�00000002255�12614627753�0021033�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- This updates jabberd2 sqlite databases created prior to 2.1.19. -- -- sqlite3 jabberd2.db < db-setup.sqlite -- ALTER TABLE "authreg" ADD COLUMN "token" TEXT; ALTER TABLE "authreg" ADD COLUMN "sequence" INTEGER; ALTER TABLE "authreg" ADD COLUMN "hash" TEXT; ALTER TABLE "vcard" ADD COLUMN "jabberid" TEXT; ALTER TABLE "vcard" ADD COLUMN "mailer" TEXT; ALTER TABLE "vcard" ADD COLUMN "uid" TEXT; ALTER TABLE "status" ADD COLUMN "xml" TEXT; -- -- Published roster items -- Used by: mod_roster_publish -- CREATE TABLE "published-roster" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "jid" TEXT NOT NULL, "group" TEXT, "name" TEXT, "to" BOOLEAN NOT NULL, "from" BOOLEAN NOT NULL, "ask" INTEGER NOT NULL ); CREATE INDEX i_pubrosteri_owner ON "published-roster"("collection-owner"); -- -- Published roster groups -- Used by: mod_roster_publish -- CREATE TABLE "published-roster-groups" ( "collection-owner" TEXT NOT NULL, "object-sequence" INTEGER PRIMARY KEY, "groupname" TEXT NOT NULL ); CREATE INDEX i_pubrosterg_owner ON "published-roster-groups"("collection-owner"); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/git��������������������������������������������������������������������0000664�0000000�0000000�00000000351�12614627753�0016444�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ChangeLog log format: git log --pretty=format:'%ai %aN <%aE>%n\t* %s\n' New release: git co -b 2.2.16 vim configure.ac git commit configure.ac -m "2.2.16 release" git tag jabberd-2.2.16 make dist git push github tag jabberd-2.2.16 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/jabberd-authpipe-pam-0.1.pl��������������������������������������������0000664�0000000�0000000�00000012376�12614627753�0022562�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w # # # jabberd-authpipe-pam.pl version 0.1 # Allows Jabber authentication against PAM without running jabberd as root. # # Copyright 2006 Nicholas J Humfrey # This code is hereby placed into the public domain. # # # Configure jabberd2 by editing c2s.xml: # # <module>pipe</module> # # <pipe> # <!-- Program to execute --> # <exec>/usr/local/libexec/jabberd-authpipe-pam.pl</exec> # </pipe> # # Place this script in /usr/local/libexec then run: # chown root jabberd-authpipe-pam.pl # chmod 4755 jabberd-authpipe-pam.pl # # This sets the script to run as suid root and gives it access to the # shadow password file. You man need to install perl-suid in order to # run perl scripts with the suid bit set. # # This script only implements the User-Exists and Check-Password routines. # See docs/dev/c2s-pipe-authenticator for details about the protocol. # # # To get this script to work with PSI, Ifound that I had to enable # "Allow Plaintext Login" in PSI. Please make sure that you use SSL # so that plain-text passwords aren't sent over the network. # # use strict; use MIME::Base64; use Authen::PAM qw(:constants); ### Start of Settings ### my $SERVICE_NAME = 'jabberd'; my $DEBUG = 0; ### End of Settings ##### open(STDERR, ">/tmp/jabber-authpipe.log") or die "Failed to open log"; # Flush output immediately. $| = 1; # On startup, we have to inform c2s of the functions we can deal with. print "OK USER-EXISTS CHECK-PASSWORD FREE\n"; # Our main loop my $buf; while(sysread (STDIN, $buf, 1024) > 0) { my ($cmd, @args) = split ' ', $buf; $cmd =~ tr/[a-z]/[A-Z]/; $cmd =~ tr/_/-/; if ($cmd eq 'USER-EXISTS') { print cmd_user_exists( @args ), "\n"; } elsif ($cmd eq 'CHECK-PASSWORD') { print cmd_check_password( @args ), "\n"; } elsif ($cmd eq 'FREE') { # c2s shutting down, do the same. last; } else { print STDERR "Unsupported command: '$cmd'\n" if ($DEBUG); print "NO\n"; } } # Determine if the requested user exists. sub cmd_user_exists { my ($user, $realm) = @_; my ($name,$passwd,$uid,$gid) = getpwnam($user); if (defined $name) { print STDERR "User '$user' exists with ID $uid.\n" if ($DEBUG); return "OK"; } else { print STDERR "User '$user' does not exist.\n" if ($DEBUG); return 'NO'; } } # Compare the given password with the stored password. sub cmd_check_password { my ($username, $encoded_pass, $realm) = @_; # Decode the password my $password = decode_base64($encoded_pass); return "NO" if not $password; my $handler = sub { my @response = (); while (@_) { my $code = shift; my $message = shift; my $answer = undef; if ( $code == PAM_PROMPT_ECHO_ON ) { $answer = $username; } if ( $code == PAM_PROMPT_ECHO_OFF ) { $answer = $password; } push( @response, PAM_SUCCESS, $answer ); } return ( @response, PAM_SUCCESS ); }; my $pam = Authen::PAM->new( $SERVICE_NAME, $username, $handler ); unless ( ref $pam ) { my $error = Authen::PAM->pam_strerror($pam); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } my $result = $pam->pam_authenticate; unless ( $result == PAM_SUCCESS ) { my $error = $pam->pam_strerror($result); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } $result = $pam->pam_acct_mgmt; unless ( $result == PAM_SUCCESS ) { my $error = $pam->pam_strerror($result); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } print STDERR "Successfully authenticated user '$username' using service '$SERVICE_NAME'.\n" if ($DEBUG); return 'OK'; } __END__ =head1 NAME jabberd-authpipe-pam - Allows Jabber authentication against PAM without running jabberd as root. =head1 VERSION This document describes version 0.1 of jabberd-authpipe-pam, released 25th December 2006. =head1 DESCRIPTION Configure jabberd2 by editing c2s.xml: <module>pipe</module> <pipe> <!-- Program to execute --> <exec>/usr/local/libexec/jabberd-authpipe-pam.pl</exec> </pipe> Place this script in /usr/local/libexec then run: chown root jabberd-authpipe-pam.pl chmod 4755 jabberd-authpipe-pam.pl This sets the script to run as suid root and gives it access to the shadow password file. You man need to install perl-suid in order to run perl scripts with the suid bit set. This script only implements the User-Exists and Check-Password routines. See docs/dev/c2s-pipe-authenticator for details about the protocol. To get this script to work with PSI, Ifound that I had to enable "Allow Plaintext Login" in PSI. Please make sure that you use SSL so that plain-text passwords aren't sent over the network. =head1 README This script allows Jabber authentication against PAM without running jabberd as root. =head1 PREREQUISITES This script requires the Jabberd 2.0 server. It also requires the following other modules from CPAN: C<MIME-Base64> and C<Authen::PAM>. =pod OSNAMES Linux =pod SCRIPT CATEGORIES Misc =head1 AUTHOR Nicholas Humfrey E<lt>njh@aelius.comE<gt> =head1 COPYRIGHT Copyright (c) 2006, Nicholas J Humfrey This code is hereby placed into the public domain. =cut ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/jabberd.in�������������������������������������������������������������0000775�0000000�0000000�00000022672�12614627753�0017674�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh #-*-Perl-*- exec perl -w -x $0 "$@" #!perl ############################################################################## # # jabberd - perl wrapper script to manage launching and controlling the various # binaries that make up the 2.0 version of the jabberd server. # ############################################################################## use strict; use Getopt::Std; use FileHandle; use IPC::Open3; use IO::Select; use POSIX; use POSIX qw(setsid); #----------------------------------------------------------------------------- # Define some initial variables and default them as needed. #----------------------------------------------------------------------------- my $Bin = "@bindir@"; my $LibExec = "@libexecdir@"; my $VERSION = "@VERSION@"; my $config_dir = "@sysconfdir@"; my $config = $config_dir."/jabberd.cfg"; $config = "internal" unless (-e $config); my $debug = 0; my $daemon = 0; my $g_kill_signal = ""; my $select = IO::Select->new(); my ($exe) = ($0 =~ /([^\/]+)$/); my %jobs; my %fhs; my @programs; #----------------------------------------------------------------------------- # Process the command line arguments #----------------------------------------------------------------------------- my %opts; getopts("c:Dhb",\%opts); &usage if exists($opts{h}); if (exists($opts{c})) { $config = $opts{c} if (defined($opts{c}) && ($opts{c} ne "")); &usage() if (!defined($opts{c}) || ($opts{c} eq "")); } $debug = 1 if exists($opts{D}); $daemon = 1 if exists($opts{b}); #----------------------------------------------------------------------------- # Catch some signals so that we can handle them later. #----------------------------------------------------------------------------- $SIG{HUP} = \&Signal; $SIG{TERM} = \&Signal; $SIG{INT} = \&Signal; $SIG{CHLD} = "IGNORE"; #----------------------------------------------------------------------------- # Setup the jobs: router, sm, c2s, s2s #----------------------------------------------------------------------------- $jobs{jabberd}->{prefix} = "JBRD"; $jobs{router}->{cmd} = "$Bin/router"; $jobs{router}->{config} = "$config_dir/router.xml"; $jobs{router}->{prefix} = "ROUT"; $jobs{sm}->{cmd} = "$Bin/sm"; $jobs{sm}->{config} = "$config_dir/sm.xml"; $jobs{sm}->{prefix} = "SM"; $jobs{c2s}->{cmd} = "$Bin/c2s"; $jobs{c2s}->{config} = "$config_dir/c2s.xml"; $jobs{c2s}->{prefix} = "C2S"; $jobs{s2s}->{cmd} = "$Bin/s2s"; $jobs{s2s}->{config} = "$config_dir/s2s.xml"; $jobs{s2s}->{prefix} = "S2S"; if ($config eq "internal") { $programs[0] = ["router"]; $programs[1] = ["sm"]; $programs[2] = ["c2s"]; $programs[3] = ["s2s"]; } else { if (!(-f $config)) { print "ERROR: config file does not exist: $config\n"; exit(1); } open(CFG,$config); while(<CFG>) { next if /^\#/; next if /^\s*$/; my ($job,$config) = /^\s*(\S+)\s*(\S*)\s*$/; # Assume that all the commands are in the same directory # as the jabberd script. The current configuration file # format does not allow specification of pathnames for commands. #my $cmd = "$Bin/$job"; my $cmd = $jobs{$job}->{cmd}; push(@programs,[$job,$config,$cmd]); } close(CFG); } if ($debug) { &debug("jabberd","stdout","debug on\n"); &debug("jabberd","stdout","version($VERSION)\n"); &debug("jabberd","stdout","config_dir($config_dir)\n"); } #----------------------------------------------------------------------------- # Launch all of the jobs. #----------------------------------------------------------------------------- if ($#programs == -1) { print "ERROR: No jobs to launch.\n"; exit(1); } foreach my $job (@programs) { &LaunchJob($job->[0],$job->[1],$job->[2]); } unless (!$daemon || $debug) { # Fork and become a daemon. Exit if we are the parent process. defined(my $pid = fork()) || die "Could not fork: $!"; POSIX:_exit(0) if $pid; # If we are the child process, continue (but act like a daemon). setsid or die "Could not start a new POSIX Session: $!"; chdir "/" or die "Could not chdir to /: $!"; umask 0; open STDIN, "/dev/null" or die "Could not set STDIN to /dev/null: $!"; open STDOUT, "/dev/null" or die "Could not set STDOUT to /dev/null: $!"; open STDERR, "/dev/null" or die "Could not set STDERR to /dev/null: $!"; } #----------------------------------------------------------------------------- # Run the main loop. Read the output from the jobs, watch for dead jobs and # restart them, make sure that the debug output is clearly marked. #----------------------------------------------------------------------------- while (1) { my @ready = $select->can_read(); if ($g_kill_signal ne "") { if (($g_kill_signal eq "INT") || ($g_kill_signal eq "TERM")) { &Shutdown($g_kill_signal); } else { &PassSignal($g_kill_signal); } $g_kill_signal = ""; } foreach my $fh (@ready) { my $line = <$fh>; if (defined($line)) { &debug($fhs{$fh}->{job},$fhs{$fh}->{std},$line); } else { print "ERROR: $fhs{$fh}->{job} died. Shutting down server.\n"; &Shutdown; } } } ############################################################################## # # LaunchJob - Do all of the necessary steps to monitor the job and launch it. # ############################################################################## sub LaunchJob { my $job = shift; my $config = shift; my $cmd = shift; if (!defined($cmd) || $cmd eq "") { $cmd = $jobs{$job}->{cmd}; if ($cmd eq "") { print "cmd is empty, cannot launch\n"; return; } } if (defined($config)) { $cmd .= " -c ".$config; } elsif (defined($jobs{$job}->{config})) { $cmd .= " -c ".$jobs{$job}->{config}; } if ($debug && $jobs{$job}->{prefix} ne "MUC") { $cmd .= " -D"; } if (defined($jobs{$job}->{args}) && ($jobs{$job}->{args} ne "")) { $cmd .= " ".$jobs{$job}->{args}; } &debug("jabberd","stdout","LaunchJob: $job -> $cmd\n"); &CloseJob($job) if exists($jobs{$job}->{launched}); $jobs{$job}->{stdout} = new FileHandle(); $jobs{$job}->{stderr} = new FileHandle(); $jobs{$job}->{stdout}->autoflush(1); $jobs{$job}->{stderr}->autoflush(1); my $stdin = new FileHandle(); $jobs{$job}->{pid} = open3($stdin, $jobs{$job}->{stdout}, $jobs{$job}->{stderr}, $cmd); print $stdin "\n"; $stdin->close(); $select->add($jobs{$job}->{stdout}); $select->add($jobs{$job}->{stderr}); $jobs{$job}->{launched} = 1; $fhs{$jobs{$job}->{stdout}}->{job} = $job; $fhs{$jobs{$job}->{stdout}}->{std} = "stdout"; $fhs{$jobs{$job}->{stderr}}->{job} = $job; $fhs{$jobs{$job}->{stderr}}->{std} = "stderr"; } ############################################################################## # # CloseJob - Do all of the necessary steps to clean up after a job. # ############################################################################## sub CloseJob { my $job = shift; $select->remove($jobs{$job}->{stdout}, $jobs{$job}->{stderr}); $jobs{$job}->{stdout}->close(); $jobs{$job}->{stderr}->close(); delete($jobs{$job}->{launched}); } ############################################################################## # # Signal - when we get a signal... we need to do something about it. # ############################################################################## sub Signal { $g_kill_signal = shift; } sub PassSignal { my $sig = shift; if ((! defined($sig)) || ($sig eq "")) { return; } foreach my $job (keys(%jobs)) { next unless exists($jobs{$job}->{launched}); &debug("jabberd","stdout","sending $sig to $jobs{$job}->{pid} : $job\n"); kill $sig => $jobs{$job}->{pid}; } } sub Shutdown { my $sig = shift; if (! defined($sig)) { $sig = "TERM"; } PassSignal($sig); &debug("Shutting down.\n"); my $ret; foreach my $job(keys(%jobs)) { $ret = waitpid($jobs{$job}->{pid}, 0) if defined($jobs{$job}->{pid}); } exit(0); } ############################################################################## # # debug - print out a message for debug. Making sure that the prefix is the # program that generated the debug. # ############################################################################## sub debug { return unless $debug; my $job = shift; my $std = shift; #my $flag = " "; #$flag = "*" if ($std eq "stderr"); #printf("%s%-4s: ",$flag,$jobs{$job}->{prefix}); my $prefix = $jobs{$job}->{prefix}; $prefix = $job if ! defined($prefix); printf("%-4s: ",$prefix); print join("",@_); } ############################################################################## # # usage - print out the help and exit # ############################################################################## sub usage { print "$exe - jabberd wrapper script ($VERSION)\n"; print "Usage: $exe <options>\n"; print "Options are:\n"; print " -c <file> config file to use [default: $config]\n"; print " -D Show debug output\n"; print " -b Push into background\n"; print " -h Show this help\n"; exit(0); } ����������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/jabberd.rc�������������������������������������������������������������0000664�0000000�0000000�00000006656�12614627753�0017673�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # # Raymond 25DEC2003 support@bigriverinfotech.com # /etc/rc.d/init.d/jabberd2 # init script for jabberd2 processes # Tested under jabberd-2.0rc2 and Fedora 1.0 only # # processname: jabberd2 # description: jabberd2 is the next generation of the jabberd server # chkconfig: 2345 85 15 # if [ -f /etc/init.d/functions ]; then . /etc/init.d/functions elif [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functions else echo -e "\ajabberd2: unable to locate functions lib. Cannot continue." exit -1 fi # progs="router sm c2s s2s" progsPath="/usr/local/bin" confPath="/usr/local/etc/jabberd" pidPath="/usr/local/var/jabberd/pid" statusCol="echo -ne \\033[60G" statusColorOK="echo -ne \\033[1;32m" statusColorFailed="echo -ne \\033[1;31m" statusColorNormal="echo -ne \\033[0;39m" retval=0 # StatusOK ( ) { ${statusCol} echo -n "[ " ${statusColorOK} echo -n "OK" ${statusColorNormal} echo " ]" return 0 } # StatusFailed ( ) { echo -ne "\a" ${statusCol} echo -n "[" ${statusColorFailed} echo -n "FAILED" ${statusColorNormal} echo "]" return 0 } # ReqBins ( ) { for prog in ${progs}; do if [ ! -x ${progsPath}/${prog} ]; then echo -n "jabberd2 binary [${prog}] not found." StatusFailed echo "Cannot continue." return -1 fi done return 0 } # ReqConfs ( ) { for prog in ${progs}; do if [ ! -f ${confPath}/${prog}.xml ]; then echo -n "jabberd2 configuration [${prog}.xml] not found." StatusFailed echo "Cannot continue." return -1 fi done return 0 } # ReqDirs ( ) { if [ ! -d ${pidPath} ]; then echo -n "jabberd2 PID directory not found. Cannot continue." StatusFailed return -1 fi return 0 } # Start ( ) { for req in ReqBins ReqConfs ReqDirs; do ${req} retval=$? [ ${retval} == 0 ] || return ${retval} done echo "Initializing jabberd2 processes ..." for prog in ${progs}; do if [ $( pidof -s ${prog} ) ]; then echo -ne "\tprocess [${prog}] already running" StatusFailed sleep 1 continue fi echo -ne "\tStarting ${prog}: " if [ ${prog} == "router" ]; then ports="5347" elif [ ${prog} == "c2s" ]; then ports="5222 5223" elif [ ${prog} == "s2s" ]; then ports="5269" else ports="" fi for port in ${ports}; do if [ $( netstat --numeric-ports --listening --protocol=inet | gawk '{ print $4 }' | gawk -F : '{ print $NF }' | grep -c ${port}$ ) -ne "0" ]; then StatusFailed echo -e "\tPort ${port} is currently in use. Cannot continue" echo -e "\tIs a Jabber 1.x server running?" Stop let retval=-1 break 2 fi done rm -f /var/lock/subsys/${prog} rm -f ${pidPath}/${prog}.pid args="-c ${confPath}/${prog}.xml" ${progsPath}/${prog} ${args} >/dev/null 2>&1 <&1 & retval=$? if [ ${retval} == 0 ]; then StatusOK touch /var/lock/subsys/${prog} else StatusFailed Stop let retval=-1 break fi sleep 1 done return ${retval} } # Stop ( ) { echo "Terminating jabberd2 processes ..." for prog in ${progs}; do echo -ne "\tStopping ${prog}: " killproc ${prog} retval=$? if [ ${retval} == 0 ]; then rm -f /var/lock/subsys/${prog} rm -f ${pidPath}/${prog}.pid fi echo sleep 1 done return ${retval} } # case "$1" in start) Start ;; stop) Stop ;; restart) Stop Start ;; condrestart) if [ -f /var/lock/subsys/${prog} ]; then Stop sleep 3 Start fi ;; *) echo "Usage: $0 {start|stop|restart|condrestart}" let retval=-1 esac exit ${retval} # # eof ����������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/jabberd2.schema��������������������������������������������������������0000664�0000000�0000000�00000002240�12614627753�0020572�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# attribyte types attributetype ( 1.3.6.1.4.1.8381.2.7 NAME 'jabberPassword' DESC 'Password of Jabber user when using LDAPFULL authreg module' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.8381.2.8 NAME 'jabberPublishedGroup' DESC 'Name of group to add to when publishing user with roster template' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) attributetype ( 1.3.6.1.4.1.8381.2.9 NAME 'jabberPublishedItem' DESC 'If set and has non-zero value, permit publishing Jabber user with template' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # objectclasses objectclass ( 1.3.6.1.4.1.8381.1.3 NAME 'descriptionObject' DESC 'Object with description attribute' SUP top AUXILIARY MAY ( description ) ) objectclass ( 1.3.6.1.4.1.8381.1.5 NAME 'structuralObject' DESC 'Structural object' SUP top STRUCTURAL ) objectclass ( 1.3.6.1.4.1.8381.1.6 NAME 'jabberExtendedObject' DESC 'Extended Jabber entry' SUP top AUXILIARY MAY ( jabberPassword $ jabberPublishedItem $ jabberPublishedGroup ) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/migrate-jd14dir-2-sqlite.pl��������������������������������������������0000775�0000000�0000000�00000024134�12614627753�0022630�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/pkg/bin/perl -w #<license> # Copyright (c) 2008 BBN Technologies Corp. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of BBN Technologies nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY BBN TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL BBN TECHNOLOGIES OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #</license> use strict; use XML::Simple; use Data::Dumper; use Getopt::Long; #This script essentially uses the perl XML parser XML::Simple to put things into internal perl structures. #It then simply tries to manipulate those perl structures to output the necessary SQL commands. #Run it in the directory with the jabberd1.4 xml files. my @description=" goes through a jabberd 1.4 spool directory and creates a file of sql commands to use to upgrade to a jabberd2 database and the jabberd2 database if it can find a schema file."; # realm my $realm = "j.jabber.com"; # intermediate file that has the sql commands - could be more useful # than just for sql my $sqlfile = "tsql"; # since we're using sqlite - this is where jabberd2 put the sqlite schema my $schema = "/usr/pkg/share/examples/jabberd/db-setup.sqlite"; # jabberd2 db my $jabberdb = "jabberd2.db"; #temporary variables my $file; my $count = 0; my $rcount = 1; my $vcount = 1; my $debug = 0; #get command line arguments if ( @ARGV > 0 ) { GetOptions ('d' => \$debug, 'r|realm=s' => \$realm, 's|schema=s' => \$schema, 'j|jabberdb=s' => \$jabberdb, 'help' => \&usage); } #open the sqlfile to put commands in open(TSQL, ">$sqlfile"); # I'm going through each file in the directory that has a .xml suffix # I'm using the XML::Simple parser, and to debug things you can look at # what the Dumper($data) puts out so that the perl structures can be inspected opendir(DIR, ".") or die "can't opendir .: $!"; while (defined($file = readdir(DIR))) { if($file =~ /\.xml/) { if($debug) { print "$file\n"; } #ForceArray causes all nested elements to be represented as arrays. #KeepRoot causes the name of the root element to be kept on input and output my $simple = XML::Simple->new (ForceArray => 1, KeepRoot => 1); my $data = $simple->XMLin($file); my @filewords = split(/\./, $file); my $DISPATCHER = { 'active' => \&migrate_active, 'auth' => \&migrate_auth, 'roster' => \&migrate_roster, }; if($debug) { print Dumper ($data); print $data->{xdb}; print "\n\nElements\n"; for my $el (@{$data->{xdb}}) { print $el . "\n"; foreach my $el1 (sort keys %{$el}) { print "$el1: "; print $el->{$el1}; } } print $data->{xdb}->[0] . "\n"; print "$filewords[0]: $data->{xdb}->[0]->{password}->[0]->{content} \n"; } #This is where we are putting in jabber users, need to populate both the authreg table and the #active table. #INSERT INTO "authreg" VALUES('tester1','realm','user'); print TSQL "insert into \"authreg\" VALUES('$filewords[0]', '$realm', '$data->{xdb}->[0]->{password}->[0]->{content}');\n"; $count++; #INSERT INTO "active" VALUES('user',4, 1201999999); print TSQL "insert into \"active\" VALUES('$filewords[0]\@$realm', $count, 120199999);\n"; #This is where we're looking for roster information #this is an array of hashes my $iqarray = $data->{xdb}->[0]->{query}; my $qelem; my $icount = 0; #iterate through the array of hashes looking for the roster "item" hash #Roster stuff is put into the roster-items table, and only subscriptions that #are both are carried over #INSERT INTO "roster-items" VALUES('tester2@host.t.com',1,'buddy1',NULL,0,0,1); #INSERT INTO "roster-items" VALUES('tester2@host.t.com',2,'buddy2','bud2-alias',1,1,0); foreach $qelem (@{$iqarray}) { if($debug) { print "$icount : $qelem - "; } #for each hash, look for the roster items foreach my $el1 (sort keys %{$qelem}) { if ($el1 =~ /item/) { #represented as an array my $rarray = $qelem->{item}; #Unfortunately the way some clients stored data, roster data is represented as #an ARRAY, but sometimes it gets dumped out as a HASH if (ref($rarray) eq "ARRAY") { foreach my $budhash (@{$rarray}) { ###CHECK THAT subscription is both#### if($budhash->{subscription} =~ /both/) { #dump data for the roster, which is in hash form print TSQL "insert into \"roster-items\" VALUES('$filewords[0]\@$realm', $rcount, '$budhash->{jid}', NULL, 1, 1, 0);\n"; #have to check for valid group my $barray ; if (exists($budhash->{group})) { $barray = $budhash->{group}->[0]; } else { $barray = "General"; } print TSQL "insert into \"roster-groups\" VALUES('$filewords[0]\@$realm', $rcount, '$budhash->{jid}', '$barray');\n"; $rcount++; } } } else { # print "IT MUST BE A HASH\n"; foreach my $bud (sort keys %{$rarray}) { if($rarray->{$bud}->{subscription} =~ /both/) { print TSQL "insert into \"roster-items\" VALUES('$filewords[0]\@$realm', $rcount, '$rarray->{$bud}->{jid}', NULL, 1, 1, 0);\n"; my $barray; if (exists($rarray->{$bud}->{group})) { $barray = $rarray->{$bud}->{group}->[0]; } else { $barray = "General"; } print TSQL "insert into \"roster-groups\" VALUES('$filewords[0]\@$realm', $rcount, '$rarray->{$bud}->{jid}', '$barray');\n"; $rcount++; } } } } } $icount++; } #The decision was just to move photo, fullname, email, and url if they #were specified. Not so elegant but it works. #starting with vCard information #this is an array my $vCarray; my $photoInfo = "NULL"; my $photoType = "NULL"; my $fname = "NULL"; my $email = "NULL"; my $url = "NULL"; my $tstring = "NULL"; if (exists($data->{xdb}->[0]{vCard})) { # it exists $vCarray = $data->{xdb}->[0]->{vCard}; if (exists($vCarray->[0]{PHOTO})) { if($debug) { print "vCarray is $vCarray->[0]->{PHOTO}\n"; print "PHOTO is $vCarray->[0]->{PHOTO}->[0]->{BINVAL}->[0]\n"; } $photoInfo = $vCarray->[0]->{PHOTO}->[0]->{BINVAL}->[0]; if (exists($vCarray->[0]->{PHOTO}->[0]{TYPE})) { if($debug) { print "TYPE is $vCarray->[0]->{PHOTO}->[0]->{TYPE}->[0]\n"; } $photoType = $vCarray->[0]->{PHOTO}->[0]->{TYPE}->[0]; } } if (exists($vCarray->[0]{FN})) { if($debug) { print "FULLNAME is $vCarray->[0]->{FN}->[0]\n"; } $fname = $vCarray->[0]->{FN}->[0]; #deal with FN being an empty hash reference and ignoring it. if (ref($fname) ne "") { $fname = "NULL"; } } if (exists($vCarray->[0]{EMAIL})) { if($debug) { print "EMAIL is $vCarray->[0]->{EMAIL}->[0]\n"; } #see if we can get the email here $email = $vCarray->[0]->{EMAIL}->[0]; #it might be a hash that holds a hash with a USERID key if (ref($vCarray->[0]->{EMAIL}->[0]) eq "HASH") { if (exists($vCarray->[0]->{EMAIL}->[0]{USERID})) { if($debug) { print "EMAIL is actually $vCarray->[0]->{EMAIL}->[0]->{USERID}->[0]\n"; } $email = $vCarray->[0]->{EMAIL}->[0]->{USERID}->[0]; } } #deal with EMAIL being an empty hash reference and ignoring it. if (ref($email) ne "") { $email = "NULL"; } } if (exists($vCarray->[0]{URL})) { if($debug) { print "URL is $vCarray->[0]->{URL}->[0]\n"; } $url = $vCarray->[0]->{URL}->[0]; #deal with URL being an empty hash reference and ignoring it. if (ref($url) ne "") { $url = "NULL"; } } #have to look at the schema to figure out what is no longer NULL if you want to import the data $tstring ="insert into \"vcard\" VALUES('$filewords[0]\@$realm', $vcount, '$fname',NULL,'$url',NULL,'$email',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'$photoType','$photoInfo',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);\n"; $tstring =~ s/\'NULL\'/NULL/g; print TSQL $tstring; $vcount++; } } } closedir(DIR); if(-r $schema) { system("/usr/pkg/bin/sqlite3 $jabberdb < $schema"); system("/usr/pkg/bin/sqlite3 $jabberdb < $sqlfile"); } #=============================================== sub usage{ printf ("\nUsage:\n"); printf (" migrate-dir.pl -r <realm> \n"); printf (" where <realm> is the jabberd2 realm\n"); printf (" migrate-dir.pl -s <schemafile> \n"); printf (" where <schemafile> shows the sqlite schema for jabberd2 (/usr/pkg/share/examples/jabberd/db-setup.sqlite)\n"); printf (" migrate-dir.pl -j <jabberdb> \n"); printf (" where <jabberdb> is the name for the output jabber2db (defaults to jabberd2.db)\n"); printf (" migrate-dir.pl -d \n"); printf (" which turns on debugging \n"); printf (" migrate-dir.pl -h \n"); printf (" prints this message \n"); printf ("\nDescription:\n"); printf (" @description\n"); exit(1); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/migrate.pl�������������������������������������������������������������0000775�0000000�0000000�00000022016�12614627753�0017730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w # # jabberd 1.4 -> 2.0 migration tool # Copyright (c) 2003 Robert Norris # GPL v2. See http://www.gnu.org/copyleft/gpl.html for more info # # # This can migrate from any 1.4 XDB source, into 2.0 MySQL or # PostgreSQL databases. Other 2.0 databases (such as Berkeley) are not # supported at this time. # # Currently, this can migrate authentication information and rosters. # Anything more than that, you're on your own. # # There's very little error checking. If you find some user data that # consistently breaks, please file a bug report with some sample data. # # # Installation # # 1. Install the following Perl packages # # - XML::Stream 1.17 or higher (from JabberStudio) # - Net::Jabber 1.29 or higher (from JabberStudio) # - Digest::SHA1 # - DBI # - DBD::Pg or DBD::mysql # # 2. Make sure the appropriate database schema is imported into your # database (db-setup.mysql or db-setup.pgsql) # # 3. Add something like the following to your 1.4 jabber.xml: # # <service id="migrate"> # <accept> # <ip>127.0.0.1</ip> # <port>7000</port> # <secret>secret</secret> # </accept> # </service> # # 4. Create a file with the JIDs of the users you wish to migrate, one # per line. # # 5. Edit the config below to taste. # # 6. Run. # # host/port that jabberd 1.4 is listening for this component on my $COMP_HOST = 'localhost'; my $COMP_PORT = 7000; # name of component my $COMP_NAME = 'migrate'; # component secret my $COMP_SECRET = 'secret'; # backend database type (either 'mysql' or 'pgsql') my $DB_TYPE = 'mysql'; # host/port of the database server my $DB_HOST = 'localhost'; my $DB_PORT = 3306; # 5432 is default for pgsql # database name my $DB_NAME = 'jabberd2'; # database user/pass my $DB_USER = 'jabberd2'; my $DB_PASS = 'secret'; # file containing user list my $USER_FILE = "migrate-users"; # data types to migrate my @DATA_TYPES = qw(roster active auth); # authentication realm for migrated users my $AUTH_REALM = 'gideon.its.monash.edu.au'; # # you shouldn't need to touch anything below here # use strict; use DBI; use Digest::SHA1 qw(sha1_hex); # # all of this madness is to work around problems and shortcomings with Net::Jabber # use Net::Jabber::XDB; $Net::Jabber::XDB::FUNCTIONS{XDB}->{XPath}->{Type} = 'master'; use Net::Jabber 1.29 qw(Component); package Net::Jabber::XDB; $FUNCTIONS{Data}->{XPath}->{Type} = 'node'; $FUNCTIONS{Data}->{XPath}->{Path} = '*[@xmlns]'; $FUNCTIONS{Data}->{XPath}->{Child} = 'Data'; $FUNCTIONS{Data}->{XPath}->{Calls} = ['Get','Defined']; package Net::Jabber::Data; $FUNCTIONS{XMLNS}->{XPath}->{Path} = '@xmlns'; $FUNCTIONS{Data}->{XPath}->{Type} = 'node'; $FUNCTIONS{Data}->{XPath}->{Path} = '*[@xmlns]'; $FUNCTIONS{Data}->{XPath}->{Child} = 'Data'; $FUNCTIONS{Data}->{XPath}->{Calls} = ['Get','Defined']; my $ns; $ns = 'jabber:iq:auth'; $NAMESPACES{$ns}->{Password}->{XPath}->{Path} = 'text()'; $NAMESPACES{$ns}->{Auth}->{XPath}->{Type} = 'master'; $ns = 'jabber:iq:register'; $NAMESPACES{$ns}->{Register}->{XPath}->{Type} = 'master'; $ns = 'jabber:iq:roster'; $NAMESPACES{$ns}->{Item}->{XPath}->{Type} = 'node'; $NAMESPACES{$ns}->{Item}->{XPath}->{Path} = 'item'; $NAMESPACES{$ns}->{Item}->{XPath}->{Child} = ['Data','__netjabber__:iq:roster:item']; $NAMESPACES{$ns}->{Item}->{XPath}->{Calls} = ['Add']; $NAMESPACES{$ns}->{Items}->{XPath}->{Type} = 'children'; $NAMESPACES{$ns}->{Items}->{XPath}->{Path} = 'item'; $NAMESPACES{$ns}->{Items}->{XPath}->{Child} = ['Data','__netjabber__:iq:roster:item']; $NAMESPACES{$ns}->{Items}->{XPath}->{Calls} = ['Get']; $ns = '__netjabber__:iq:roster:item'; $NAMESPACES{$ns}->{Ask}->{XPath}->{Path} = '@ask'; $NAMESPACES{$ns}->{Group}->{XPath}->{Type} = 'array'; $NAMESPACES{$ns}->{Group}->{XPath}->{Path} = 'group/text()'; $NAMESPACES{$ns}->{JID}->{XPath}->{Type} = 'jid'; $NAMESPACES{$ns}->{JID}->{XPath}->{Path} = '@jid'; $NAMESPACES{$ns}->{Name}->{XPath}->{Path} = '@name'; $NAMESPACES{$ns}->{Subscription}->{XPath}->{Path} = '@subscription'; $NAMESPACES{$ns}->{Item}->{XPath}->{Type} = 'master'; package main; # # end madness # $| = 1; print "Loading user file\n"; open IN, $USER_FILE or die "couldn't open $USER_FILE for reading: $!"; my @users = grep { chomp } <IN>; close IN; die "unknown database type '$DB_TYPE'" if $DB_TYPE ne 'mysql' and $DB_TYPE ne 'pgsql'; print "Connecting to database\n"; my $dbh; eval { if($DB_TYPE eq 'mysql') { $dbh = DBI->connect("dbi:mysql:dbname=$DB_NAME;host=$DB_HOST;port=$DB_PORT", $DB_USER, $DB_PASS, { AutoCommit => 0, RaiseError => 1 }); } else { $dbh = DBI->connect("dbi:Pg:dbname=$DB_NAME;host=$DB_HOST;port=$DB_PORT", $DB_USER, $DB_PASS, { AutoCommit => 0, RaiseError => 1 }); } }; if($@) { die "db connect error: $@"; } print "Connecting to jabber server\n"; my $c = new Net::Jabber::Component( # debuglevel => 1, debugfile => 'stdout', debugtime => 0 ); $c->Connect( hostname => $COMP_HOST, port => $COMP_PORT, secret => $COMP_SECRET, componentname => $COMP_NAME, connectiontype => 'accept'); $c->Connected or die "$0: connect to jabber server failed"; my ($iq, $xdb, $res); print scalar @users, " users to migrate\n"; foreach my $user (@users) { print "Converting data for $user...\n"; my $data = { }; for(@DATA_TYPES) { print " $_\n"; eval '_migrate_'.$_.'($data, $user)'; warn "$@" if $@; } print "Writing to database... "; eval { my ($rows, $tables) = (0, 0); foreach my $type (keys %$data) { foreach my $item (@{$data->{$type}}) { my $sql = 'INSERT INTO ' . _sql_literal($type) . " ( "; for(keys %$item) { $sql .= _sql_literal($_) . ', '; } $sql =~ s/, $/) VALUES ( /; for(keys %$item) { $sql .= $item->{$_} . ', '; } $sql =~ s/, $/)/; $dbh->do($sql); $rows++; } $tables++; } $dbh->commit; print "inserted $rows rows into $tables tables.\n"; }; if($@) { warn "db error: $@"; $dbh->rollback; } } $dbh->disconnect; sub _sql_literal { my $arg = shift; return "\"$arg\"" if $DB_TYPE eq 'pgsql'; return "\`$arg\`"; } sub _xdb_get { my ($user, $ns) = @_; my $xdb = new Net::Jabber::XDB; $xdb->SetXDB( to => $user, from => $COMP_NAME, type => 'get', ns => $ns); return $c->SendAndReceiveWithID($xdb); } sub _object_quote { $dbh->quote(shift); } sub _object_new { my $item; $item->{'collection-owner'} = _object_quote(shift); $item->{'object-sequence'} = "nextval('object-sequence')" if $DB_TYPE eq 'pgsql'; return $item; } sub _migrate_roster { my ($data, $user) = @_; my $xdb = _xdb_get($user, 'jabber:iq:roster'); my $roster = $xdb->GetData or return; my @items = $roster->GetItems; for(@items) { my $item = _object_new($user); $item->{'jid'} = _object_quote($_->GetJID); $item->{'name'} = _object_quote($_->GetName) if $_->GetName; my $s10n = $_->GetSubscription; if(not $s10n or $s10n eq 'none') { $item->{'to'} = _object_quote('0'); $item->{'from'} = _object_quote('0'); } elsif($s10n eq 'both') { $item->{'to'} = _object_quote('1'); $item->{'from'} = _object_quote('1'); } elsif($s10n eq 'to') { $item->{'to'} = _object_quote('1'); $item->{'from'} = _object_quote('0'); } elsif($s10n eq 'from') { $item->{'to'} = _object_quote('0'); $item->{'from'} = _object_quote('1'); } my $ask = $_->GetAsk; if(not $ask) { $item->{'ask'} = 0; } elsif($ask eq 'subscribe') { $item->{'ask'} = 1; } elsif($ask eq 'unsubscribe') { $item->{'ask'} = 2; } push @{$data->{'roster-items'}}, $item; my $jid = $item->{'jid'}; my @groups = $_->GetGroup; for(@groups) { my $item = _object_new($user); $item->{'jid'} = $jid; $item->{'group'} = _object_quote($_); push @{$data->{'roster-groups'}}, $item; } } } sub _migrate_active { my ($data, $user) = @_; my $item = _object_new($user); $item->{'time'} = time(); push @{$data->{'active'}}, $item; } sub _migrate_auth { my ($data, $user) = @_; my $xdb = _xdb_get($user, 'jabber:iq:auth'); my $auth = $xdb->GetData or return; my $item; $user =~ m/^(.*)\@/; $item->{'username'} = _object_quote($1); $item->{'realm'} = _object_quote($AUTH_REALM); my $pass = $auth->GetPassword; $item->{'password'} = _object_quote($pass); push @{$data->{'authreg'}}, $item; } sub _migrate_vcard { my ($data, $user) = @_; my $xdb = _xdb_get($user, 'vcard-temp'); my $vcard = $xdb->GetData or return; # !!! implement this } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/pam_jabberd������������������������������������������������������������0000664�0000000�0000000�00000000262�12614627753�0020110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#%PAM-1.0 #/etc/pam.d/jabberd auth required pam_nologin.so auth include system-auth account include system-auth session include system-auth ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/tools/pipe-auth.pl�����������������������������������������������������������0000775�0000000�0000000�00000004370�12614627753�0020177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w # # Sample pipe authenticator module. You can use this as a basis for your # own auth/reg module. See docs/dev/c2s-pipe-authenticator for details # about the protocol. # # This code is hereby placed into the public domain. # use strict; use MIME::Base64; # Flush output immediately. $| = 1; # On startup, we have to inform c2s of the functions we can deal with. USER-EXISTS is not optional. print "OK USER-EXISTS GET-PASSWORD CHECK-PASSWORD SET-PASSWORD CREATE-USER DESTROY-USER FREE\n"; # Our main loop my $buf; while(sysread (STDIN, $buf, 1024) > 0) { my ($cmd, @args) = split ' ', $buf; $cmd =~ tr/[A-Z]/[a-z]/; $cmd =~ tr/-/_/; eval "print _cmd_$cmd(\@args), '\n'"; } # Determine if the requested user exists. sub _cmd_user_exists { my ($user, $realm) = @_; # !!! return "OK" if user exists; return "NO"; } # Retrieve the user's password. sub _cmd_get_password { my ($user, $realm) = @_; # !!! $pass = [password in database]; # return "NO" if not $pass; # $encoded_pass = encode_base64($pass); # return "OK $encoded_pass" if $encoded_pass; return "NO"; } # Compare the given password with the stored password. sub _cmd_check_password { my ($user, $encoded_pass, $realm) = @_; # !!! $pass = decode_base64($encoded_pass); # return "NO" if not $pass; # $spass = [password in database]; # return "OK" if $pass eq $spass; return "NO"; } # Store the password in the database. sub _cmd_set_password { my ($user, $encoded_pass, $realm) = @_; # !!! $pass = decode_base64($encoded_pass); # return "NO" if not $pass; # $fail = [store $pass in database]; # return "OK" if not $fail; return "NO"; } # Create a user in the database (with no auth credentials). sub _cmd_create_user { my ($user, $realm) = @_; # !!! $fail = [create user in database] # return "OK" if not $fail; return "NO"; } # Delete a user and associated credentials. sub _cmd_delete_user { my ($user, $realm) = @_; # !!! $fail = [delete user in database] # return "OK" if not $fail; return "NO"; } # c2s shutting down, do the same. sub _cmd_free { # !!! free data # close database handles exit(0); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015554�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/Makefile.am�������������������������������������������������������������0000664�0000000�0000000�00000000704�12614627753�0017611�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������LIBTOOL += --quiet AM_CPPFLAGS = -I@top_srcdir@ noinst_LTLIBRARIES = libutil.la noinst_HEADERS = inaddr.h md5.h sha1.h util.h util_compat.h xdata.h nad.h pool.h xhash.h uri.h jid.h base64.h datetime.h log.h crypt_blowfish.h libutil_la_SOURCES = access.c base64.c config.c datetime.c hex.c inaddr.c jid.c jqueue.c jsignal.c log.c md5.c nad.c pool.c rate.c serial.c sha1.c stanza.c str.c xdata.c xhash.c crypt_blowfish.c libutil_la_LIBADD = @LDFLAGS@������������������������������������������������������������jabberd2-jabberd-2.3.4/util/access.c����������������������������������������������������������������0000664�0000000�0000000�00000014757�12614627753�0017177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* this implements allow/deny filters for IP address */ #include "util.h" access_t access_new(int order) { access_t access = (access_t) calloc(1, sizeof(struct access_st)); access->order = order; return access; } void access_free(access_t access) { if(access->allow != NULL) free(access->allow); if(access->deny != NULL) free(access->deny); free(access); } static int _access_calc_netsize(const char *mask, int defaultsize) { struct in_addr legacy_mask; int netsize; #ifndef HAVE_INET_PTON if(strchr(mask, '.') && inet_aton(mask, &legacy_mask)) #else if(inet_pton(AF_INET, mask, &legacy_mask.s_addr) > 0) #endif { /* netmask has been given in dotted decimal form */ int temp = ntohl(legacy_mask.s_addr); netsize = 32; while(netsize && temp%2==0) { netsize--; temp /= 2; } } else { /* numerical netsize */ netsize = j_atoi(mask, defaultsize); } return netsize; } /** convert a IPv6 mapped IPv4 address to a real IPv4 address */ static void _access_unmap_v4(struct sockaddr_in6 *src, struct sockaddr_in *dst) { memset(dst, 0, sizeof(struct sockaddr_in)); dst->sin_family = AF_INET; dst->sin_addr.s_addr = htonl((((int)src->sin6_addr.s6_addr[12]*256+src->sin6_addr.s6_addr[13])*256+src->sin6_addr.s6_addr[14])*256+(int)src->sin6_addr.s6_addr[15]); } /** check if two ip addresses are within the same subnet */ static int _access_check_match(struct sockaddr_storage *ip_1, struct sockaddr_storage *ip_2, int netsize) { struct sockaddr_in *sin_1; struct sockaddr_in *sin_2; struct sockaddr_in6 *sin6_1; struct sockaddr_in6 *sin6_2; int i; sin_1 = (struct sockaddr_in *)ip_1; sin_2 = (struct sockaddr_in *)ip_2; sin6_1 = (struct sockaddr_in6 *)ip_1; sin6_2 = (struct sockaddr_in6 *)ip_2; /* addresses of different families */ if(ip_1->ss_family != ip_2->ss_family) { /* maybe on of the addresses is just a IPv6 mapped IPv4 address */ if (ip_1->ss_family == AF_INET && ip_2->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6_2->sin6_addr)) { struct sockaddr_storage t; struct sockaddr_in *temp; temp = (struct sockaddr_in *)&t; _access_unmap_v4(sin6_2, temp); if(netsize>96) netsize -= 96; return _access_check_match(ip_1, &t, netsize); } if (ip_1->ss_family == AF_INET6 && ip_2->ss_family == AF_INET && IN6_IS_ADDR_V4MAPPED(&sin6_1->sin6_addr)) { struct sockaddr_storage t; struct sockaddr_in *temp; temp = (struct sockaddr_in *)&t; _access_unmap_v4(sin6_1, temp); if(netsize>96) netsize -= 96; return _access_check_match(&t, ip_2, netsize); } return 0; } /* IPv4? */ if(ip_1->ss_family == AF_INET) { int netmask; if(netsize > 32) netsize = 32; netmask = htonl(-1 << (32-netsize)); return ((sin_1->sin_addr.s_addr&netmask) == (sin_2->sin_addr.s_addr&netmask)); } /* IPv6? */ if(ip_1->ss_family == AF_INET6) { unsigned char bytemask; if(netsize > 128) netsize = 128; for(i=0; i<netsize/8; i++) if(sin6_1->sin6_addr.s6_addr[i] != sin6_2->sin6_addr.s6_addr[i]) return 0; if(netsize%8 == 0) return 1; bytemask = 0xff << (8 - netsize%8); return ((sin6_1->sin6_addr.s6_addr[i]&bytemask) == (sin6_2->sin6_addr.s6_addr[i]&bytemask)); } /* unknown address family */ return 0; } int access_allow(access_t access, const char *ip, const char *mask) { struct sockaddr_storage ip_addr; int netsize; if(j_inet_pton(ip, &ip_addr) <= 0) return 1; netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128); access->allow = (access_rule_t) realloc(access->allow, sizeof(struct access_rule_st) * (access->nallow + 1)); memcpy(&access->allow[access->nallow].ip, &ip_addr, sizeof(ip_addr)); access->allow[access->nallow].mask = netsize; access->nallow++; return 0; } int access_deny(access_t access, const char *ip, const char *mask) { struct sockaddr_storage ip_addr; int netsize; if(j_inet_pton(ip, &ip_addr) <= 0) return 1; netsize = _access_calc_netsize(mask, ip_addr.ss_family==AF_INET ? 32 : 128); access->deny = (access_rule_t) realloc(access->deny, sizeof(struct access_rule_st) * (access->ndeny + 1)); memcpy(&access->deny[access->ndeny].ip, &ip_addr, sizeof(ip_addr)); access->deny[access->ndeny].mask = netsize; access->ndeny++; return 0; } int access_check(access_t access, const char *ip) { struct sockaddr_storage addr; access_rule_t rule; int i, allow = 0, deny = 0; if(j_inet_pton(ip, &addr) <= 0) return 0; /* first, search the allow list */ for(i = 0; !allow && i < access->nallow; i++) { rule = &access->allow[i]; if(_access_check_match(&addr, &rule->ip, rule->mask)) allow = 1; } /* now the deny list */ for(i = 0; !deny && i < access->ndeny; i++) { rule = &access->deny[i]; if(_access_check_match(&addr, &rule->ip, rule->mask)) deny = 1; } /* allow then deny */ if(access->order == 0) { if(allow) return 1; if(deny) return 0; /* allow by default */ return 1; } /* deny then allow */ if(deny) return 0; if(allow) return 1; /* deny by default */ return 0; } �����������������jabberd2-jabberd-2.3.4/util/base64.c����������������������������������������������������������������0000664�0000000�0000000�00000014050�12614627753�0017004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* base64 encoder/decoder. Originally part of main/util.c * but moved here so that support/ab and apr_sha1.c could * use it. This meant removing the apr_palloc()s and adding * ugly 'len' functions, which is quite a nasty cost. */ #include "util.h" /* aaaack but it's fast and const should make it shared text page. */ static const unsigned char pr2six[256] = { /* ASCII table */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 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, 64, 64, 64, 64, 64, 64, 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, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; int apr_base64_decode_len(const char *bufcoded, int buflen) { int nbytesdecoded; register const unsigned char *bufin; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63 && buflen-- > 0); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; nbytesdecoded = (((int)nprbytes + 3) / 4) * 3; return nbytesdecoded + 1; } int apr_base64_decode_binary(unsigned char *bufplain, const char *bufcoded, int buflen); int apr_base64_decode(char *bufplain, const char *bufcoded, int buflen) { int len; len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded, buflen); bufplain[len] = '\0'; return len; } int apr_base64_decode_binary(unsigned char *bufplain, const char *bufcoded, int buflen) { int nbytesdecoded; register const unsigned char *bufin; register unsigned char *bufout; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63 && buflen-- > 0); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; nbytesdecoded = (((int)nprbytes + 3) / 4) * 3; bufout = (unsigned char *) bufplain; bufin = (const unsigned char *) bufcoded; while (nprbytes > 4) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); bufin += 4; nprbytes -= 4; } /* Note: (nprbytes == 1) would be an error, so just ingore that case */ if (nprbytes > 1) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); } if (nprbytes > 2) { *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); } if (nprbytes > 3) { *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); } nbytesdecoded -= (4 - (int)nprbytes) & 3; return nbytesdecoded; } static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int apr_base64_encode_len(int len) { return ((len + 2) / 3 * 4) + 1; } int apr_base64_encode_binary(char *encoded, const unsigned char *string, int len); int apr_base64_encode(char *encoded, const char *string, int len) { return apr_base64_encode_binary(encoded, (const unsigned char *) string, len); } int apr_base64_encode_binary(char *encoded, const unsigned char *string, int len) { int i; char *p; p = encoded; for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; *p++ = basis_64[string[i + 2] & 0x3F]; } if (i < len) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; if (i == (len - 1)) { *p++ = basis_64[((string[i] & 0x3) << 4)]; *p++ = '='; } else { *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; } *p++ = '='; } *p++ = '\0'; return (int)(p - encoded); } /* convenience functions for j2 */ char *b64_encode(char *buf, int len) { int elen; char *out; if(len == 0) len = strlen(buf); elen = apr_base64_encode_len(len); out = (char *) malloc(sizeof(char) * (elen + 1)); apr_base64_encode(out, buf, len); return out; } char *b64_decode(char *buf) { int blen; int elen; char *out; blen = strlen(buf); elen = apr_base64_decode_len(buf, blen); out = (char *) malloc(sizeof(char) * (elen + 1)); apr_base64_decode(out, buf, blen); return out; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/base64.h����������������������������������������������������������������0000664�0000000�0000000�00000003540�12614627753�0017013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/base64.h * @brief Base64 encoding * @author Apache Software Foundation * $Date: 2004/05/17 05:03:13 $ * $Revision: 1.1 $ */ #ifndef INCL_UTIL_BASE64_H #define INCL_UTIL_BASE64_H 1 /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ /* base64 functions */ JABBERD2_API int apr_base64_decode_len(const char *bufcoded); JABBERD2_API int apr_base64_decode(char *bufplain, const char *bufcoded); JABBERD2_API int apr_base64_encode_len(int len); JABBERD2_API int apr_base64_encode(char *encoded, const unsigned char *string, int len); /* convenience, result string must be free()'d by caller */ JABBERD2_API char *b64_encode(char *buf, int len); JABBERD2_API char *b64_decode(char *buf); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/config.c����������������������������������������������������������������0000664�0000000�0000000�00000026554�12614627753�0017201�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" #include "expat.h" /** new config structure */ config_t config_new(void) { config_t c; c = (config_t) calloc(1, sizeof(struct config_st)); c->hash = xhash_new(501); return c; } struct build_data { nad_t nad; int depth; }; static void _config_startElement(void *arg, const char *name, const char **atts) { struct build_data *bd = (struct build_data *) arg; int i = 0; nad_append_elem(bd->nad, -1, (char *) name, bd->depth); while(atts[i] != NULL) { nad_append_attr(bd->nad, -1, (char *) atts[i], (char *) atts[i + 1]); i += 2; } bd->depth++; } static void _config_endElement(void *arg, const char *name) { struct build_data *bd = (struct build_data *) arg; bd->depth--; } static void _config_charData(void *arg, const char *str, int len) { struct build_data *bd = (struct build_data *) arg; nad_append_cdata(bd->nad, (char *) str, len, bd->depth); } static char *_config_expandx(config_t c, const char *value, int l); /** turn an xml file into a config hash */ int config_load(config_t c, const char *file) { return config_load_with_id(c, file, 0); } /** turn an xml file into a config hash */ int config_load_with_id(config_t c, const char *file, const char *id) { struct build_data bd; FILE *f; XML_Parser p; int done, len, end, i, j, attr; char buf[1024], *next; struct nad_elem_st **path; config_elem_t elem; int rv = 0; /* open the file */ f = fopen(file, "r"); if(f == NULL) { fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno)); return 1; } /* new parser */ p = XML_ParserCreate(NULL); if(p == NULL) { fprintf(stderr, "config_load: couldn't allocate XML parser\n"); fclose(f); return 1; } /* nice new nad to parse it into */ bd.nad = nad_new(); bd.depth = 0; /* setup the parser */ XML_SetUserData(p, (void *) &bd); XML_SetElementHandler(p, _config_startElement, _config_endElement); XML_SetCharacterDataHandler(p, _config_charData); for(;;) { /* read that file */ len = fread(buf, 1, 1024, f); if(ferror(f)) { fprintf(stderr, "config_load: read error: %s\n", strerror(errno)); XML_ParserFree(p); fclose(f); nad_free(bd.nad); return 1; } done = feof(f); /* parse it */ if(!XML_Parse(p, buf, len, done)) { fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); XML_ParserFree(p); fclose(f); nad_free(bd.nad); return 1; } if(done) break; } /* done reading */ XML_ParserFree(p); fclose(f); // Put id if specified if (id) { elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem); elem->values = calloc(1, sizeof(char *)); elem->values[0] = pstrdup(xhash_pool(c->hash), id); elem->nvalues = 1; } /* now, turn the nad into a config hash */ path = NULL; len = 0, end = 0; /* start at 1, so we skip the root element */ for(i = 1; i < bd.nad->ecur && rv == 0; i++) { /* make sure we have enough room to add this element to our path */ if(end <= bd.nad->elems[i].depth) { end = bd.nad->elems[i].depth + 1; path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end); } /* save this path element */ path[bd.nad->elems[i].depth] = &bd.nad->elems[i]; len = bd.nad->elems[i].depth + 1; /* construct the key from the current path */ next = buf; for(j = 1; j < len; j++) { strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname); next = next + path[j]->lname; *next = '.'; next++; } next--; *next = '\0'; /* find the config element for this key */ elem = xhash_get(c->hash, buf); if(elem == NULL) { /* haven't seen it before, so create it */ elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem); } /* make room for this value .. can't easily realloc off a pool, so * we do it this way and let _config_reaper clean up */ elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1)); /* and copy it in */ if(NAD_CDATA_L(bd.nad, i) > 0) { // Expand values const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i)); if (!val) { rv = 1; break; } // Make a copy elem->values[elem->nvalues] = val; } else { elem->values[elem->nvalues] = "1"; } /* make room for the attribute lists */ elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1)); elem->attrs[elem->nvalues] = NULL; /* count the attributes */ for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++); /* make space */ elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2)); /* if we have some */ if(j > 0) { /* copy them in */ j = 0; attr = bd.nad->elems[i].attr; while(attr >= 0) { elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr)); elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); /* * pstrdupx(blob, 0) returns NULL - which means that later * there's no way of telling whether an attribute is defined * as empty, or just not defined. This fixes that by creating * an empty string for attributes which are defined empty */ if (NAD_AVAL_L(bd.nad, attr)==0) { elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), ""); } else { elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); } j += 2; attr = bd.nad->attrs[attr].next; } } /* do this and we can use j_attr */ elem->attrs[elem->nvalues][j] = NULL; elem->attrs[elem->nvalues][j + 1] = NULL; elem->nvalues++; } if(path != NULL) free(path); if(c->nad != NULL) nad_free(c->nad); c->nad = bd.nad; return rv; } /** get the config element for this key */ config_elem_t config_get(config_t c, const char *key) { return xhash_get(c->hash, key); } /** get config value n for this key */ const char *config_get_one(config_t c, const char* key, int num) { config_elem_t elem = xhash_get(c->hash, key); if(elem == NULL) return NULL; if(num >= elem->nvalues) return NULL; return elem->values[num]; } /** get config value n for this key, returns default_value if not found */ const char *config_get_one_default(config_t c, const char *key, int num, const char *default_value) { const char *rv = config_get_one(c, key, num); if (!rv) rv = default_value; return rv; }; /** how many values for this key? */ int config_count(config_t c, const char *key) { config_elem_t elem = xhash_get(c->hash, key); if(elem == NULL) return 0; return elem->nvalues; } /** get an attr for this value */ char *config_get_attr(config_t c, const char *key, int num, const char *attr) { config_elem_t elem = xhash_get(c->hash, key); if(num >= elem->nvalues || elem->attrs == NULL || elem->attrs[num] == NULL) return NULL; return j_attr((const char **) elem->attrs[num], attr); } /** cleanup helper */ static void _config_reaper(const char *key, int keylen, void *val, void *arg) { config_elem_t elem = (config_elem_t) val; free(elem->values); free(elem->attrs); } char *config_expand(config_t c, const char *value) { return _config_expandx(c, value, strlen(value)); } static char *_config_expandx(config_t c, const char *value, int l) { #ifdef CONFIGEXPAND_GUARDED static char guard[] = "deadbeaf"; #endif // fprintf(stderr, "config_expand: Expanding '%s'\n", value); char *s = strndup(value, l); char *var_start, *var_end; while ((var_start = strstr(s, "${")) != 0) { // fprintf(stderr, "config_expand: processing '%s'\n", s); var_end = strstr(var_start + 2, "}"); if (var_end) { char *tail = var_end + 1; char *var = var_start + 2; *var_end = 0; // fprintf(stderr, "config_expand: Var '%s', tail is '%s'\n", var, tail); const char *var_value = config_get_one(c, var, 0); if (var_value) { int len = (var_start - s) + strlen(tail) + strlen(var_value) + 1; #ifdef CONFIGEXPAND_GUARDED len += sizeof(guard); #endif char *expanded_str = calloc(len, 1); #ifdef CONFIGEXPAND_GUARDED char *p_guard = expanded_str + len - sizeof(guard); strncpy(p_guard, guard, sizeof(guard)); #endif char *p = expanded_str; strncpy(expanded_str, s, var_start - s); p += var_start - s; strcpy(p, var_value); p += strlen(var_value); strcpy(p, tail); free(s); s = expanded_str; } else { fprintf(stderr, "config_expand: Have no '%s' defined\n", var); free(s); s = 0; break; } } else { fprintf(stderr, "config_expand: } missmatch\n"); free(s); s = 0; break; } } if (s) { char *retval = pstrdup(xhash_pool(c->hash), s); free(s); return retval; } else { return 0; } } /** cleanup */ void config_free(config_t c) { xhash_walk(c->hash, _config_reaper, NULL); xhash_free(c->hash); nad_free(c->nad); free(c); } ����������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/crypt_blowfish.c��������������������������������������������������������0000664�0000000�0000000�00000117555�12614627753�0020774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The crypt_blowfish homepage is: * * http://www.openwall.com/crypt/ * * This code comes from John the Ripper password cracker, with reentrant * and crypt(3) interfaces added, but optimizations specific to password * cracking removed. * * Written by Solar Designer <solar at openwall.com> in 1998-2014. * No copyright is claimed, and the software is hereby placed in the public * domain. In case this attempt to disclaim copyright and place the software * in the public domain is deemed null and void, then the software is * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * It is my intent that you should be able to use this on your system, * as part of a software package, or anywhere else to improve security, * ensure compatibility, or for any other purpose. I would appreciate * it if you give credit where it is due and keep your modifications in * the public domain as well, but I don't require that in order to let * you place this code and any modifications you make under a license * of your choice. * * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix * "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses * some of his ideas. The password hashing algorithm was designed by David * Mazieres <dm at lcs.mit.edu>. For information on the level of * compatibility for bcrypt hash prefixes other than "$2b$", please refer to * the comments in BF_set_key() below and to the included crypt(3) man page. * * There's a paper on the algorithm that explains its design decisions: * * http://www.usenix.org/events/usenix99/provos.html * * Some of the tricks in BF_ROUND might be inspired by Eric Young's * Blowfish library (I can't be sure if I would think of something if I * hadn't seen his code). */ #include <stdlib.h> #include <string.h> #include <errno.h> #ifndef __set_errno #define __set_errno(val) errno = (val) #endif /* Just to make sure the prototypes match the actual definitions */ #include "crypt_blowfish.h" #ifdef __i386__ #define BF_ASM 1 #define BF_SCALE 1 #elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) #define BF_ASM 0 #define BF_SCALE 1 #else #define BF_ASM 0 #define BF_SCALE 0 #endif typedef unsigned int BF_word; typedef signed int BF_word_signed; /* Number of Blowfish rounds, this is also hardcoded into a few places */ #define BF_N 16 typedef BF_word BF_key[BF_N + 2]; typedef struct { BF_word S[4][0x100]; BF_key P; } BF_ctx; /* * Magic IV for 64 Blowfish encryptions that we do at the end. * The string is "OrpheanBeholderScryDoubt" on big-endian. */ static BF_word BF_magic_w[6] = { 0x4F727068, 0x65616E42, 0x65686F6C, 0x64657253, 0x63727944, 0x6F756274 }; /* * P-box and S-box tables initialized with digits of Pi. */ static BF_ctx BF_init_state = { { { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }, { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }, { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }, { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 } }, { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b } }; static unsigned char BF_itoa64[64 + 1] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static unsigned char BF_atoi64[0x60] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 }; #define BF_safe_atoi64(dst, src) \ { \ tmp = (unsigned char)(src); \ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ tmp = BF_atoi64[tmp]; \ if (tmp > 63) return -1; \ (dst) = tmp; \ } static int BF_decode(BF_word *dst, const char *src, int size) { unsigned char *dptr = (unsigned char *)dst; unsigned char *end = dptr + size; const unsigned char *sptr = (const unsigned char *)src; unsigned int tmp, c1, c2, c3, c4; do { BF_safe_atoi64(c1, *sptr++); BF_safe_atoi64(c2, *sptr++); *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); if (dptr >= end) break; BF_safe_atoi64(c3, *sptr++); *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); if (dptr >= end) break; BF_safe_atoi64(c4, *sptr++); *dptr++ = ((c3 & 0x03) << 6) | c4; } while (dptr < end); return 0; } static void BF_encode(char *dst, const BF_word *src, int size) { const unsigned char *sptr = (const unsigned char *)src; const unsigned char *end = sptr + size; unsigned char *dptr = (unsigned char *)dst; unsigned int c1, c2; do { c1 = *sptr++; *dptr++ = BF_itoa64[c1 >> 2]; c1 = (c1 & 0x03) << 4; if (sptr >= end) { *dptr++ = BF_itoa64[c1]; break; } c2 = *sptr++; c1 |= c2 >> 4; *dptr++ = BF_itoa64[c1]; c1 = (c2 & 0x0f) << 2; if (sptr >= end) { *dptr++ = BF_itoa64[c1]; break; } c2 = *sptr++; c1 |= c2 >> 6; *dptr++ = BF_itoa64[c1]; *dptr++ = BF_itoa64[c2 & 0x3f]; } while (sptr < end); } static void BF_swap(BF_word *x, int count) { static int endianness_check = 1; char *is_little_endian = (char *)&endianness_check; BF_word tmp; if (*is_little_endian) do { tmp = *x; tmp = (tmp << 16) | (tmp >> 16); *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); } while (--count); } #if BF_SCALE /* Architectures which can shift addresses left by 2 bits with no extra cost */ #define BF_ROUND(L, R, N) \ tmp1 = L & 0xFF; \ tmp2 = L >> 8; \ tmp2 &= 0xFF; \ tmp3 = L >> 16; \ tmp3 &= 0xFF; \ tmp4 = L >> 24; \ tmp1 = data.ctx.S[3][tmp1]; \ tmp2 = data.ctx.S[2][tmp2]; \ tmp3 = data.ctx.S[1][tmp3]; \ tmp3 += data.ctx.S[0][tmp4]; \ tmp3 ^= tmp2; \ R ^= data.ctx.P[N + 1]; \ tmp3 += tmp1; \ R ^= tmp3; #else /* Architectures with no complicated addressing modes supported */ #define BF_INDEX(S, i) \ (*((BF_word *)(((unsigned char *)S) + (i)))) #define BF_ROUND(L, R, N) \ tmp1 = L & 0xFF; \ tmp1 <<= 2; \ tmp2 = L >> 6; \ tmp2 &= 0x3FC; \ tmp3 = L >> 14; \ tmp3 &= 0x3FC; \ tmp4 = L >> 22; \ tmp4 &= 0x3FC; \ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ tmp3 ^= tmp2; \ R ^= data.ctx.P[N + 1]; \ tmp3 += tmp1; \ R ^= tmp3; #endif /* * Encrypt one block, BF_N is hardcoded here. */ #define BF_ENCRYPT \ L ^= data.ctx.P[0]; \ BF_ROUND(L, R, 0); \ BF_ROUND(R, L, 1); \ BF_ROUND(L, R, 2); \ BF_ROUND(R, L, 3); \ BF_ROUND(L, R, 4); \ BF_ROUND(R, L, 5); \ BF_ROUND(L, R, 6); \ BF_ROUND(R, L, 7); \ BF_ROUND(L, R, 8); \ BF_ROUND(R, L, 9); \ BF_ROUND(L, R, 10); \ BF_ROUND(R, L, 11); \ BF_ROUND(L, R, 12); \ BF_ROUND(R, L, 13); \ BF_ROUND(L, R, 14); \ BF_ROUND(R, L, 15); \ tmp4 = R; \ R = L; \ L = tmp4 ^ data.ctx.P[BF_N + 1]; #if BF_ASM #define BF_body() \ _BF_body_r(&data.ctx); #else #define BF_body() \ L = R = 0; \ ptr = data.ctx.P; \ do { \ ptr += 2; \ BF_ENCRYPT; \ *(ptr - 2) = L; \ *(ptr - 1) = R; \ } while (ptr < &data.ctx.P[BF_N + 2]); \ \ ptr = data.ctx.S[0]; \ do { \ ptr += 2; \ BF_ENCRYPT; \ *(ptr - 2) = L; \ *(ptr - 1) = R; \ } while (ptr < &data.ctx.S[3][0xFF]); #endif static void BF_set_key(const char *key, BF_key expanded, BF_key initial, unsigned char flags) { const char *ptr = key; unsigned int bug, i, j; BF_word safety, sign, diff, tmp[2]; /* * There was a sign extension bug in older revisions of this function. While * we would have liked to simply fix the bug and move on, we have to provide * a backwards compatibility feature (essentially the bug) for some systems and * a safety measure for some others. The latter is needed because for certain * multiple inputs to the buggy algorithm there exist easily found inputs to * the correct algorithm that produce the same hash. Thus, we optionally * deviate from the correct algorithm just enough to avoid such collisions. * While the bug itself affected the majority of passwords containing * characters with the 8th bit set (although only a percentage of those in a * collision-producing way), the anti-collision safety measure affects * only a subset of passwords containing the '\xff' character (not even all of * those passwords, just some of them). This character is not found in valid * UTF-8 sequences and is rarely used in popular 8-bit character encodings. * Thus, the safety measure is unlikely to cause much annoyance, and is a * reasonable tradeoff to use when authenticating against existing hashes that * are not reliably known to have been computed with the correct algorithm. * * We use an approach that tries to minimize side-channel leaks of password * information - that is, we mostly use fixed-cost bitwise operations instead * of branches or table lookups. (One conditional branch based on password * length remains. It is not part of the bug aftermath, though, and is * difficult and possibly unreasonable to avoid given the use of C strings by * the caller, which results in similar timing leaks anyway.) * * For actual implementation, we set an array index in the variable "bug" * (0 means no bug, 1 means sign extension bug emulation) and a flag in the * variable "safety" (bit 16 is set when the safety measure is requested). * Valid combinations of settings are: * * Prefix "$2a$": bug = 0, safety = 0x10000 * Prefix "$2b$": bug = 0, safety = 0 * Prefix "$2x$": bug = 1, safety = 0 * Prefix "$2y$": bug = 0, safety = 0 */ bug = (unsigned int)flags & 1; safety = ((BF_word)flags & 2) << 15; sign = diff = 0; for (i = 0; i < BF_N + 2; i++) { tmp[0] = tmp[1] = 0; for (j = 0; j < 4; j++) { tmp[0] <<= 8; tmp[0] |= (unsigned char)*ptr; /* correct */ tmp[1] <<= 8; tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ /* * Sign extension in the first char has no effect - nothing to overwrite yet, * and those extra 24 bits will be fully shifted out of the 32-bit word. For * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign * extension in tmp[1] occurs. Once this flag is set, it remains set. */ if (j) sign |= tmp[1] & 0x80; if (!*ptr) ptr = key; else ptr++; } diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ expanded[i] = tmp[bug]; initial[i] = BF_init_state.P[i] ^ tmp[bug]; } /* * At this point, "diff" is zero iff the correct and buggy algorithms produced * exactly the same result. If so and if "sign" is non-zero, which indicates * that there was a non-benign sign extension, this means that we have a * collision between the correctly computed hash for this password and a set of * passwords that could be supplied to the buggy algorithm. Our safety measure * is meant to protect from such many-buggy to one-correct collisions, by * deviating from the correct algorithm in such cases. Let's check for this. */ diff |= diff >> 16; /* still zero iff exact match */ diff &= 0xffff; /* ditto */ diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ sign &= ~diff & safety; /* action needed? */ /* * If we have determined that we need to deviate from the correct algorithm, * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but * let's stick to it now. It came out of the approach we used above, and it's * not any worse than any other choice we could make.) * * It is crucial that we don't do the same to the expanded key used in the main * Eksblowfish loop. By doing it to only one of these two, we deviate from a * state that could be directly specified by a password to the buggy algorithm * (and to the fully correct one as well, but that's a side-effect). */ initial[0] ^= sign; } static const unsigned char flags_by_subtype[26] = {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; static char *BF_crypt(const char *key, const char *setting, char *output, int size, BF_word min) { #if BF_ASM extern void _BF_body_r(BF_ctx *ctx); #endif struct { BF_ctx ctx; BF_key expanded_key; union { BF_word salt[4]; BF_word output[6]; } binary; } data; BF_word L, R; BF_word tmp1, tmp2, tmp3, tmp4; BF_word *ptr; BF_word count; int i; if (size < 7 + 22 + 31 + 1) { __set_errno(ERANGE); return NULL; } if (setting[0] != '$' || setting[1] != '2' || setting[2] < 'a' || setting[2] > 'z' || !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || setting[3] != '$' || setting[4] < '0' || setting[4] > '3' || setting[5] < '0' || setting[5] > '9' || (setting[4] == '3' && setting[5] > '1') || setting[6] != '$') { __set_errno(EINVAL); return NULL; } count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { __set_errno(EINVAL); return NULL; } BF_swap(data.binary.salt, 4); BF_set_key(key, data.expanded_key, data.ctx.P, flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); L = R = 0; for (i = 0; i < BF_N + 2; i += 2) { L ^= data.binary.salt[i & 2]; R ^= data.binary.salt[(i & 2) + 1]; BF_ENCRYPT; data.ctx.P[i] = L; data.ctx.P[i + 1] = R; } ptr = data.ctx.S[0]; do { ptr += 4; L ^= data.binary.salt[(BF_N + 2) & 3]; R ^= data.binary.salt[(BF_N + 3) & 3]; BF_ENCRYPT; *(ptr - 4) = L; *(ptr - 3) = R; L ^= data.binary.salt[(BF_N + 4) & 3]; R ^= data.binary.salt[(BF_N + 5) & 3]; BF_ENCRYPT; *(ptr - 2) = L; *(ptr - 1) = R; } while (ptr < &data.ctx.S[3][0xFF]); do { int done; for (i = 0; i < BF_N + 2; i += 2) { data.ctx.P[i] ^= data.expanded_key[i]; data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; } done = 0; do { BF_body(); if (done) break; done = 1; tmp1 = data.binary.salt[0]; tmp2 = data.binary.salt[1]; tmp3 = data.binary.salt[2]; tmp4 = data.binary.salt[3]; for (i = 0; i < BF_N; i += 4) { data.ctx.P[i] ^= tmp1; data.ctx.P[i + 1] ^= tmp2; data.ctx.P[i + 2] ^= tmp3; data.ctx.P[i + 3] ^= tmp4; } data.ctx.P[16] ^= tmp1; data.ctx.P[17] ^= tmp2; } while (1); } while (--count); for (i = 0; i < 6; i += 2) { L = BF_magic_w[i]; R = BF_magic_w[i + 1]; count = 64; do { BF_ENCRYPT; } while (--count); data.binary.output[i] = L; data.binary.output[i + 1] = R; } memcpy(output, setting, 7 + 22 - 1); output[7 + 22 - 1] = BF_itoa64[(int) BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; /* This has to be bug-compatible with the original implementation, so * only encode 23 of the 24 bytes. :-) */ BF_swap(data.binary.output, 6); BF_encode(&output[7 + 22], data.binary.output, 23); output[7 + 22 + 31] = '\0'; return output; } int _crypt_output_magic(const char *setting, char *output, int size) { if (size < 3) return -1; output[0] = '*'; output[1] = '0'; output[2] = '\0'; if (setting[0] == '*' && setting[1] == '0') output[1] = '1'; return 0; } /* * Please preserve the runtime self-test. It serves two purposes at once: * * 1. We really can't afford the risk of producing incompatible hashes e.g. * when there's something like gcc bug 26587 again, whereas an application or * library integrating this code might not also integrate our external tests or * it might not run them after every build. Even if it does, the miscompile * might only occur on the production build, but not on a testing build (such * as because of different optimization settings). It is painful to recover * from incorrectly-computed hashes - merely fixing whatever broke is not * enough. Thus, a proactive measure like this self-test is needed. * * 2. We don't want to leave sensitive data from our actual password hash * computation on the stack or in registers. Previous revisions of the code * would do explicit cleanups, but simply running the self-test after hash * computation is more reliable. * * The performance cost of this quick self-test is around 0.6% at the "$2a$08" * setting. */ char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size) { const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; static const char * const test_hashes[2] = {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ const char *test_hash = test_hashes[0]; char *retval; const char *p; int save_errno, ok; struct { char s[7 + 22 + 1]; char o[7 + 22 + 31 + 1 + 1 + 1]; } buf; /* Hash the supplied password */ _crypt_output_magic(setting, output, size); retval = BF_crypt(key, setting, output, size, 16); save_errno = errno; /* * Do a quick self-test. It is important that we make both calls to BF_crypt() * from the same scope such that they likely use the same stack locations, * which makes the second call overwrite the first call's sensitive data on the * stack and makes it more likely that any alignment related issues would be * detected by the self-test. */ memcpy(buf.s, test_setting, sizeof(buf.s)); if (retval) { unsigned int flags = flags_by_subtype[ (unsigned int)(unsigned char)setting[2] - 'a']; test_hash = test_hashes[flags & 1]; buf.s[2] = setting[2]; } memset(buf.o, 0x55, sizeof(buf.o)); buf.o[sizeof(buf.o) - 1] = 0; p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); ok = (p == buf.o && !memcmp(p, buf.s, 7 + 22) && !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); { const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; BF_key ae, ai, ye, yi; BF_set_key(k, ae, ai, 2); /* $2a$ */ BF_set_key(k, ye, yi, 4); /* $2y$ */ ai[0] ^= 0x10000; /* undo the safety (for comparison) */ ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && !memcmp(ae, ye, sizeof(ae)) && !memcmp(ai, yi, sizeof(ai)); } __set_errno(save_errno); if (ok) return retval; /* Should not happen */ _crypt_output_magic(setting, output, size); __set_errno(EINVAL); /* pretend we don't support this hash type */ return NULL; } char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { if (size < 16 || output_size < 7 + 22 + 1 || (count && (count < 4 || count > 31)) || prefix[0] != '$' || prefix[1] != '2' || (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); return NULL; } if (!count) count = 5; output[0] = '$'; output[1] = '2'; output[2] = prefix[2]; output[3] = '$'; output[4] = '0' + count / 10; output[5] = '0' + count % 10; output[6] = '$'; BF_encode(&output[7], (const BF_word *)input, 16); output[7 + 22] = '\0'; return output; } unsigned char _crypt_itoa64[64 + 1] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { (void) prefix; if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); return NULL; } output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; output[2] = '\0'; return output; } char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { unsigned long value; (void) prefix; /* Even iteration counts make it easier to detect weak DES keys from a look * at the hash, so they should be avoided */ if (size < 3 || output_size < 1 + 4 + 4 + 1 || (count && (count > 0xffffff || !(count & 1)))) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); return NULL; } if (!count) count = 725; output[0] = '_'; output[1] = _crypt_itoa64[count & 0x3f]; output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; value = (unsigned long)(unsigned char)input[0] | ((unsigned long)(unsigned char)input[1] << 8) | ((unsigned long)(unsigned char)input[2] << 16); output[5] = _crypt_itoa64[value & 0x3f]; output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; output[9] = '\0'; return output; } char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { unsigned long value; (void) prefix; if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { if (output_size > 0) output[0] = '\0'; __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); return NULL; } output[0] = '$'; output[1] = '1'; output[2] = '$'; value = (unsigned long)(unsigned char)input[0] | ((unsigned long)(unsigned char)input[1] << 8) | ((unsigned long)(unsigned char)input[2] << 16); output[3] = _crypt_itoa64[value & 0x3f]; output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; output[7] = '\0'; if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { value = (unsigned long)(unsigned char)input[3] | ((unsigned long)(unsigned char)input[4] << 8) | ((unsigned long)(unsigned char)input[5] << 16); output[7] = _crypt_itoa64[value & 0x3f]; output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; output[11] = '\0'; } return output; } #define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1) #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1) static int _crypt_data_alloc(void **data, int *size, int need) { void *updated; if (*data && *size >= need) return 0; updated = realloc(*data, need); if (!updated) { #ifndef __GLIBC__ /* realloc(3) on glibc sets errno, so we don't need to bother */ __set_errno(ENOMEM); #endif return -1; } *data = updated; *size = need; return 0; } static char *_crypt_retval_magic(char *retval, const char *setting, char *output, int size) { if (retval) return retval; if (_crypt_output_magic(setting, output, size)) return NULL; /* shouldn't happen */ return output; } #if defined(__GLIBC__) && defined(_LIBC) /* * Applications may re-use the same instance of struct crypt_data without * resetting the initialized field in order to let crypt_r() skip some of * its initialization code. Thus, it is important that our multiple hashing * algorithms either don't conflict with each other in their use of the * data area or reset the initialized field themselves whenever required. * Currently, the hashing algorithms simply have no conflicts: the first * field of struct crypt_data is the 128-byte large DES key schedule which * __des_crypt_r() calculates each time it is called while the two other * hashing algorithms use less than 128 bytes of the data area. */ char *__crypt_rn(__const char *key, __const char *setting, void *data, int size) { if (setting[0] == '$' && setting[1] == '2') return _crypt_blowfish_rn(key, setting, (char *)data, size); if (setting[0] == '$' && setting[1] == '1') return __md5_crypt_r(key, setting, (char *)data, size); if (setting[0] == '$' || setting[0] == '_') { __set_errno(EINVAL); return NULL; } if (size >= sizeof(struct crypt_data)) return __des_crypt_r(key, setting, (struct crypt_data *)data); __set_errno(ERANGE); return NULL; } char *__crypt_ra(__const char *key, __const char *setting, void **data, int *size) { if (setting[0] == '$' && setting[1] == '2') { if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) return NULL; return _crypt_blowfish_rn(key, setting, (char *)*data, *size); } if (setting[0] == '$' && setting[1] == '1') { if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) return NULL; return __md5_crypt_r(key, setting, (char *)*data, *size); } if (setting[0] == '$' || setting[0] == '_') { __set_errno(EINVAL); return NULL; } if (_crypt_data_alloc(data, size, sizeof(struct crypt_data))) return NULL; return __des_crypt_r(key, setting, (struct crypt_data *)*data); } char *__crypt_r(__const char *key, __const char *setting, struct crypt_data *data) { return _crypt_retval_magic( __crypt_rn(key, setting, data, sizeof(*data)), setting, (char *)data, sizeof(*data)); } char *__crypt(__const char *key, __const char *setting) { return _crypt_retval_magic( __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)), setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar)); } #else char *crypt_rn(const char *key, const char *setting, void *data, int size) { return _crypt_blowfish_rn(key, setting, (char *)data, size); } char *crypt_ra(const char *key, const char *setting, void **data, int *size) { if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) return NULL; return _crypt_blowfish_rn(key, setting, (char *)*data, *size); } char *crypt_r(const char *key, const char *setting, void *data) { return _crypt_retval_magic( crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), setting, (char *)data, CRYPT_OUTPUT_SIZE); } char *bcrypt(const char *key, const char *setting) { static char output[CRYPT_OUTPUT_SIZE]; return _crypt_retval_magic( crypt_rn(key, setting, output, sizeof(output)), setting, output, sizeof(output)); } #define __crypt_gensalt_rn crypt_gensalt_rn #define __crypt_gensalt_ra crypt_gensalt_ra #define __crypt_gensalt bcrypt_gensalt #endif char *__crypt_gensalt_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { char *(*use)(const char *_prefix, unsigned long _count, const char *_input, int _size, char *_output, int _output_size); /* This may be supported on some platforms in the future */ if (!input) { __set_errno(EINVAL); return NULL; } if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) || !strncmp(prefix, "$2y$", 4)) use = _crypt_gensalt_blowfish_rn; else if (!strncmp(prefix, "$1$", 3)) use = _crypt_gensalt_md5_rn; else if (prefix[0] == '_') use = _crypt_gensalt_extended_rn; else if (!prefix[0] || (prefix[0] && prefix[1] && memchr(_crypt_itoa64, prefix[0], 64) && memchr(_crypt_itoa64, prefix[1], 64))) use = _crypt_gensalt_traditional_rn; else { __set_errno(EINVAL); return NULL; } return use(prefix, count, input, size, output, output_size); } char *__crypt_gensalt_ra(const char *prefix, unsigned long count, const char *input, int size) { char output[CRYPT_GENSALT_OUTPUT_SIZE]; char *retval; retval = __crypt_gensalt_rn(prefix, count, input, size, output, sizeof(output)); if (retval) { retval = strdup(retval); #ifndef __GLIBC__ /* strdup(3) on glibc sets errno, so we don't need to bother */ if (!retval) __set_errno(ENOMEM); #endif } return retval; } char *__crypt_gensalt(const char *prefix, unsigned long count, const char *input, int size) { static char output[CRYPT_GENSALT_OUTPUT_SIZE]; return __crypt_gensalt_rn(prefix, count, input, size, output, sizeof(output)); }���������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/crypt_blowfish.h��������������������������������������������������������0000664�0000000�0000000�00000004265�12614627753�0020772�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Written by Solar Designer <solar at openwall.com> in 2000-2011. * No copyright is claimed, and the software is hereby placed in the public * domain. In case this attempt to disclaim copyright and place the software * in the public domain is deemed null and void, then the software is * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * See crypt_blowfish.c for more information. */ #ifndef _CRYPT_BLOWFISH_H #define _CRYPT_BLOWFISH_H #ifndef __GNUC__ #undef __const #define __const const #endif extern char *bcrypt(__const char *key, __const char *setting); extern char *crypt_r(__const char *key, __const char *setting, void *data); #ifndef __SKIP_OW extern char *crypt_rn(__const char *key, __const char *setting, void *data, int size); extern char *crypt_ra(__const char *key, __const char *setting, void **data, int *size); extern char *bcrypt_gensalt(__const char *prefix, unsigned long count, __const char *input, int size); extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count, __const char *input, int size, char *output, int output_size); extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count, __const char *input, int size); #endif extern int _crypt_output_magic(const char *setting, char *output, int size); extern char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size); extern char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); extern unsigned char _crypt_itoa64[]; extern char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); extern char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/datetime.c��������������������������������������������������������������0000664�0000000�0000000�00000010776�12614627753�0017527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" /* ISO 8601 / JEP-0082 date/time manipulation */ /* formats */ #define DT_DATETIME_P "%04d-%02d-%02dT%02d:%02d:%lf+%02d:%02d" #define DT_DATETIME_M "%04d-%02d-%02dT%02d:%02d:%lf-%02d:%02d" #define DT_DATETIME_Z "%04d-%02d-%02dT%02d:%02d:%lfZ" #define DT_TIME_P "%02d:%02d:%lf+%02d:%02d" #define DT_TIME_M "%02d:%02d:%lf-%02d:%02d" #define DT_TIME_Z "%02d:%02d:%lfZ" #define DT_LEGACY "%04d%02d%02dT%02d:%02d:%lf" time_t datetime_in(char *date) { struct tm gmt, off; double sec; off_t fix = 0; struct timeval tv; struct timezone tz; assert((int) (date != NULL)); /* !!! sucks having to call this each time */ tzset(); memset(&gmt, 0, sizeof(struct tm)); memset(&off, 0, sizeof(struct tm)); if(sscanf(date, DT_DATETIME_P, &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, &gmt.tm_hour, &gmt.tm_min, &sec, &off.tm_hour, &off.tm_min) == 8) { gmt.tm_sec = (int) sec; gmt.tm_year -= 1900; gmt.tm_mon--; fix = off.tm_hour * 3600 + off.tm_min * 60; } else if(sscanf(date, DT_DATETIME_M, &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, &gmt.tm_hour, &gmt.tm_min, &sec, &off.tm_hour, &off.tm_min) == 8) { gmt.tm_sec = (int) sec; gmt.tm_year -= 1900; gmt.tm_mon--; fix = - off.tm_hour * 3600 - off.tm_min * 60; } else if(sscanf(date, DT_DATETIME_Z, &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, &gmt.tm_hour, &gmt.tm_min, &sec) == 6) { gmt.tm_sec = (int) sec; gmt.tm_year -= 1900; gmt.tm_mon--; fix = 0; } else if(sscanf(date, DT_TIME_P, &gmt.tm_hour, &gmt.tm_min, &sec, &off.tm_hour, &off.tm_min) == 5) { gmt.tm_sec = (int) sec; fix = off.tm_hour * 3600 + off.tm_min * 60; } else if(sscanf(date, DT_TIME_M, &gmt.tm_hour, &gmt.tm_min, &sec, &off.tm_hour, &off.tm_min) == 5) { gmt.tm_sec = (int) sec; fix = - off.tm_hour * 3600 - off.tm_min * 60; } else if(sscanf(date, DT_TIME_Z, &gmt.tm_hour, &gmt.tm_min, &sec) == 3) { gmt.tm_sec = (int) sec; fix = - off.tm_hour * 3600 - off.tm_min * 60; } else if(sscanf(date, DT_LEGACY, &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday, &gmt.tm_hour, &gmt.tm_min, &sec) == 6) { gmt.tm_sec = (int) sec; gmt.tm_year -= 1900; gmt.tm_mon--; fix = 0; } gmt.tm_isdst = -1; gettimeofday(&tv, &tz); return mktime(&gmt) + fix - (tz.tz_minuteswest * 60); } void datetime_out(time_t t, datetime_t type, char *date, int datelen) { struct tm *gmt; assert((int) type); assert((int) (date != NULL)); assert((int) datelen); gmt = gmtime(&t); switch(type) { case dt_DATE: snprintf(date, datelen, "%04d-%02d-%02d", gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday); break; case dt_TIME: snprintf(date, datelen, "%02d:%02d:%02dZ", gmt->tm_hour, gmt->tm_min, gmt->tm_sec); break; case dt_DATETIME: snprintf(date, datelen, "%04d-%02d-%02dT%02d:%02d:%02dZ", gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec); break; case dt_LEGACY: snprintf(date, datelen, "%04d%02d%02dT%02d:%02d:%02d", gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec); break; } } ��jabberd2-jabberd-2.3.4/util/datetime.h��������������������������������������������������������������0000664�0000000�0000000�00000003353�12614627753�0017525�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/datetime.h * @brief ISO 8610 / JEP 82 date/time manipulation * @author Robert Norris * $Date: 2004/05/05 23:49:38 $ * $Revision: 1.1 $ */ #ifndef INCL_UTIL_DATETIME_H #define INCL_UTIL_DATETIME_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <time.h> /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ typedef enum { dt_DATE = 1, dt_TIME = 2, dt_DATETIME = 3, dt_LEGACY = 4 } datetime_t; JABBERD2_API time_t datetime_in(char *date); JABBERD2_API void datetime_out(time_t t, datetime_t type, const char *date, int datelen); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/hex.c�������������������������������������������������������������������0000664�0000000�0000000�00000004061�12614627753�0016505�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* simple hex conversion functions */ #include "util.h" /** turn raw into hex - out must be (inlen*2)+1 */ void hex_from_raw(const unsigned char *in, int inlen, char *out) { int i, h, l; for(i = 0; i < inlen; i++) { h = in[i] & 0xf0; h >>= 4; l = in[i] & 0x0f; out[i * 2] = (h >= 0x0 && h <= 0x9) ? (h + 0x30) : (h + 0x57); out[i * 2 + 1] = (l >= 0x0 && l <= 0x9) ? (l + 0x30) : (l + 0x57); } out[i * 2] = '\0'; } /** turn hex into raw - out must be (inlen/2) */ int hex_to_raw(const char *in, int inlen, char *out) { int i, o, h, l; /* need +ve even input */ if(inlen == 0 || (inlen / 2 * 2) != inlen) return 1; for(i = o = 0; i < inlen; i += 2, o++) { h = (in[i] >= 0x30 && in[i] <= 0x39) ? (in[i] - 0x30) : (in[i] >= 0x41 && in[i] <= 0x64) ? (in[i] - 0x36) : (in[i] >= 0x61 && in[i] <= 0x66) ? (in[i] - 0x56) : -1; l = (in[i + 1] >= 0x30 && in[i + 1] <= 0x39) ? (in[i + 1] - 0x30) : (in[i + 1] >= 0x41 && in[i + 1] <= 0x64) ? (in[i + 1] - 0x36) : (in[i + 1] >= 0x61 && in[i + 1] <= 0x66) ? (in[i + 1] - 0x56) : -1; if(h < 0 || l < 0) return 1; out[o] = (h << 4) + l; } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/inaddr.c����������������������������������������������������������������0000664�0000000�0000000�00000013645�12614627753�0017172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** * @file util/inaddr.c * @brief object like wrapper around struct sockaddr_storage * * The functions in this file are used as a wrapper around struct * sockaddr_storage to access this structure like an object. The structure * is seen as an object that contains an IPv4 or an IPv6 address and * these functions are the access methods to this object. * * @warning this is the same as mio/mio_inaddr.c - changes made here need to be * made there too. is there anyway we can merge these without * requiring mio to depend on util? */ #include "util.h" /** * set the address of a struct sockaddr_storage * (modeled after the stdlib function inet_pton) * * @param src the address that should be assigned to the struct sockaddr_storage * (either a dotted quad for IPv4 or a compressed IPv6 address) * @param dst the struct sockaddr_storage that should get the new address * @return 1 on success, 0 if address is not valid */ int j_inet_pton(const char *src, struct sockaddr_storage *dst) { #ifndef HAVE_INET_PTON struct sockaddr_in *sin; memset(dst, 0, sizeof(struct sockaddr_storage)); sin = (struct sockaddr_in *)dst; if(inet_aton(src, &sin->sin_addr)) { dst->ss_family = AF_INET; return 1; } return 0; #else struct sockaddr_in *sin; struct sockaddr_in6 *sin6; memset(dst, 0, sizeof(struct sockaddr_storage)); sin = (struct sockaddr_in *)dst; sin6 = (struct sockaddr_in6 *)dst; if(inet_pton(AF_INET, src, &sin->sin_addr) > 0) { dst->ss_family = AF_INET; return 1; } if(inet_pton(AF_INET6, src, &sin6->sin6_addr) > 0) { dst->ss_family = AF_INET6; #ifdef SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); #endif return 1; } return 0; #endif } /** * get the string representation of an address in struct sockaddr_storage * (modeled after the stdlib function inet_ntop) * * @param src the struct sockaddr_storage where the address should be read * @param dst where to write the result * @param size the size of the result buffer * @return NULL if failed, pointer to the result otherwise */ const char *j_inet_ntop(struct sockaddr_storage *src, char *dst, size_t size) { #ifndef HAVE_INET_NTOP char *tmp; struct sockaddr_in *sin; sin = (struct sockaddr_in *)src; /* if we don't have inet_ntop we only accept AF_INET * it's unlikely that we would have use for AF_INET6 */ if(src->ss_family != AF_INET) { return NULL; } tmp = inet_ntoa(sin->sin_addr); if(!tmp || strlen(tmp)>=size) { return NULL; } strncpy(dst, tmp, size); return dst; #else struct sockaddr_in *sin; struct sockaddr_in6 *sin6; sin = (struct sockaddr_in *)src; sin6 = (struct sockaddr_in6 *)src; switch(src->ss_family) { case AF_UNSPEC: case AF_INET: return inet_ntop(AF_INET, &sin->sin_addr, dst, size); case AF_INET6: return inet_ntop(AF_INET6, &sin6->sin6_addr, dst, size); default: return NULL; } #endif } /** * get the port number out of a struct sockaddr_storage * * @param sa the struct sockaddr_storage where we want to read the port * @return the port number (already converted to host byte order!) */ int j_inet_getport(struct sockaddr_storage *sa) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; switch(sa->ss_family) { case AF_INET: sin = (struct sockaddr_in *)sa; return ntohs(sin->sin_port); case AF_INET6: sin6 = (struct sockaddr_in6 *)sa; return ntohs(sin6->sin6_port); default: return 0; } } /** * set the port number in a struct sockaddr_storage * * @param sa the struct sockaddr_storage where the port should be set * @param port the port number that should be set (in host byte order) * @return 1 on success, 0 if address family is not supported */ int j_inet_setport(struct sockaddr_storage *sa, in_port_t port) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; sin = (struct sockaddr_in *)sa; sin6 = (struct sockaddr_in6 *)sa; switch(sa->ss_family) { case AF_INET: sin->sin_port = htons(port); return 1; case AF_INET6: sin6->sin6_port = htons(port); return 1; default: return 0; } } /** * calculate the size of an address structure * (on some unices the stdlibc functions for socket handling want to get the * size of the address structure that is contained in the * struct sockaddr_storage, not the size of struct sockaddr_storage itself) * * @param sa the struct sockaddr_storage for which we want to get the size of the contained address structure * @return the size of the contained address structure */ socklen_t j_inet_addrlen(struct sockaddr_storage *sa) { #ifdef SIN6_LEN if(sa->ss_len != 0) return sa->ss_len; #endif switch(sa->ss_family) { case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); default: return sizeof(struct sockaddr_storage); } } �������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/inaddr.h����������������������������������������������������������������0000664�0000000�0000000�00000004163�12614627753�0017172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifndef INCL_INADDR_H #define INCL_INADDR_H #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "ac-stdint.h" #ifdef HAVE_STRING_H #include <string.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef USE_LIBSUBST #include "subst/subst.h" #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifdef __cplusplus extern "C" { #endif /* * helpers for ip addresses */ #include <util/util_compat.h> JABBERD2_API int j_inet_pton(const char *src, struct sockaddr_storage *dst); JABBERD2_API const char *j_inet_ntop(struct sockaddr_storage* src, char* dst, size_t size); JABBERD2_API int j_inet_getport(struct sockaddr_storage *sa); JABBERD2_API int j_inet_setport(struct sockaddr_storage *sa, in_port_t port); JABBERD2_API socklen_t j_inet_addrlen(struct sockaddr_storage *sa); #ifdef __cplusplus } #endif #endif /* INCL_UTIL_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/jid.c�������������������������������������������������������������������0000664�0000000�0000000�00000031664�12614627753�0016500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" #include <stringprep.h> /** Forward declaration **/ static jid_t jid_reset_components_internal(jid_t jid, const char *node, const char *domain, const char *resource, int prepare); /** do stringprep on the pieces */ static int jid_prep_pieces(char *node, char *domain, char *resource) { if(node[0] != '\0') if(stringprep_xmpp_nodeprep(node, 1024) != 0) return 1; if(stringprep_nameprep(domain, 1024) != 0) return 1; if(resource[0] != '\0') if(stringprep_xmpp_resourceprep(resource, 1024) != 0) return 1; return 0; } /** do stringprep on the piece **/ int jid_prep(jid_t jid) { char node[MAXLEN_JID_COMP+1]; char domain[MAXLEN_JID_COMP+1]; char resource[MAXLEN_JID_COMP+1]; if(jid->node != NULL) { strncpy(node, jid->node, MAXLEN_JID_COMP); node[MAXLEN_JID_COMP]='\0'; } else node[0] = '\0'; if(jid->domain != NULL) { strncpy(domain, jid->domain, MAXLEN_JID_COMP); domain[MAXLEN_JID_COMP]='\0'; } else domain[0] = '\0'; if(jid->resource != NULL) { strncpy(resource, jid->resource, MAXLEN_JID_COMP); resource[MAXLEN_JID_COMP]='\0'; } else resource[0] = '\0'; if(jid_prep_pieces(node, domain, resource) != 0) return 1; /* put prepared components into jid */ jid_reset_components_internal(jid, node, domain, resource, 0); return 0; } /** make a new jid */ jid_t jid_new(const char *id, int len) { jid_t jid, ret; jid = malloc(sizeof(struct jid_st)); jid->jid_data = NULL; ret = jid_reset(jid, id, len); if(ret == NULL) { if(len < 0) { log_debug(ZONE, "invalid jid: %s", id); } else { log_debug(ZONE, "invalid jid: %.*s", len, id); } free(jid); } return ret; } /** Make jid to use static buffer (jid data won't be allocated dynamically, but * given buffer will be always used. JID may not be previously used! */ void jid_static(jid_t jid, jid_static_buf *buf) { /* clear jid */ memset(jid, 0, sizeof(*jid)); /* set buffer */ jid->jid_data = (char *)buf; } /** build a jid from an id */ jid_t jid_reset(jid_t jid, const char *id, int len) { char *myid, *cur, *olddata=NULL; assert((int) (jid != NULL)); if (jid->jid_data != NULL) { if(jid->jid_data_len != 0) free(jid->jid_data); else olddata = jid->jid_data; /* store pointer to old data */ } memset(jid, 0, sizeof(struct jid_st)); jid->dirty = 1; jid->node = ""; jid->domain = ""; jid->resource = ""; /* nice empty jid */ if(id == NULL) return jid; if(len < 0) len = strlen(id); if((len == 0) || (len > MAXLEN_JID)) return NULL; if(olddata != NULL) myid = olddata; /* use static buffer */ else { jid->jid_data_len = sizeof(char) * (len + 1); myid = (char *) malloc(jid->jid_data_len); } sprintf(myid, "%.*s", len, id); /* fail - only a resource or leading @ */ if(myid[0] == '/' || myid[0] == '@') { if(olddata == NULL) free(myid); return NULL; } /* get the resource first */ cur = strstr(myid, "/"); if(cur != NULL) { *cur = '\0'; cur++; if(strlen(cur) > 0) { jid->resource = cur; } else { /* fail - a resource separator but nothing after it */ if(olddata == NULL) free(myid); return NULL; } } /* find the domain */ cur = strstr(myid, "@"); if(cur != NULL) { *cur = '\0'; cur++; if(strlen(cur) == 0) { /* no domain part, bail out */ if(olddata == NULL) free(myid); return NULL; } jid->domain = cur; jid->node = myid; } else { /* no @, so it's a domain only */ jid->domain = myid; } jid->jid_data = myid; if(jid_prep(jid) != 0) { if(olddata == NULL) free(myid); jid->jid_data = NULL; return NULL; } return jid; } /** build a jid from components - internal version */ static jid_t jid_reset_components_internal(jid_t jid, const char *node, const char *domain, const char *resource, int prepare) { char *olddata=NULL; int node_l,domain_l,resource_l; int dataStatic; jid_static_buf staticTmpBuf; assert((int) (jid != NULL)); if(jid->jid_data != NULL) olddata = jid->jid_data; /* Store old data before clearing JID */ dataStatic = ((jid->jid_data != NULL) && (jid->jid_data_len == 0)); if (jid->_user != NULL ) free(jid->_user); if (jid->_full != NULL ) free(jid->_full); memset(jid, 0, sizeof(struct jid_st)); /* get lengths */ node_l = strlen(node); domain_l = strlen(domain); resource_l = strlen(resource); if(node_l > MAXLEN_JID_COMP) node_l = MAXLEN_JID_COMP; if(domain_l > MAXLEN_JID_COMP) domain_l = MAXLEN_JID_COMP; if(resource_l > MAXLEN_JID_COMP) resource_l = MAXLEN_JID_COMP; if(dataStatic) { /* use static buffer */ jid->jid_data = staticTmpBuf; } else { /* allocate new data buffer */ jid->jid_data_len = node_l+domain_l+resource_l+3; jid->jid_data = realloc(jid->jid_data, jid->jid_data_len); } /* copy to buffer */ jid->node = jid->jid_data; strncpy(jid->node, node, node_l); jid->node[node_l] = 0; jid->domain = jid->node + node_l + 1; strncpy(jid->domain, domain, domain_l); jid->domain[domain_l] = 0; jid->resource = jid->domain + domain_l + 1; strncpy(jid->resource, resource, resource_l); jid->resource[resource_l] = 0; /* Free old data buffer. Postponed to this point so that arguments may point (in)to old jid data. */ if((!dataStatic) && (olddata != NULL)) free(olddata); if(prepare) { if(jid_prep(jid) != 0) return NULL; } jid->dirty = 1; if (dataStatic) { jid->jid_data = olddata; /* Return pointer to the original static buffer */ memcpy(jid->jid_data,staticTmpBuf,node_l+domain_l+resource_l+3); /* Copy data from tmp buf to original buffer */ /* Relocate pointers */ jid->node = olddata+(jid->node-(char *)staticTmpBuf); jid->domain = olddata+(jid->domain-(char *)staticTmpBuf); jid->resource = olddata+(jid->resource-(char *)staticTmpBuf); } return jid; } /** build a jid from components */ jid_t jid_reset_components(jid_t jid, const char *node, const char *domain, const char *resource) { return jid_reset_components_internal(jid, node, domain, resource, 1); } /** free a jid */ void jid_free(jid_t jid) { if((jid->jid_data != NULL) && (jid->jid_data_len != 0)) free(jid->jid_data); if (jid->_user != NULL ) free(jid->_user); if (jid->_full != NULL ) free(jid->_full); if (jid != NULL ) free(jid); } /** build user and full if they're out of date */ void jid_expand(jid_t jid) { int nlen, dlen, rlen, ulen; if((!jid->dirty) && (jid->_full)) return; /* Not dirty & already expanded */ if(*jid->domain == '\0') { /* empty */ jid->_full = (char*) realloc(jid->_full, 1); jid->_full[0] = 0; return; } nlen = strlen(jid->node); dlen = strlen(jid->domain); rlen = strlen(jid->resource); if(nlen == 0) { ulen = dlen+1; jid->_user = (char*) realloc(jid->_user, ulen); strcpy(jid->_user, jid->domain); } else { ulen = nlen+1+dlen+1; jid->_user = (char*) realloc(jid->_user, ulen); snprintf(jid->_user, ulen, "%s@%s", jid->node, jid->domain); } if(rlen == 0) { jid->_full = (char*) realloc(jid->_full, ulen); strcpy(jid->_full, jid->_user); } else { jid->_full = (char*) realloc(jid->_full, ulen+1+rlen); snprintf(jid->_full, ulen+1+rlen, "%s/%s", jid->_user, jid->resource); } jid->dirty = 0; } /** expand and return the user */ const char *jid_user(jid_t jid) { jid_expand(jid); return jid->_user; } /** expand and return the full */ const char *jid_full(jid_t jid) { jid_expand(jid); return jid->_full; } /** compare the user portion of two jids */ int jid_compare_user(jid_t a, jid_t b) { jid_expand(a); jid_expand(b); return strcmp(a->_user, b->_user); } /** compare two full jids */ int jid_compare_full(jid_t a, jid_t b) { jid_expand(a); jid_expand(b); return strcmp(a->_full, b->_full); } /** duplicate a jid */ jid_t jid_dup(jid_t jid) { jid_t new; new = (jid_t) malloc(sizeof(struct jid_st)); memcpy(new, jid, sizeof(struct jid_st)); if(jid->jid_data != NULL) { if(jid->jid_data_len == 0) { /* when original jid had static buffer, allocate new dynamic buffer * of the same size as has the static buffer */ jid->jid_data_len = sizeof(jid_static_buf); } /* allocate & populate new dynamic buffer */ new->jid_data = malloc(new->jid_data_len); memcpy(new->jid_data, jid->jid_data, new->jid_data_len); /* relocate pointers */ if(jid->node[0] == '\0') new->node = ""; else new->node = new->jid_data + (jid->node - jid->jid_data); if(jid->domain[0] == '\0') new->domain = ""; else new->domain = new->jid_data + (jid->domain - jid->jid_data); if(jid->resource[0] == '\0') new->resource = ""; else new->resource = new->jid_data + (jid->resource - jid->jid_data); } if(jid->_user) new->_user = strdup(jid->_user); if(jid->_full) new->_full = strdup(jid->_full); return new; } /** util to search through jids */ int jid_search(jid_t list, jid_t jid) { jid_t cur; for(cur = list; cur != NULL; cur = cur->next) if(jid_compare_full(cur,jid) == 0) return 1; return 0; } /** remove a jid_t from a list, returning the new list */ jid_t jid_zap(jid_t list, jid_t jid) { jid_t cur, dead; if(jid == NULL || list == NULL) return NULL; /* check first */ if(jid_compare_full(jid,list) == 0) { cur = list->next; jid_free(list); return cur; } /* check through the list, stopping at the previous list entry to a matching one */ cur = list; while(cur != NULL) { if(cur->next == NULL) /* none match, so we're done */ return list; if(jid_compare_full(cur->next, jid) == 0) { /* match, kill it */ dead = cur->next; cur->next = cur->next->next; jid_free(dead); return list; } /* loop */ cur = cur->next; } /* shouldn't get here */ return list; } /** make a copy of jid, link into list (avoiding dups) */ jid_t jid_append(jid_t list, jid_t jid) { jid_t scan; if(list == NULL) return jid_dup(jid); scan = list; while(scan != NULL) { /* check for dups */ if(jid_compare_full(scan, jid) == 0) return list; /* tack it on to the end of the list */ if(scan->next == NULL) { scan->next = jid_dup(jid); return list; } scan = scan->next; } return list; } /** create random resource **/ void jid_random_part(jid_t jid, jid_part_t part) { char hashBuf[41]; char randomBuf[257]; int i,r; /* create random string */ for(i = 0; i < 256; i++) { r = (int) (36.0 * rand() / RAND_MAX); randomBuf[i] = (r >= 0 && r <= 0) ? (r + 48) : (r + 87); } randomBuf[256] = 0; /* hash it */ shahash_r(randomBuf, hashBuf); /* change jid */ switch(part) { case jid_NODE: jid_reset_components(jid, hashBuf, jid->domain, jid->resource); break; case jid_DOMAIN: /* unused */ jid_reset_components(jid, jid->node, hashBuf, jid->resource); break; case jid_RESOURCE: jid_reset_components(jid, jid->node, jid->domain, hashBuf); break; } /* prepare */ jid_prep(jid); } ����������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/jid.h�������������������������������������������������������������������0000664�0000000�0000000�00000010626�12614627753�0016500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/jid.h * @brief Jabber identifiers * @author Robert Norris * $Date: 2004/05/01 00:51:10 $ * $Revision: 1.1 $ * * JID manipulation. Validity is checked via stringprep, using * the "nodeprep", "nameprep" and "resourceprep" profiles (see xmpp-core * section 3). * * The application should fill out node, domain and resource directly, then * call jid_expand(), or set the dirty flag. */ #ifndef INCL_UTIL_JID_H #define INCL_UTIL_JID_H 1 /** these sizings come from xmpp-core */ #define MAXLEN_JID_COMP 1023 /* XMPP (RFC3920) 3.1 */ #define MAXLEN_JID 3071 /* nodename (1023) + '@' + domain (1023) + '/' + resource (1023) = 3071 */ typedef struct jid_st { /* basic components of the jid */ char *node; char *domain; char *resource; /* Points to jid broken with \0s into componets. node/domain/resource point * into this string (or to statically allocated empty string, if they are * empty) */ char *jid_data; /* Valid only when jid_data != NULL. When = 0, jid_data is statically * allocated. Otherwise it tells length of the allocated data. Used to * implement jid_dup() */ size_t jid_data_len; /* the "user" part of the jid (sans resource) */ char *_user; /* the complete jid */ char *_full; /* application should set to 1 if user/full need regenerating */ int dirty; /* for lists of jids */ struct jid_st *next; } *jid_t; typedef enum { jid_NODE = 1, jid_DOMAIN = 2, jid_RESOURCE = 3 } jid_part_t; /** JID static buffer **/ typedef char jid_static_buf[3*1025]; /** make a new jid, and call jid_reset() to populate it */ JABBERD2_API jid_t jid_new(const char *id, int len); /** Make jid to use static buffer (jid data won't be allocated dynamically, but * given buffer will be always used. */ JABBERD2_API void jid_static(jid_t jid, jid_static_buf *buf); /** clear and populate the jid with the given id. if id == NULL, just clears the jid to 0 */ JABBERD2_API jid_t jid_reset(jid_t jid, const char *id, int len); JABBERD2_API jid_t jid_reset_components(jid_t jid, const char *node, const char *domain, const char *resource); /** free the jid */ JABBERD2_API void jid_free(jid_t jid); /** do string preparation on a jid */ JABBERD2_API int jid_prep(jid_t jid); /** fill jid's resource with a random string **/ JABBERD2_API void jid_random_part(jid_t jid, jid_part_t part); /** expands user and full if the dirty flag is set */ JABBERD2_API void jid_expand(jid_t jid); /** return the user or full jid. these call jid_expand to make sure the user and * full jid are up to date */ JABBERD2_API const char *jid_user(jid_t jid); JABBERD2_API const char *jid_full(jid_t jid); /** compare two user or full jids. these call jid_expand, then strcmp. returns * 0 if they're the same, < 0 if a < b, > 0 if a > b */ JABBERD2_API int jid_compare_user(jid_t a, jid_t b); JABBERD2_API int jid_compare_full(jid_t a, jid_t b); /** duplicate a jid */ JABBERD2_API jid_t jid_dup(jid_t jid); /** list helpers */ /** see if a jid is present in a list */ JABBERD2_API int jid_search(jid_t list, jid_t jid); /** remove a jid from a list, and return the new list */ JABBERD2_API jid_t jid_zap(jid_t list, jid_t jid); /** insert of a copy of jid into list, avoiding dups */ JABBERD2_API jid_t jid_append(jid_t list, jid_t jid); #endif ����������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/jqueue.c����������������������������������������������������������������0000664�0000000�0000000�00000005504�12614627753�0017222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* priority jqueues */ #include "util.h" jqueue_t jqueue_new(void) { pool_t p; jqueue_t q; p = pool_new(); q = (jqueue_t) pmalloco(p, sizeof(struct _jqueue_st)); q->p = p; q->init_time = time(NULL); return q; } void jqueue_free(jqueue_t q) { assert((int) (q != NULL)); pool_free(q->p); } void jqueue_push(jqueue_t q, void *data, int priority) { _jqueue_node_t qn, scan; assert((int) (q != NULL)); q->size++; /* node from the cache, or make a new one */ qn = q->cache; if(qn != NULL) q->cache = qn->next; else qn = (_jqueue_node_t) pmalloc(q->p, sizeof(struct _jqueue_node_st)); qn->data = data; qn->priority = priority; qn->next = NULL; qn->prev = NULL; /* first one */ if(q->back == NULL && q->front == NULL) { q->back = qn; q->front = qn; return; } /* find the first node with priority <= to us */ for(scan = q->back; scan != NULL && scan->priority > priority; scan = scan->next); /* didn't find one, so we have top priority - push us on the front */ if(scan == NULL) { qn->prev = q->front; qn->prev->next = qn; q->front = qn; return; } /* push us in front of scan */ qn->next = scan; qn->prev = scan->prev; if(scan->prev != NULL) scan->prev->next = qn; else q->back = qn; scan->prev = qn; } void *jqueue_pull(jqueue_t q) { void *data; _jqueue_node_t qn; assert((int) (q != NULL)); if(q->front == NULL) return NULL; data = q->front->data; qn = q->front; if(qn->prev != NULL) qn->prev->next = NULL; q->front = qn->prev; /* node to cache for later reuse */ qn->next = q->cache; q->cache = qn; if(q->front == NULL) q->back = NULL; q->size--; return data; } int jqueue_size(jqueue_t q) { return q->size; } time_t jqueue_age(jqueue_t q) { return time(NULL) - q->init_time; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/jsignal.c���������������������������������������������������������������0000664�0000000�0000000�00000015755�12614627753�0017364�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * A compatible implementation of signal which relies of sigaction. * More or less taken from teh Stevens book. */ #include <signal.h> #include "util.h" #ifdef _WIN32 /* Those routines define Windows jabberd2 services */ #include <windows.h> #include <winsvc.h> #include <time.h> SERVICE_STATUS jabber_service_status; SERVICE_STATUS_HANDLE jabber_service_status_handle; LPCTSTR jabber_service_name = NULL; LPCTSTR jabber_service_display = NULL; LPCTSTR jabber_service_description = NULL; LPCTSTR jabber_service_depends = NULL; jmainhandler_t *jabber_service_wrapper = NULL; void WINAPI jabber_service_main(DWORD argc, LPTSTR *argv); void WINAPI jabber_service_ctrl_handler(DWORD Opcode); BOOL jabber_install_service(); BOOL jabber_delete_service(); jsighandler_t *jabber_term_handler = NULL; #endif /* _WIN32 */ jsighandler_t* jabber_signal(int signo, jsighandler_t *func) { #ifdef _WIN32 if(signo == SIGTERM) jabber_term_handler = func; return NULL; #else struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; #ifdef SA_RESTART if (signo != SIGALRM) act.sa_flags |= SA_RESTART; #endif if (sigaction(signo, &act, &oact) < 0) return (SIG_ERR); return (oact.sa_handler); #endif } #ifdef _WIN32 BOOL WINAPI jabber_ctrl_handler(DWORD dwCtrlType) { if(jabber_term_handler) jabber_term_handler(0); return TRUE; } int jabber_wrap_service(int argc, char** argv, jmainhandler_t *wrapper, LPCTSTR name, LPCTSTR display, LPCTSTR description, LPCTSTR depends) { jabber_service_wrapper = wrapper; jabber_service_name = name; jabber_service_display = display; jabber_service_description = description; jabber_service_depends = depends; if((argc == 2) && !strcmp(argv[1], "-I")) { // Jabber service installation requested if(jabber_install_service()) printf("Service %s installed sucessfully.\n", jabber_service_name); else printf("Error installing service %s.\n", jabber_service_name); return 0; } if((argc == 2) && !strcmp(argv[1], "-U")) { // Jabber service removal requested if(jabber_delete_service()) printf("Service %s uninstalled sucessfully.\n", jabber_service_name); else printf("Error uninstalling service %s.\n", jabber_service_name); return 0; } if((argc == 2) && !strcmp(argv[1], "-S")) { TCHAR szPathName[MAX_PATH]; LPTSTR slash = NULL; SERVICE_TABLE_ENTRY DispatchTable[] = {{(LPTSTR)jabber_service_name, jabber_service_main}, {NULL, NULL}}; GetModuleFileName(NULL, szPathName, sizeof(szPathName)); // Set working directory to the service path if(slash = strrchr(szPathName, '\\')) { *slash = 0; SetCurrentDirectory(szPathName); } // Run service dispatcher StartServiceCtrlDispatcher(DispatchTable); return 0; } // If we are not in the service, register console handle for shutdown SetConsoleCtrlHandler(jabber_ctrl_handler, TRUE); // Wrap original main function if(jabber_service_wrapper) return jabber_service_wrapper(argc, argv); return 0; } void WINAPI jabber_service_main(DWORD argc, LPTSTR *argv) { jabber_service_status.dwServiceType = SERVICE_WIN32; jabber_service_status.dwCurrentState = SERVICE_START_PENDING; jabber_service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; jabber_service_status.dwWin32ExitCode = 0; jabber_service_status.dwServiceSpecificExitCode = 0; jabber_service_status.dwCheckPoint = 0; jabber_service_status.dwWaitHint = 0; jabber_service_status_handle = RegisterServiceCtrlHandler(jabber_service_name, jabber_service_ctrl_handler); if (jabber_service_status_handle == (SERVICE_STATUS_HANDLE)0) return; jabber_service_status.dwCurrentState = SERVICE_RUNNING; jabber_service_status.dwCheckPoint = 0; jabber_service_status.dwWaitHint = 0; SetServiceStatus(jabber_service_status_handle, &jabber_service_status); if(jabber_service_wrapper) jabber_service_wrapper(argc, argv); jabber_service_status.dwWin32ExitCode = 0; jabber_service_status.dwCurrentState = SERVICE_STOPPED; jabber_service_status.dwCheckPoint = 0; jabber_service_status.dwWaitHint = 0; SetServiceStatus(jabber_service_status_handle, &jabber_service_status); return; } void WINAPI jabber_service_ctrl_handler(DWORD Opcode) { switch(Opcode) { case SERVICE_CONTROL_PAUSE: jabber_service_status.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: jabber_service_status.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: jabber_service_status.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(jabber_service_status_handle, &jabber_service_status); // Call int signal if(jabber_term_handler) jabber_term_handler(0); break; case SERVICE_CONTROL_INTERROGATE: break; } return; } BOOL jabber_install_service() { TCHAR szPathName[MAX_PATH]; TCHAR szCmd[MAX_PATH + 16]; HANDLE schSCManager, schService; SERVICE_DESCRIPTION sdServiceDescription = { jabber_service_description }; GetModuleFileName(NULL, szPathName, sizeof(szPathName)); sprintf(szCmd, "\"%s\" -S", szPathName); schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return FALSE; schService = CreateService(schSCManager, jabber_service_name, // service name (alias) jabber_service_display, // service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type szCmd, // service's binary NULL, // no load ordering group NULL, // no tag identifier jabber_service_depends, // dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) return FALSE; ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, (LPVOID)&sdServiceDescription); CloseServiceHandle(schService); return TRUE; } BOOL jabber_delete_service() { HANDLE schSCManager; SC_HANDLE hService; schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return FALSE; hService=OpenService(schSCManager, jabber_service_name, SERVICE_ALL_ACCESS); if (hService == NULL) return FALSE; if(DeleteService(hService)==0) return FALSE; if(CloseServiceHandle(hService)==0) return FALSE; else return TRUE; } #endif /* _WIN32 */ �������������������jabberd2-jabberd-2.3.4/util/log.c�������������������������������������������������������������������0000664�0000000�0000000�00000014447�12614627753�0016513�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" #define MAX_LOG_LINE (1024) #ifdef DEBUG static int debug_flag; static FILE *debug_log_target = 0; #endif static const char *_log_level[] = { "emergency", "alert", "critical", "error", "warning", "notice", "info", "debug" }; static log_facility_t _log_facilities[] = { { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { "log_user", LOG_USER }, { NULL, -1 } }; static int _log_facility(const char *facility) { log_facility_t *lp; if (facility == NULL) { return -1; } for (lp = _log_facilities; lp->facility; lp++) { if (!strcasecmp(lp->facility, facility)) { break; } } return lp->number; } log_t log_new(log_type_t type, const char *ident, const char *facility) { log_t log; int fnum = 0; log = (log_t) calloc(1, sizeof(struct log_st)); log->type = type; if(type == log_SYSLOG) { fnum = _log_facility(facility); if (fnum < 0) fnum = LOG_LOCAL7; openlog(ident, LOG_PID, fnum); return log; } else if(type == log_STDOUT) { log->file = stdout; return log; } log->file = fopen(ident, "a+"); if(log->file == NULL) { fprintf(stderr, "ERROR: couldn't open logfile: %s\n" " logging will go to stdout instead\n", strerror(errno)); log->type = log_STDOUT; log->file = stdout; } return log; } void log_write(log_t log, int level, const char *msgfmt, ...) { va_list ap; char *pos, message[MAX_LOG_LINE+1]; int sz, len; time_t t; if(log && log->type == log_SYSLOG) { va_start(ap, msgfmt); #ifdef HAVE_VSYSLOG vsyslog(level, msgfmt, ap); #else len = vsnprintf(message, MAX_LOG_LINE, msgfmt, ap); if (len > MAX_LOG_LINE) message[MAX_LOG_LINE] = '\0'; else message[len] = '\0'; syslog(level, "%s", message); #endif va_end(ap); #ifndef DEBUG return; #endif } /* timestamp */ t = time(NULL); pos = ctime(&t); sz = strlen(pos); /* chop off the \n */ pos[sz-1]=' '; /* insert the header */ len = snprintf(message, MAX_LOG_LINE, "%s[%s] ", pos, _log_level[level]); if (len > MAX_LOG_LINE) message[MAX_LOG_LINE] = '\0'; else message[len] = '\0'; /* find the end and attach the rest of the msg */ for (pos = message; *pos != '\0'; pos++); /*empty statement */ sz = pos - message; va_start(ap, msgfmt); vsnprintf(pos, MAX_LOG_LINE - sz, msgfmt, ap); va_end(ap); #ifndef DEBUG if(log && log->type != log_SYSLOG) { #endif if(log && log->file) { fprintf(log->file,"%s", message); fprintf(log->file, "\n"); fflush(log->file); } #ifndef DEBUG } #endif #ifdef DEBUG if (!debug_log_target) { debug_log_target = stderr; } /* If we are in debug mode we want everything copied to the stdout */ if ((log == 0) || (get_debug_flag() && log->type != log_STDOUT)) { fprintf(debug_log_target, "%s\n", message); fflush(debug_log_target); } #endif /*DEBUG*/ } void log_free(log_t log) { if(log->type == log_SYSLOG) closelog(); else if(log->type == log_FILE) fclose(log->file); free(log); } #ifdef DEBUG /** debug logging */ void debug_log(const char *file, int line, const char *msgfmt, ...) { va_list ap; char *pos, message[MAX_DEBUG]; int sz; time_t t; if (!debug_log_target) { debug_log_target = stderr; } /* timestamp */ t = time(NULL); pos = ctime(&t); sz = strlen(pos); /* chop off the \n */ pos[sz-1]=' '; /* insert the header */ snprintf(message, MAX_DEBUG, "%s%s:%d ", pos, file, line); /* find the end and attach the rest of the msg */ for (pos = message; *pos != '\0'; pos++); /*empty statement */ sz = pos - message; va_start(ap, msgfmt); vsnprintf(pos, MAX_DEBUG - sz, msgfmt, ap); va_end(ap); fprintf(debug_log_target,"%s", message); fprintf(debug_log_target, "\n"); fflush(debug_log_target); } int get_debug_flag(void) { return debug_flag; } void set_debug_flag(int v) { debug_flag = v; } void set_debug_log_from_config(config_t c) { return set_debug_file(config_get_one(c, "log.debug", 0)); } JABBERD2_API void set_debug_file(const char *filename) { // Close debug output file but not stderr if (debug_log_target != 0 && debug_log_target != stderr) { fprintf(debug_log_target, "Closing log\n"); fclose(debug_log_target); debug_log_target = stderr; } // Setup new log target if (filename) { log_debug(ZONE, "Openning debug log file %s", filename); debug_log_target = fopen(filename, "a+"); if (debug_log_target) { log_debug(ZONE, "Staring debug log"); } else { debug_log_target = stderr; log_debug(ZONE, "Failed to open debug output file %s. Fallback to stderr", filename); } } else { // set stderr debug_log_target = stderr; } } #else /* DEBUG */ void debug_log(const char *file, int line, const char *msgfmt, ...) { } void set_debug_flag(int v) { } void set_debug_log_from_config(config_t c) { } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/log.h�������������������������������������������������������������������0000664�0000000�0000000�00000004163�12614627753�0016512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/log.h * @brief logging functions * @author Robert Norris * $Revision: 1.1 $ * $Date: 2004/04/30 00:53:54 $ */ #ifndef INCL_UTIL_LOG_H #define INCL_UTIL_LOG_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif #ifdef HAVE_SYSLOG_H # include <syslog.h> #endif #include "pool.h" typedef enum { log_STDOUT, log_SYSLOG, log_FILE } log_type_t; /* opaque decl */ typedef struct _log_st *log_t; JABBERD2_API log_t log_new(pool_t p, log_type_t type, const char *ident, const char *facility); JABBERD2_API void log_write(log_t log, int level, const char *msgfmt, ...); /* debug logging */ #if defined(DEBUG) && 0 JABBERD2_API int log_debug_flag; void log_debug(char *file, int line, const char *subsys, const char *msgfmt, ...); # define log_debug_get_flag() log_debug_flag # define log_debug_set_flag(f) (log_debug_flag = f ? 1 : 0) # define log_debug(...) if(log_debug_flag) __log_debug(__FILE__,__LINE__,0,__VA_ARGS__) # define log_debug_subsys(...) if(log_debug_flag) __log_debug(__FILE__,__LINE__,__VA_ARGS__) #else # define log_debug_get_flag() (0) # define log_debug_set_flag(f) # define log_debug(...) # define log_debug_subsys(...) #endif #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/md5.c�������������������������������������������������������������������0000664�0000000�0000000�00000030370�12614627753�0016410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.5 2005/06/02 04:48:25 zion Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch <ghost@aladdin.com>. Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include <string.h> in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include <stdio.h> in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #ifndef HAVE_SSL /* only if we do not use OpenSSL provided implementation */ #include <string.h> #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } #endif /* HAVE_SSL */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/md5.h�������������������������������������������������������������������0000664�0000000�0000000�00000007737�12614627753�0016430�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.6 2005/06/02 04:48:25 zion Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch <ghost@aladdin.com>. Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke <purschke@bnl.gov>. 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED #include "util.h" /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ /* use OpenSSL functions when available */ #ifdef HAVE_SSL #include <openssl/md5.h> #define md5_state_t MD5_CTX #define md5_init(c) MD5_Init(c) #define md5_append(c, data, len) MD5_Update(c, data, len); #define md5_finish(c, md) MD5_Final(md, c) #else /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef uint8_t md5_byte_t; /* 8-bit byte */ typedef uint32_t md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ JABBERD2_API void md5_init(md5_state_t *pms); /* Append a string to the message. */ JABBERD2_API void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ JABBERD2_API void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ #endif /* HAVE_SSL */ ���������������������������������jabberd2-jabberd-2.3.4/util/misc.c������������������������������������������������������������������0000664�0000000�0000000�00000002474�12614627753�0016662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "misc.h" #include <stdio.h> #include <stdlib.h> #define BLOCKSIZE (1024) int misc_realloc(void **blocks, int len) { void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len - 1) / BLOCKSIZE) + 1) * BLOCKSIZE; /* keep trying till we get it */ if((nblocks = realloc(*blocks, nlen)) == NULL) { fprintf(stderr, "fatal: out of memory\n"); abort(); } *blocks = nblocks; return nlen; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/misc.h������������������������������������������������������������������0000664�0000000�0000000�00000003057�12614627753�0016665�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/misc.h * @brief Miscellaneous utilities * @author Robert Norris * $Revision: 1.1 $ * $Date: 2004/05/01 00:51:10 $ */ #ifndef INCL_UTIL_MISC_H #define INCL_UTIL_MISC_H 1 /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ JABBERD2_API int misc_realloc(void **blocks, int len); #define misc_alloc(blocks, size, len) if((size) > len) len = misc_realloc((void **) &(blocks), (size)) #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/nad.c�������������������������������������������������������������������0000664�0000000�0000000�00000130724�12614627753�0016471�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** * !!! Things to do (after 2.0) * * - make nad_find_scoped_namespace() take an element index, and only search * the scope on that element (currently, it searchs all elements from * end to start, which isn't really correct, though it works in most cases * * - new functions: * * insert one nad (or part thereof) into another nad * * clear a part of a nad (like xmlnode_hide) * * - audit use of depth array and parent (see j2 bug #792) */ #include "nad.h" #include "util.h" /* define NAD_DEBUG to get pointer tracking - great for weird bugs that you can't reproduce */ #ifdef NAD_DEBUG static xht _nad_alloc_tracked = NULL; static xht _nad_free_tracked = NULL; static void _nad_ptr_check(const char *func, nad_t nad) { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); if(xhash_get(_nad_alloc_tracked, loc) == NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad); abort(); } if(xhash_get(_nad_free_tracked, loc) != NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad); abort(); } fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad); } #else #define _nad_ptr_check(func,nad) #endif #define BLOCKSIZE 128 /** * Reallocate the given buffer to make it larger. * * @param oblocks A pointer to a buffer that will be made larger. * @param len The minimum size in bytes to make the buffer. The * actual size of the buffer will be rounded up to the * nearest block of 1024 bytes. * * @return The new size of the buffer in bytes. */ static int _nad_realloc(void **oblocks, int len) { int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ *oblocks = realloc(*oblocks, nlen); return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size)); /** internal: append some cdata and return the index to it */ static int _nad_cdata(nad_t nad, const char *cdata, int len) { NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen); memcpy(nad->cdata + nad->ccur, cdata, len); nad->ccur += len; return nad->ccur - len; } /** internal: create a new attr on any given elem */ static int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen) { int attr; /* make sure there's mem for us */ NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen); attr = nad->acur; nad->acur++; nad->attrs[attr].next = nad->elems[elem].attr; nad->elems[elem].attr = attr; nad->attrs[attr].lname = strlen(name); nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname); if(vallen > 0) nad->attrs[attr].lval = vallen; else nad->attrs[attr].lval = strlen(val); nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval); nad->attrs[attr].my_ns = ns; return attr; } nad_t nad_new(void) { nad_t nad; nad = calloc(1, sizeof(struct nad_st)); nad->scope = -1; #ifdef NAD_DEBUG { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1); } _nad_ptr_check(__func__, nad); #endif return nad; } nad_t nad_copy(nad_t nad) { nad_t copy; _nad_ptr_check(__func__, nad); if(nad == NULL) return NULL; copy = nad_new(); /* if it's not large enough, make bigger */ NAD_SAFE(copy->elems, nad->elen, copy->elen); NAD_SAFE(copy->attrs, nad->alen, copy->alen); NAD_SAFE(copy->nss, nad->nlen, copy->nlen); NAD_SAFE(copy->cdata, nad->clen, copy->clen); /* copy all data */ memcpy(copy->elems, nad->elems, nad->elen); memcpy(copy->attrs, nad->attrs, nad->alen); memcpy(copy->nss, nad->nss, nad->nlen); memcpy(copy->cdata, nad->cdata, nad->clen); /* sync data */ copy->ecur = nad->ecur; copy->acur = nad->acur; copy->ncur = nad->ncur; copy->ccur = nad->ccur; copy->scope = nad->scope; return copy; } void nad_free(nad_t nad) { if(nad == NULL) return; #ifdef NAD_DEBUG _nad_ptr_check(__func__, nad); { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_zap(_nad_alloc_tracked, loc); xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad); } #endif /* Free nad */ free(nad->elems); free(nad->attrs); free(nad->cdata); free(nad->nss); free(nad->depths); #ifndef NAD_DEBUG free(nad); #endif } /** locate the next elem at a given depth with an optional matching name */ int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth) { int my_ns; int lname = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur) return -1; /* set up args for searching */ depth = nad->elems[elem].depth + depth; if(name != NULL) lname = strlen(name); /* search */ for(elem++;elem < nad->ecur;elem++) { /* if we hit one with a depth less than ours, then we don't have the * same parent anymore, bail */ if(nad->elems[elem].depth < depth) return -1; if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) && (ns < 0 || ((my_ns = nad->elems[elem].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return elem; } return -1; } /** get a matching attr on this elem, both name and optional val */ int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val) { int attr, my_ns; int lname, lval = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; attr = nad->elems[elem].attr; lname = strlen(name); if(val != NULL) lval = strlen(val); while(attr >= 0) { /* hefty, match name and if a val, also match that */ if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 && (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) && (ns < 0 || ((my_ns = nad->attrs[attr].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return attr; attr = nad->attrs[attr].next; } return -1; } /** get a matching ns on this elem, both uri and optional prefix */ int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix) { int check, ns; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || uri == NULL) return -1; /* work backwards through our parents, looking for our namespace on each one. * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */ check = elem; while(check >= 0) { ns = nad->elems[check].ns; while(ns >= 0) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; ns = nad->nss[ns].next; } check = nad->elems[check].parent; } return -1; } /** find a namespace in scope */ int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); if(uri == NULL) return -1; for(ns = 0; ns < nad->ncur; ns++) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; } return -1; } /** find elem using XPath like query * name -- "name" for the child tag of that name * "name/name" for a sub child (recurses) * "?attrib" to match the first tag with that attrib defined * "?attrib=value" to match the first tag with that attrib and value * or any combination: "name/name/?attrib", etc */ int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name) { char *str, *slash, *qmark, *equals; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; /* if it's plain name just search children */ if(strstr(name, "/") == NULL && strstr(name,"?") == NULL) return nad_find_elem(nad, elem, ns, name, 1); str = strdup(name); slash = strstr(str, "/"); qmark = strstr(str, "?"); equals = strstr(str, "="); /* no / in element name part */ if(qmark != NULL && (slash == NULL || qmark < slash)) { /* of type ?attrib */ *qmark = '\0'; qmark++; if(equals != NULL) { *equals = '\0'; equals++; } for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if(strcmp(qmark, "xmlns") == 0) { if(nad_find_namespace(nad, elem, equals, NULL) >= 0) break; } else { if(nad_find_attr(nad, elem, ns, qmark, equals) >= 0) break; } } free(str); return elem; } /* there is a / in element name part - need to recurse */ *slash = '\0'; ++slash; for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if((elem = nad_find_elem_path(nad, elem, ns, slash)) >= 0) break; } free(str); return elem; } /** create, update, or zap any matching attr on this elem */ void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen) { int attr; _nad_ptr_check(__func__, nad); /* find one to replace first */ if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0) { /* only create new if there's a value to store */ if(val != NULL) _nad_attr(nad, elem, ns, name, val, vallen); return; } /* got matching, update value or zap */ if(val == NULL) { nad->attrs[attr].lval = nad->attrs[attr].lname = 0; }else{ if(vallen > 0) nad->attrs[attr].lval = vallen; else nad->attrs[attr].lval = strlen(val); nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval); } } /** shove in a new child elem after the given one */ int nad_insert_elem(nad_t nad, int parent, int ns, const char *name, const char *cdata) { int elem; if (parent >= nad->ecur) { if (nad->ecur > 0) parent = nad->ecur -1; else parent = 0; } elem = parent + 1; _nad_ptr_check(__func__, nad); NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); /* relocate all the rest of the elems (unless we're at the end already) */ if(nad->ecur != elem) memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st)); nad->ecur++; /* set up req'd parts of new elem */ nad->elems[elem].parent = parent; nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].my_ns = ns; /* add cdata if given */ if(cdata != NULL) { nad->elems[elem].lcdata = strlen(cdata); nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata); }else{ nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; } /* parent/child */ nad->elems[elem].depth = nad->elems[parent].depth + 1; return elem; } /** remove an element (and its subelements) */ void nad_drop_elem(nad_t nad, int elem) { int next, cur; _nad_ptr_check(__func__, nad); if(elem >= nad->ecur) return; /* find the next elem at this depth to move into the space */ next = elem + 1; while(next < nad->ecur && nad->elems[next].depth > nad->elems[elem].depth) next++; /* relocate */ if(next < nad->ecur) memmove(&nad->elems[elem], &nad->elems[next], (nad->ecur - next) * sizeof(struct nad_elem_st)); nad->ecur -= next - elem; /* relink parents */ for(cur = elem; cur < nad->ecur; cur++) if(nad->elems[cur].parent > next) nad->elems[cur].parent -= (next - elem); } /** wrap an element with another element */ void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name) { int cur; _nad_ptr_check(__func__, nad); if(elem >= nad->ecur) return; NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); /* relocate all the rest of the elems after us */ memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st)); nad->ecur++; /* relink parents on moved elements */ for(cur = elem + 1; cur < nad->ecur; cur++) if(nad->elems[cur].parent > elem + 1) nad->elems[cur].parent++; /* set up req'd parts of new elem */ nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; nad->elems[elem].my_ns = ns; /* raise the bar on all the children */ nad->elems[elem+1].depth++; for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++; /* hook up the parent */ nad->elems[elem].parent = nad->elems[elem + 1].parent; } /** insert part of a nad into another nad */ int nad_insert_nad(nad_t dest, int delem, nad_t src, int selem) { int nelem, first, i, j, ns, nattr, attr; char buri[256], *uri = buri, bprefix[256], *prefix = bprefix; _nad_ptr_check(__func__, dest); _nad_ptr_check(__func__, src); /* can't do anything if these aren't real elems */ if(src->ecur <= selem || dest->ecur <= delem) return -1; /* figure out how many elements to copy */ nelem = 1; while(selem + nelem < src->ecur && src->elems[selem + nelem].depth > src->elems[selem].depth) nelem++; /* make room */ NAD_SAFE(dest->elems, (dest->ecur + nelem) * sizeof(struct nad_elem_st), dest->elen); /* relocate all the elems after us */ memmove(&dest->elems[delem + nelem + 1], &dest->elems[delem + 1], (dest->ecur - delem - 1) * sizeof(struct nad_elem_st)); dest->ecur += nelem; /* relink parents on moved elements */ for(i = delem + nelem; i < dest->ecur; i++) if(dest->elems[i].parent > delem) dest->elems[i].parent += nelem; first = delem + 1; /* copy them in, one at a time */ for(i = 0; i < nelem; i++) { /* link the parent */ dest->elems[first + i].parent = delem + (src->elems[selem + i].parent - src->elems[selem].parent); /* depth */ dest->elems[first + i].depth = dest->elems[delem].depth + (src->elems[selem + i].depth - src->elems[selem].depth) + 1; /* name */ dest->elems[first + i].lname = src->elems[selem + i].lname; dest->elems[first + i].iname = _nad_cdata(dest, src->cdata + src->elems[selem + i].iname, src->elems[selem + i].lname); /* cdata */ dest->elems[first + i].lcdata = src->elems[selem + i].lcdata; dest->elems[first + i].icdata = _nad_cdata(dest, src->cdata + src->elems[selem + i].icdata, src->elems[selem + i].lcdata); dest->elems[first + i].ltail = src->elems[selem + i].ltail; dest->elems[first + i].itail = _nad_cdata(dest, src->cdata + src->elems[selem + i].itail, src->elems[selem + i].ltail); /* namespaces */ dest->elems[first + i].my_ns = dest->elems[first + i].ns = dest->scope = -1; /* first, the element namespace */ ns = src->elems[selem + i].my_ns; if(ns >= 0) { for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) { dest->elems[first + i].my_ns = j; break; } /* not found, gotta add it */ if(j == dest->ncur) { /* make room */ /* !!! this can go once we have _ex() functions */ if(NAD_NURI_L(src, ns) > 255) uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); if(NAD_NPREFIX_L(src, ns) > 255) prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns)); if(NAD_NPREFIX_L(src, ns) > 0) { sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns)); dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, prefix); } else dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, NULL); if(uri != buri) free(uri); if(prefix != bprefix) free(prefix); } } /* then, any declared namespaces */ for(ns = src->elems[selem + i].ns; ns >= 0; ns = src->nss[ns].next) { for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) break; /* not found, gotta add it */ if(j == dest->ncur) { /* make room */ /* !!! this can go once we have _ex() functions */ if(NAD_NURI_L(src, ns) > 255) uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); if(NAD_NPREFIX_L(src, ns) > 255) prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns)); if(NAD_NPREFIX_L(src, ns) > 0) { sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns)); nad_add_namespace(dest, uri, prefix); } else nad_add_namespace(dest, uri, NULL); if(uri != buri) free(uri); if(prefix != bprefix) free(prefix); } } /* scope any new namespaces onto this element */ dest->elems[first + i].ns = dest->scope; dest->scope = -1; /* attributes */ dest->elems[first + i].attr = -1; if(src->acur > 0) { nattr = 0; for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) nattr++; /* make room */ NAD_SAFE(dest->attrs, (dest->acur + nattr) * sizeof(struct nad_attr_st), dest->alen); /* kopy ker-azy! */ for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) { /* name */ dest->attrs[dest->acur].lname = src->attrs[attr].lname; dest->attrs[dest->acur].iname = _nad_cdata(dest, src->cdata + src->attrs[attr].iname, src->attrs[attr].lname); /* val */ dest->attrs[dest->acur].lval = src->attrs[attr].lval; dest->attrs[dest->acur].ival = _nad_cdata(dest, src->cdata + src->attrs[attr].ival, src->attrs[attr].lval); /* namespace */ dest->attrs[dest->acur].my_ns = -1; ns = src->attrs[attr].my_ns; if(ns >= 0) for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) { dest->attrs[dest->acur].my_ns = j; break; } /* link it up */ dest->attrs[dest->acur].next = dest->elems[first + i].attr; dest->elems[first + i].attr = dest->acur; dest->acur++; } } } return first; } /** create a new elem on the list */ int nad_append_elem(nad_t nad, int ns, const char *name, int depth) { int elem; _nad_ptr_check(__func__, nad); /* make sure there's mem for us */ NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); elem = nad->ecur; nad->ecur++; nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].depth = depth; nad->elems[elem].my_ns = ns; /* make sure there's mem in the depth array, then track us */ NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen); nad->depths[depth] = elem; /* our parent is the previous guy in the depth array */ if(depth <= 0) nad->elems[elem].parent = -1; else nad->elems[elem].parent = nad->depths[depth - 1]; return elem; } /** attach new attr to the last elem */ int nad_append_attr(nad_t nad, int ns, const char *name, const char *val) { _nad_ptr_check(__func__, nad); return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0); } /** append new cdata to the last elem */ void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth) { int elem = nad->ecur - 1; _nad_ptr_check(__func__, nad); /* make sure this cdata is the child of the last elem to append */ if(nad->elems[elem].depth == depth - 1) { if(nad->elems[elem].icdata == 0) nad->elems[elem].icdata = nad->ccur; _nad_cdata(nad,cdata,len); nad->elems[elem].lcdata += len; return; } /* otherwise, pin the cdata on the tail of the last element at this depth */ elem = nad->depths[depth]; if(nad->elems[elem].itail == 0) nad->elems[elem].itail = nad->ccur; _nad_cdata(nad,cdata,len); nad->elems[elem].ltail += len; } /** bring a new namespace into scope */ int nad_add_namespace(nad_t nad, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); /* only add it if its not already in scope */ ns = nad_find_scoped_namespace(nad, uri, NULL); if(ns >= 0) return ns; /* make sure there's mem for us */ NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen); ns = nad->ncur; nad->ncur++; nad->nss[ns].next = nad->scope; nad->scope = ns; nad->nss[ns].luri = strlen(uri); nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri); if(prefix != NULL) { nad->nss[ns].lprefix = strlen(prefix); nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix); } else { nad->nss[ns].lprefix = 0; nad->nss[ns].iprefix = -1; } return ns; } /** declare a namespace on an already-existing element */ int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); /* see if its already scoped on this element */ ns = nad_find_namespace(nad, elem, uri, NULL); if(ns >= 0) return ns; /* make some room */ NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen); ns = nad->ncur; nad->ncur++; nad->nss[ns].next = nad->elems[elem].ns; nad->elems[elem].ns = ns; nad->nss[ns].luri = strlen(uri); nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri); if(prefix != NULL) { nad->nss[ns].lprefix = strlen(prefix); nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix); } else { nad->nss[ns].lprefix = 0; nad->nss[ns].iprefix = -1; } return ns; } static void _nad_escape(nad_t nad, int data, int len, int flag) { char *c; int ic; if(len <= 0) return; /* first, if told, find and escape " */ while(flag >= 4 && (c = memchr(nad->cdata + data,'"',len)) != NULL) { /* get offset */ ic = c - nad->cdata; /* cute, eh? handle other data before this normally */ _nad_escape(nad, data, ic - data, 3); /* ensure enough space, and add our escaped &quot; */ NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen); memcpy(nad->cdata + nad->ccur, "&quot;", 6); nad->ccur += 6; /* just update and loop for more */ len -= (ic+1) - data; data = ic+1; } /* next, find and escape ' */ while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL) { ic = c - nad->cdata; _nad_escape(nad, data, ic - data, 2); /* ensure enough space, and add our escaped &apos; */ NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen); memcpy(nad->cdata + nad->ccur, "&apos;", 6); nad->ccur += 6; /* just update and loop for more */ len -= (ic+1) - data; data = ic+1; } /* next look for < */ while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL) { ic = c - nad->cdata; _nad_escape(nad, data, ic - data, 1); /* ensure enough space, and add our escaped &lt; */ NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen); memcpy(nad->cdata + nad->ccur, "&lt;", 4); nad->ccur += 4; /* just update and loop for more */ len -= (ic+1) - data; data = ic+1; } /* next look for > */ while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL) { ic = c - nad->cdata; _nad_escape(nad, data, ic - data, 0); /* ensure enough space, and add our escaped &gt; */ NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen); memcpy(nad->cdata + nad->ccur, "&gt;", 4); nad->ccur += 4; /* just update and loop for more */ len -= (ic+1) - data; data = ic+1; } /* if & is found, escape it */ while((c = memchr(nad->cdata + data,'&',len)) != NULL) { ic = c - nad->cdata; /* ensure enough space */ NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen); /* handle normal data */ memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data)); nad->ccur += (ic - data); /* append escaped &amp; */ memcpy(nad->cdata + nad->ccur, "&amp;", 5); nad->ccur += 5; /* just update and loop for more */ len -= (ic+1) - data; data = ic+1; } /* nothing exciting, just append normal cdata */ if(len > 0) { NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen); memcpy(nad->cdata + nad->ccur, nad->cdata + data, len); nad->ccur += len; } } /** internal recursive printing function */ static int _nad_lp0(nad_t nad, int elem) { int attr; int ndepth; int ns; int elem_ns; /* there's a lot of code in here, but don't let that scare you, it's just duplication in order to be a bit more efficient cpu-wise */ /* this whole thing is in a big loop for processing siblings */ while(elem != nad->ecur) { /* make enough space for the opening element */ ns = nad->elems[elem].my_ns; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen); } /* opening tag */ *(nad->cdata + nad->ccur++) = '<'; /* add the prefix if necessary */ if(ns >= 0 && nad->nss[ns].iprefix >= 0) { memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; *(nad->cdata + nad->ccur++) = ':'; } /* copy in the name */ memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname); nad->ccur += nad->elems[elem].lname; /* add element prefix namespace */ ns = nad->elems[elem].my_ns; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { /* make space */ if(nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen); } /* start */ memcpy(nad->cdata + nad->ccur, " xmlns", 6); nad->ccur += 6; /* prefix if necessary */ if(nad->nss[ns].iprefix >= 0) { *(nad->cdata + nad->ccur++) = ':'; memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; } *(nad->cdata + nad->ccur++) = '='; *(nad->cdata + nad->ccur++) = '\''; /* uri */ memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri); nad->ccur += nad->nss[ns].luri; *(nad->cdata + nad->ccur++) = '\''; elem_ns = ns; }else{ elem_ns = -1; } /* add the namespaces */ for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next) { /* never explicitly declare the implicit xml namespace */ if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0) continue; /* do not redeclare element namespace */ if(ns == elem_ns) continue; /* make space */ if(nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen); } /* start */ memcpy(nad->cdata + nad->ccur, " xmlns", 6); nad->ccur += 6; /* prefix if necessary */ if(nad->nss[ns].iprefix >= 0) { *(nad->cdata + nad->ccur++) = ':'; memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; } *(nad->cdata + nad->ccur++) = '='; *(nad->cdata + nad->ccur++) = '\''; /* uri */ memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri); nad->ccur += nad->nss[ns].luri; *(nad->cdata + nad->ccur++) = '\''; } for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next) { if(nad->attrs[attr].lname <= 0) continue; /* make enough space for the wrapper part */ ns = nad->attrs[attr].my_ns; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen); } *(nad->cdata + nad->ccur++) = ' '; /* add the prefix if necessary */ if(ns >= 0 && nad->nss[ns].iprefix >= 0) { memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; *(nad->cdata + nad->ccur++) = ':'; } /* copy in the name parts */ memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname); nad->ccur += nad->attrs[attr].lname; *(nad->cdata + nad->ccur++) = '='; *(nad->cdata + nad->ccur++) = '\''; /* copy in the escaped value */ _nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 4); /* make enough space for the closing quote and add it */ NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen); *(nad->cdata + nad->ccur++) = '\''; } /* figure out what's next */ if(elem+1 == nad->ecur) ndepth = -1; else ndepth = nad->elems[elem+1].depth; /* handle based on if there are children, update nelem after done */ if(ndepth <= nad->elems[elem].depth) { /* make sure there's enough for what we could need */ NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen); if(nad->elems[elem].lcdata == 0) { memcpy(nad->cdata + nad->ccur, "/>", 2); nad->ccur += 2; }else{ *(nad->cdata + nad->ccur++) = '>'; /* copy in escaped cdata */ _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,4); /* make room */ ns = nad->elems[elem].my_ns; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen); } /* close tag */ memcpy(nad->cdata + nad->ccur, "</", 2); nad->ccur += 2; /* add the prefix if necessary */ if(ns >= 0 && nad->nss[ns].iprefix >= 0) { memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; *(nad->cdata + nad->ccur++) = ':'; } memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname); nad->ccur += nad->elems[elem].lname; *(nad->cdata + nad->ccur++) = '>'; } /* always try to append the tail */ _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4); /* if no siblings either, bail */ if(ndepth < nad->elems[elem].depth) return elem+1; /* next sibling */ elem++; }else{ int nelem; /* process any children */ /* close ourself and append any cdata first */ NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen); *(nad->cdata + nad->ccur++) = '>'; _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata, 4); /* process children */ nelem = _nad_lp0(nad, elem+1); /* close and tail up */ ns = nad->elems[elem].my_ns; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen); } else { NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen); } memcpy(nad->cdata + nad->ccur, "</", 2); nad->ccur += 2; if(ns >= 0 && nad->nss[ns].iprefix >= 0) { memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix); nad->ccur += nad->nss[ns].lprefix; *(nad->cdata + nad->ccur++) = ':'; } memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname); nad->ccur += nad->elems[elem].lname; *(nad->cdata + nad->ccur++) = '>'; _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4); /* if the next element is not our sibling, we're done */ if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth) return nelem; /* for next sibling in while loop */ elem = nelem; } /* here's the end of that big while loop */ } return elem; } void nad_print(nad_t nad, int elem, const char **xml, int *len) { int ixml = nad->ccur; _nad_ptr_check(__func__, nad); _nad_lp0(nad, elem); *len = nad->ccur - ixml; *xml = nad->cdata + ixml; } /** * nads serialize to a buffer of this form: * * [buflen][ecur][acur][ncur][ccur][elems][attrs][nss][cdata] * * nothing is done with endianness or word length, so the nad must be * serialized and deserialized on the same platform * * buflen is not actually used by deserialize(), but is provided as a * convenience to the application so it knows how many bytes to read before * passing them in to deserialize() * * the depths array is not stored, so after deserialization * nad_append_elem() and nad_append_cdata() will not work. this is rarely * a problem */ void nad_serialize(nad_t nad, char **buf, int *len) { char *pos; _nad_ptr_check(__func__, nad); *len = sizeof(int) * 5 + /* 4 ints in nad_t, plus one for len */ sizeof(struct nad_elem_st) * nad->ecur + sizeof(struct nad_attr_st) * nad->acur + sizeof(struct nad_ns_st) * nad->ncur + sizeof(char) * nad->ccur; *buf = (char *) malloc(*len); pos = *buf; * (int *) pos = *len; pos += sizeof(int); * (int *) pos = nad->ecur; pos += sizeof(int); * (int *) pos = nad->acur; pos += sizeof(int); * (int *) pos = nad->ncur; pos += sizeof(int); * (int *) pos = nad->ccur; pos += sizeof(int); memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur; memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur; memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur; memcpy(pos, nad->cdata, sizeof(char) * nad->ccur); } nad_t nad_deserialize(const char *buf) { nad_t nad = nad_new(); const char *pos = buf + sizeof(int); /* skip len */ _nad_ptr_check(__func__, nad); nad->ecur = * (int *) pos; pos += sizeof(int); nad->acur = * (int *) pos; pos += sizeof(int); nad->ncur = * (int *) pos; pos += sizeof(int); nad->ccur = * (int *) pos; pos += sizeof(int); nad->elen = nad->ecur; nad->alen = nad->acur; nad->nlen = nad->ncur; nad->clen = nad->ccur; if(nad->ecur > 0) { nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur); memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur; } if(nad->acur > 0) { nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur); memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur; } if(nad->ncur > 0) { nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur); memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur; } if(nad->ccur > 0) { nad->cdata = (char *) malloc(sizeof(char) * nad->ccur); memcpy(nad->cdata, pos, sizeof(char) * nad->ccur); } return nad; } /** parse a buffer into a nad */ struct build_data { nad_t nad; int depth; XML_Parser p; }; static void _nad_parse_element_start(void *arg, const char *name, const char **atts) { struct build_data *bd = (struct build_data *) arg; char buf[1024]; char *uri, *elem, *prefix; const char **attr; int el, ns; /* make a copy */ strncpy(buf, name, 1024); buf[1023] = '\0'; /* expat gives us: prefixed namespaced elem: uri|elem|prefix default namespaced elem: uri|elem un-namespaced elem: elem */ /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_add_namespace(bd->nad, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ el = nad_append_elem(bd->nad, ns, elem, bd->depth); /* now the attributes, one at a time */ attr = atts; while(attr[0] != NULL) { /* make a copy */ strncpy(buf, attr[0], 1024); buf[1023] = '\0'; /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_append_namespace(bd->nad, el, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ nad_append_attr(bd->nad, ns, elem, (char *) attr[1]); attr += 2; } bd->depth++; } static void _nad_parse_element_end(void *arg, const char *name) { struct build_data *bd = (struct build_data *) arg; bd->depth--; } static void _nad_parse_cdata(void *arg, const char *str, int len) { struct build_data *bd = (struct build_data *) arg; /* go */ nad_append_cdata(bd->nad, (char *) str, len, bd->depth); } static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri) { struct build_data *bd = (struct build_data *) arg; int ns; ns = nad_add_namespace(bd->nad, (char *) uri, (char *) prefix); /* Always set the namespace (to catch cases where nad_add_namespace doesn't add it) */ bd->nad->scope = ns; } #ifdef HAVE_XML_STOPPARSER /* Stop the parser if an entity declaration is hit. */ static void _nad_parse_entity_declaration(void *arg, const char *entityName, int is_parameter_entity, const char *value, int value_length, const char *base, const char *systemId, const char *publicId, const char *notationName) { struct build_data *bd = (struct build_data *) arg; XML_StopParser(bd->p, XML_FALSE); } #endif nad_t nad_parse(const char *buf, int len) { struct build_data bd; XML_Parser p; if(len == 0) len = strlen(buf); p = XML_ParserCreateNS(NULL, '|'); if(p == NULL) return NULL; bd.p = p; XML_SetReturnNSTriplet(p, 1); /* Prevent the "billion laughs" attack against expat by disabling * internal entity expansion. With 2.x, forcibly stop the parser * if an entity is declared - this is safer and a more obvious * failure mode. With older versions, simply prevent expenansion * of such entities. */ #ifdef HAVE_XML_STOPPARSER XML_SetEntityDeclHandler(p, (void *) _nad_parse_entity_declaration); #else XML_SetDefaultHandler(p, NULL); #endif bd.nad = nad_new(); bd.depth = 0; XML_SetUserData(p, (void *) &bd); XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end); XML_SetCharacterDataHandler(p, _nad_parse_cdata); XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start); if(!XML_Parse(p, buf, len, 1)) { XML_ParserFree(p); nad_free(bd.nad); return NULL; } XML_ParserFree(p); if(bd.depth != 0) return NULL; return bd.nad; } ��������������������������������������������jabberd2-jabberd-2.3.4/util/nad.h�������������������������������������������������������������������0000664�0000000�0000000�00000016410�12614627753�0016471�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/nad.h * @brief Not A DOM * @author Jeremie Miller * @author Robert Norris * $Date: 2004/05/05 23:49:38 $ * $Revision: 1.3 $ * * NAD is very simplistic, and requires all string handling to use a length. * Apps using this must be aware of the structure and access it directly for * most information. NADs can only be built by successively using the _append_ * functions correctly. After built, they can be modified using other * functions, or by direct access. To access cdata on an elem or attr, use * nad->cdata + nad->xxx[index].ixxx for the start, and .lxxx for len. * * Namespace support seems to work, but hasn't been thoroughly tested. in * particular, editing the NAD after its creation might have quirks. use at * your own risk! Note that nad_add_namespace() brings a namespace into scope * for the next element added with nad_append_elem(), nad_insert_elem() or * nad_wrap_elem() (and by extension, any of its subelements). This is the * same way that Expat does things, so nad_add_namespace() can be driven from * Expat's StartNamespaceDeclHandler. See nad_parse() for an example of how to * use Expat to drive NAD. */ #ifndef INCL_UTIL_NAD_H #define INCL_UTIL_NAD_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ struct nad_elem_st { int parent; int iname, lname; int icdata, lcdata; /* cdata within this elem (up to first child) */ int itail, ltail; /* cdata after this elem */ int attr; int ns; int my_ns; int depth; }; struct nad_attr_st { int iname, lname; int ival, lval; int my_ns; int next; }; struct nad_ns_st { int iuri, luri; int iprefix, lprefix; int next; }; typedef struct nad_st { struct nad_elem_st *elems; struct nad_attr_st *attrs; struct nad_ns_st *nss; char *cdata; int *depths; /* for tracking the last elem at a depth */ /* The size in bytes of the elems, attrs, nss and cdata buffers, respectively. */ int elen, alen, nlen, clen, dlen; /* The number of elements of each type of that data that are actually stored in the elems, attrs, nss and cdata buffers, respectively. */ int ecur, acur, ncur, ccur; int scope; /* currently scoped namespaces, get attached to the next element */ struct nad_st *next; /* for keeping a list of nads */ } *nad_t; /** create a new nad */ JABBERD2_API nad_t nad_new(void); /** copy a nad */ JABBERD2_API nad_t nad_copy(nad_t nad); /** free that nad */ JABBERD2_API void nad_free(nad_t nad); /** find the next element with this name/depth */ /** 0 for siblings, 1 for children and so on */ JABBERD2_API int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth); /** find the first matching attribute (and optionally value) */ JABBERD2_API int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val); /** find the first matching namespace (and optionally prefix) */ JABBERD2_API int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix); /** find a namespace in scope (and optionally prefix) */ JABBERD2_API int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix); /** find elem using XPath like query * name -- "name" for the child tag of that name * "name/name" for a sub child (recurses) * "?attrib" to match the first tag with that attrib defined * "?attrib=value" to match the first tag with that attrib and value * or any combination: "name/name/?attrib", etc */ JABBERD2_API int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name); /** reset or store the given attribute */ JABBERD2_API void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen); /** insert and return a new element as a child of this one */ JABBERD2_API int nad_insert_elem(nad_t nad, int elem, int ns, const char *name, const char *cdata); /** remove an element (and its subelements) */ JABBERD2_API void nad_drop_elem(nad_t nad, int elem); /** wrap an element with another element */ JABBERD2_API void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name); /** insert part of a nad into another nad */ JABBERD2_API int nad_insert_nad(nad_t dest, int delem, nad_t src, int selem); /** append and return a new element */ JABBERD2_API int nad_append_elem(nad_t nad, int ns, const char *name, int depth); /** append attribs to the last element */ JABBERD2_API int nad_append_attr(nad_t nad, int ns, const char *name, const char *val); /** append more cdata to the last element */ JABBERD2_API void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth); /** add a namespace to the next element (ie, called when the namespace comes into scope) */ JABBERD2_API int nad_add_namespace(nad_t nad, const char *uri, const char *prefix); /** declare a namespace on an already existing element */ JABBERD2_API int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix); /** create a string representation of the given element (and children), point references to it */ JABBERD2_API void nad_print(nad_t nad, int elem, const char **xml, int *len); /** serialize and deserialize a nad */ JABBERD2_API void nad_serialize(nad_t nad, char **buf, int *len); JABBERD2_API nad_t nad_deserialize(const char *buf); /** create a nad from raw xml */ JABBERD2_API nad_t nad_parse(const char *buf, int len); /* these are some helpful macros */ #define NAD_ENAME(N,E) (N->cdata + N->elems[E].iname) #define NAD_ENAME_L(N,E) (N->elems[E].lname) #define NAD_CDATA(N,E) (N->cdata + N->elems[E].icdata) #define NAD_CDATA_L(N,E) (N->elems[E].lcdata) #define NAD_ANAME(N,A) (N->cdata + N->attrs[A].iname) #define NAD_ANAME_L(N,A) (N->attrs[A].lname) #define NAD_AVAL(N,A) (N->cdata + N->attrs[A].ival) #define NAD_AVAL_L(N,A) (N->attrs[A].lval) #define NAD_NURI(N,NS) (N->cdata + N->nss[NS].iuri) #define NAD_NURI_L(N,NS) (N->nss[NS].luri) #define NAD_NPREFIX(N,NS) (N->cdata + N->nss[NS].iprefix) #define NAD_NPREFIX_L(N,NS) (N->nss[NS].lprefix) #define NAD_ENS(N,E) (N->elems[E].my_ns) #define NAD_ANS(N,A) (N->attrs[A].my_ns) #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/pool.c������������������������������������������������������������������0000664�0000000�0000000�00000015305�12614627753�0016675�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" #include "pool.h" #ifdef POOL_DEBUG int pool__total = 0; int pool__ltotal = 0; xht pool__disturbed = NULL; void *_pool__malloc(size_t size) { pool__total++; return malloc(size); } void _pool__free(void *block) { pool__total--; free(block); } #else #define _pool__malloc malloc #define _pool__free free #endif /** make an empty pool */ pool_t _pool_new(const char *zone, int line) { pool_t p; while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1); p->cleanup = NULL; p->heap = NULL; p->size = 0; #ifdef POOL_DEBUG p->lsize = -1; p->zone[0] = '\0'; snprintf(p->zone, sizeof(p->zone), "%s:%i", zone, line); sprintf(p->name,"%X",(int)p); if(pool__disturbed == NULL) { pool__disturbed = (xht)1; /* reentrancy flag! */ pool__disturbed = xhash_new(POOL_NUM); } if(pool__disturbed != (xht)1) xhash_put(pool__disturbed,p->name,p); #endif return p; } /** free a heap */ static void _pool_heap_free(void *arg) { struct pheap *h = (struct pheap *)arg; _pool__free(h->block); _pool__free(h); } /** mem should always be freed last */ static void _pool_cleanup_append(pool_t p, struct pfree *pf) { struct pfree *cur; if(p->cleanup == NULL) { p->cleanup = pf; p->cleanup_tail = pf; return; } /* append at end of list */ cur = p->cleanup_tail; cur->next = pf; p->cleanup_tail = pf; } /** create a cleanup tracker */ static struct pfree *_pool_free(pool_t p, pool_cleanup_t f, void *arg) { struct pfree *ret; /* make the storage for the tracker */ while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1); ret->f = f; ret->arg = arg; ret->next = NULL; return ret; } /** create a heap and make sure it get's cleaned up */ static struct pheap *_pool_heap(pool_t p, int size) { struct pheap *ret; struct pfree *clean; /* make the return heap */ while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1); while((ret->block = _pool__malloc(size)) == NULL) sleep(1); ret->size = size; p->size += size; ret->used = 0; /* append to the cleanup list */ clean = _pool_free(p, _pool_heap_free, (void *)ret); clean->heap = ret; /* for future use in finding used mem for pstrdup */ _pool_cleanup_append(p, clean); return ret; } pool_t _pool_new_heap(int size, const char *zone, int line) { pool_t p; p = _pool_new(zone, line); p->heap = _pool_heap(p,size); return p; } void *pmalloc(pool_t p, int size) { void *block; if(p == NULL) { fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n"); abort(); } /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */ if(p->heap == NULL || size > (p->heap->size / 2)) { while((block = _pool__malloc(size)) == NULL) sleep(1); p->size += size; _pool_cleanup_append(p, _pool_free(p, _pool__free, block)); return block; } /* we have to preserve boundaries, long story :) */ if(size >= 4) while(p->heap->used&7) p->heap->used++; /* if we don't fit in the old heap, replace it */ if(size > (p->heap->size - p->heap->used)) p->heap = _pool_heap(p, p->heap->size); /* the current heap has room */ block = (char *)p->heap->block + p->heap->used; p->heap->used += size; return block; } void *pmalloc_x(pool_t p, int size, char c) { void* result = pmalloc(p, size); if (result != NULL) memset(result, c, size); return result; } /** easy safety utility (for creating blank mem for structs, etc) */ void *pmalloco(pool_t p, int size) { void *block = pmalloc(p, size); memset(block, 0, size); return block; } /** XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */ char *pstrdup(pool_t p, const char *src) { char *ret; if(src == NULL) return NULL; ret = pmalloc(p,strlen(src) + 1); strcpy(ret,src); return ret; } /** use given size */ char *pstrdupx(pool_t p, const char *src, int len) { char *ret; if(src == NULL || len <= 0) return NULL; ret = pmalloc(p,len + 1); memcpy(ret,src,len); ret[len] = '\0'; return ret; } int pool_size(pool_t p) { if(p == NULL) return 0; return p->size; } void pool_free(pool_t p) { struct pfree *cur, *stub; if(p == NULL) return; cur = p->cleanup; while(cur != NULL) { (*cur->f)(cur->arg); stub = cur->next; _pool__free(cur); cur = stub; } #ifdef POOL_DEBUG if (pool__disturbed != NULL && pool__disturbed != (xht)1) xhash_zap(pool__disturbed,p->name); #endif _pool__free(p); } /** public cleanup utils, insert in a way that they are run FIFO, before mem frees */ void pool_cleanup(pool_t p, pool_cleanup_t f, void *arg) { struct pfree *clean; clean = _pool_free(p, f, arg); clean->next = p->cleanup; p->cleanup = clean; } #ifdef POOL_DEBUG void _pool_stat(const char *key, int keylen, void *val, void *arg) { pool_t p = (pool_t)val; if(p->lsize == -1) fprintf(stderr, "POOL: %s: %s is a new pool\n",p->zone,p->name); else if(p->size > p->lsize) fprintf(stderr, "POOL: %s: %s grew %d\n",p->zone,p->name, p->size - p->lsize); else if((int)arg) fprintf(stderr, "POOL: %s: %s exists %d\n",p->zone,p->name, p->size); p->lsize = p->size; } void pool_stat(int full) { if (pool__disturbed == NULL || pool__disturbed == (xht)1) return; xhash_walk(pool__disturbed,_pool_stat,(void *)full); if(pool__total != pool__ltotal) fprintf(stderr, "POOL: %d total missed mallocs\n",pool__total); pool__ltotal = pool__total; return; } #else void pool_stat(int full) { return; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/pool.h������������������������������������������������������������������0000664�0000000�0000000�00000007067�12614627753�0016710�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Pool-based memory management routines. * * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifndef INCL_UTIL_POOL_H #define INCL_UTIL_POOL_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifdef POOL_DEBUG /* prime number for top # of pools debugging */ #define POOL_NUM 40009 #endif /** * pool_cleanup_t - callback type which is associated * with a pool entry; invoked when the pool entry is * free'd **/ typedef void (*pool_cleanup_t)(void *arg); /** * pheap - singular allocation of memory **/ struct pheap { void *block; int size, used; }; /** * pfree - a linked list node which stores an * allocation chunk, plus a callback **/ struct pfree { pool_cleanup_t f; void *arg; struct pheap *heap; struct pfree *next; }; /** * pool - base node for a pool. Maintains a linked list * of pool entries (pfree) **/ typedef struct pool_struct { int size; struct pfree *cleanup; struct pfree *cleanup_tail; struct pheap *heap; #ifdef POOL_DEBUG char name[8], zone[32]; int lsize; #endif } _pool, *pool_t; #ifdef POOL_DEBUG # define pool_new() _pool_new(__FILE__,__LINE__) # define pool_heap(i) _pool_new_heap(i,__FILE__,__LINE__) #else # define pool_heap(i) _pool_new_heap(i,NULL,0) # define pool_new() _pool_new(NULL,0) #endif JABBERD2_API pool_t _pool_new(const char *file, int line); /* new pool :) */ JABBERD2_API pool_t _pool_new_heap(int size, const char *file, int line); /* creates a new memory pool with an initial heap size */ JABBERD2_API void *pmalloc(pool_t, int size); /* wrapper around malloc, takes from the pool, cleaned up automatically */ JABBERD2_API void *pmalloc_x(pool_t p, int size, char c); /* Wrapper around pmalloc which prefils buffer with c */ JABBERD2_API void *pmalloco(pool_t p, int size); /* YAPW for zeroing the block */ JABBERD2_API char *pstrdup(pool_t p, const char *src); /* wrapper around strdup, gains mem from pool */ JABBERD2_API char *pstrdupx(pool_t p, const char *src, int len); /* use given len */ JABBERD2_API void pool_stat(int full); /* print to stderr the changed pools and reset */ JABBERD2_API void pool_cleanup(pool_t p, pool_cleanup_t fn, void *arg); /* calls f(arg) before the pool is freed during cleanup */ JABBERD2_API void pool_free(pool_t p); /* calls the cleanup functions, frees all the data on the pool, and deletes the pool itself */ JABBERD2_API int pool_size(pool_t p); /* returns total bytes allocated in this pool */ #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/pqueue.c����������������������������������������������������������������0000664�0000000�0000000�00000006010�12614627753�0017221�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* priority queues */ #include "pqueue.h" #include "pool.h" #include <stdio.h> /* to get NULL */ #include <assert.h> typedef struct _pqueue_node_st *_pqueue_node_t; struct _pqueue_node_st { void *data; int priority; _pqueue_node_t next; _pqueue_node_t prev; }; struct _pqueue_st { pool_t p; _pqueue_node_t cache; _pqueue_node_t front; _pqueue_node_t back; int size; }; pqueue_t pqueue_new(pool_t p) { pqueue_t q; q = (pqueue_t) pmalloco(p, sizeof(struct _pqueue_st)); q->p = p; return q; } void pqueue_push(pqueue_t q, void *data, int priority) { _pqueue_node_t qn, scan; assert((q != NULL)); q->size++; /* node from the cache, or make a new one */ qn = q->cache; if(qn != NULL) q->cache = qn->next; else qn = (_pqueue_node_t) pmalloc(q->p, sizeof(struct _pqueue_node_st)); qn->data = data; qn->priority = priority; qn->next = NULL; qn->prev = NULL; /* first one */ if(q->back == NULL && q->front == NULL) { q->back = qn; q->front = qn; return; } /* find the first node with priority <= to us */ for(scan = q->back; scan != NULL && scan->priority > priority; scan = scan->next); /* didn't find one, so we have top priority - push us on the front */ if(scan == NULL) { qn->prev = q->front; qn->prev->next = qn; q->front = qn; return; } /* push us in front of scan */ qn->next = scan; qn->prev = scan->prev; if(scan->prev != NULL) scan->prev->next = qn; else q->back = qn; scan->prev = qn; } void *pqueue_pull(pqueue_t q) { void *data; _pqueue_node_t qn; assert((q != NULL)); if(q->front == NULL) return NULL; data = q->front->data; qn = q->front; if(qn->prev != NULL) qn->prev->next = NULL; q->front = qn->prev; /* node to cache for later reuse */ qn->next = q->cache; q->cache = qn; if(q->front == NULL) q->back = NULL; q->size--; return data; } int pqueue_size(pqueue_t q) { return q->size; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/pqueue.h����������������������������������������������������������������0000664�0000000�0000000�00000002533�12614627753�0017234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/pqueue.h * @brief priority queues * @author Robert Norris * $Date: 2004/05/05 23:49:38 $ * $Revision: 1.1 $ */ #ifndef INCL_UTIL_PQUEUE_H #define INCL_UTIL_PQUEUE_H 1 #include "pool.h" /* opaque decl */ typedef struct _pqueue_st *pqueue_t; JABBERD2_API pqueue_t pqueue_new(pool_t p); JABBERD2_API void pqueue_push(pqueue_t q, void *data, int pri); JABBERD2_API void *pqueue_pull(pqueue_t q); JABBERD2_API int pqueue_size(pqueue_t q); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/rate.c������������������������������������������������������������������0000664�0000000�0000000�00000004372�12614627753�0016661�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* rate controls (for implementing connect-limiting or karma) */ #include "util.h" rate_t rate_new(int total, int seconds, int wait) { rate_t rt = (rate_t) calloc(1, sizeof(struct rate_st)); rt->total = total; rt->seconds = seconds; rt->wait = wait; return rt; } void rate_free(rate_t rt) { free(rt); } void rate_reset(rate_t rt) { rt->time = 0; rt->count = 0; rt->bad = 0; } void rate_add(rate_t rt, int count) { time_t now; now = time(NULL); /* rate expired */ if(now - rt->time >= rt->seconds) rate_reset(rt); rt->count += count; /* first event, so set the time */ if(rt->time == 0) rt->time = now; /* uhoh, they stuffed up */ if(rt->count >= rt->total) rt->bad = now; } int rate_left(rate_t rt) { /* if we're bad, then there's none left */ if(rt->bad != 0) return 0; return rt->total - rt->count; } int rate_check(rate_t rt) { /* not tracking */ if(rt->time == 0) return 1; /* under the limit */ if(rt->count < rt->total) return 1; /* currently bad */ if(rt->bad != 0) { /* wait over, they're good again */ if(time(NULL) - rt->bad >= rt->wait) { rate_reset(rt); return 1; } /* keep them waiting */ return 0; } /* they're inside the time, and not bad yet */ return 1; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/serial.c����������������������������������������������������������������0000664�0000000�0000000�00000007750�12614627753�0017210�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* these are useful utilities for data serialisation */ #include "util.h" /* * ser_string_get() and ser_int_get() retrieve a string (null-terminated) or * an int (sizeof(int) chars) from source, and store it in dest. source is a * pointer into buf, and will be updated before the call returns. * buf is a pointer to the start of the source buffer, and len is the length * of the buffer. if retrieving the data would take us pass the end of the * array, a non-zero value will be returned. if the call succeeds, 0 is * returned. */ int ser_string_get(char **dest, int *source, const char *buf, int len) { const char *end, *c; /* end of the buffer */ end = buf + ((sizeof(char) * (len - 1))); /* make sure we have a \0 before the end of the buffer */ c = &(buf[*source]); while(c <= end && *c != '\0') c++; if(c > end) /* we ran past the end, fail */ return 1; /* copy the string */ *dest = strdup(&(buf[*source])); /* and move the pointer */ *source += strlen(*dest) + 1; return 0; } int ser_int_get(int *dest, int *source, const char *buf, int len) { union { char c[sizeof(int)]; int i; } u; int i; /* we need sizeof(int) bytes */ if(&(buf[*source]) + sizeof(int) > buf + (sizeof(char) * len)) return 1; /* copy the bytes into the union. we do it this way to avoid alignment problems */ for(i = 0; i < sizeof(int); i++) { u.c[i] = buf[*source]; (*source)++; } *dest = u.i; return 0; } /* * ser_string_set() and ser_int_set() stores the string or int referenced by * source into buf, starting at dest. len holds the current length of the * buffer. if storing the data would overrun the end of the buffer, the buffer * will be grown to accomodate. buf, dest and len will be updated. */ /* shamelessy stolen from nad.c */ #define BLOCKSIZE 1024 /** internal: do and return the math and ensure it gets realloc'd */ static int _ser_realloc(void **oblocks, int len) { void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen; } /** this is the safety check used to make sure there's always enough mem */ #define SER_SAFE(blocks, size, len) if((size) > len) len = _ser_realloc((void**)&(blocks),(size)); void ser_string_set(const char *source, int *dest, char **buf, int *len) { int need = sizeof(char) * (strlen(source) + 1); /* make more space if necessary */ SER_SAFE(*buf, *dest + need, *len); /* copy it in */ strcpy(*buf + *dest, source); /* and shift the pointer */ *dest += need; } void ser_int_set(int source, int *dest, char **buf, int *len) { union { char c[sizeof(int)]; int i; } u; int i; /* make more space if necessary */ SER_SAFE(*buf, *dest + sizeof(int), *len) /* copy it in */ u.i = source; for(i = 0; i < sizeof(int); i++) (*buf)[*dest + i] = u.c[i]; /* and shift the pointer */ *dest += sizeof(int); } ������������������������jabberd2-jabberd-2.3.4/util/sha1.c������������������������������������������������������������������0000664�0000000�0000000�00000010043�12614627753�0016552�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is SHA 180-1 Reference Implementation (Compact version) * * The Initial Developer of the Original Code is Paul Kocher of * Cryptography Research. Portions created by Paul Kocher are * Copyright (C) 1995-9 by Cryptography Research, Inc. All * Rights Reserved. * */ /* modified for j2 by Robert Norris */ #include "sha1.h" #include <string.h> static void sha1_hashblock(sha1_state_t *ctx); void sha1_init(sha1_state_t *ctx) { int i; ctx->lenW = 0; ctx->sizeHi = ctx->sizeLo = 0; /* Initialize H with the magic constants (see FIPS180 for constants) */ ctx->H[0] = 0x67452301L; ctx->H[1] = 0xefcdab89L; ctx->H[2] = 0x98badcfeL; ctx->H[3] = 0x10325476L; ctx->H[4] = 0xc3d2e1f0L; for (i = 0; i < 80; i++) ctx->W[i] = 0; } void sha1_append(sha1_state_t *ctx, const unsigned char *dataIn, int len) { int i; /* Read the data into W and process blocks as they get full */ for (i = 0; i < len; i++) { ctx->W[ctx->lenW / 4] <<= 8; ctx->W[ctx->lenW / 4] |= (uint32_t)dataIn[i]; if ((++ctx->lenW) % 64 == 0) { sha1_hashblock(ctx); ctx->lenW = 0; } ctx->sizeLo += 8; ctx->sizeHi += (ctx->sizeLo < 8); } } void sha1_finish(sha1_state_t *ctx, unsigned char hashout[20]) { unsigned char pad0x80 = 0x80; unsigned char pad0x00 = 0x00; unsigned char padlen[8]; int i; /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length */ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); sha1_append(ctx, &pad0x80, 1); while (ctx->lenW != 56) sha1_append(ctx, &pad0x00, 1); sha1_append(ctx, padlen, 8); /* Output hash */ for (i = 0; i < 20; i++) { hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); ctx->H[i / 4] <<= 8; } /* * Re-initialize the context (also zeroizes contents) */ sha1_init(ctx); } void sha1_hash(const unsigned char *dataIn, int len, unsigned char hashout[20]) { sha1_state_t ctx; sha1_init(&ctx); sha1_append(&ctx, dataIn, len); sha1_finish(&ctx, hashout); } #define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) static void sha1_hashblock(sha1_state_t *ctx) { int t; uint32_t A,B,C,D,E,TEMP; for (t = 16; t <= 79; t++) ctx->W[t] = SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); A = ctx->H[0]; B = ctx->H[1]; C = ctx->H[2]; D = ctx->H[3]; E = ctx->H[4]; for (t = 0; t <= 19; t++) { TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; } for (t = 20; t <= 39; t++) { TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; } for (t = 40; t <= 59; t++) { TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; } for (t = 60; t <= 79; t++) { TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; } ctx->H[0] += A; ctx->H[1] += B; ctx->H[2] += C; ctx->H[3] += D; ctx->H[4] += E; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/sha1.h������������������������������������������������������������������0000664�0000000�0000000�00000004034�12614627753�0016562�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* sha1 functions */ #ifndef INCL_SHA1_H #define INCL_SHA1_H /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ /* use OpenSSL functions when available */ #ifdef HAVE_SSL #include <openssl/sha.h> #define sha1_state_t SHA_CTX #define sha1_init(c) SHA1_Init(c) #define sha1_append(c, data, len) SHA1_Update(c, data, len); #define sha1_finish(c, md) SHA1_Final(md, c) #define sha1_hash(data, len, md) SHA1(data, len, md); #else #include <inttypes.h> typedef struct sha1_state_s { uint32_t H[5]; uint32_t W[80]; int lenW; uint32_t sizeHi,sizeLo; } sha1_state_t; JABBERD2_API void sha1_init(sha1_state_t *ctx); JABBERD2_API void sha1_append(sha1_state_t *ctx, const unsigned char *dataIn, int len); JABBERD2_API void sha1_finish(sha1_state_t *ctx, unsigned char hashout[20]); JABBERD2_API void sha1_hash(const unsigned char *dataIn, int len, unsigned char hashout[20]); #endif #endif /* HAVE_SSL */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/stanza.c����������������������������������������������������������������0000664�0000000�0000000�00000011145�12614627753�0017222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "util.h" /** if you change these, reflect your changes in the defines in util.h */ struct _stanza_error_st _stanza_errors[] = { { "bad-request", "modify", "400" }, /* stanza_err_BAD_REQUEST */ { "conflict", "cancel", "409" }, /* stanza_err_CONFLICT */ { "feature-not-implemented", "cancel", "501" }, /* stanza_err_FEATURE_NOT_IMPLEMENTED */ { "forbidden", "auth", "403" }, /* stanza_err_FORBIDDEN */ { "gone", "modify", "302" }, /* stanza_err_GONE */ { "internal-server-error", "wait", "500" }, /* stanza_err_INTERNAL_SERVER_ERROR */ { "item-not-found", "cancel", "404" }, /* stanza_err_ITEM_NOT_FOUND */ { "jid-malformed", "modify", "400" }, /* stanza_err_JID_MALFORMED */ { "not-acceptable", "cancel", "406" }, /* stanza_err_NOT_ACCEPTABLE */ { "not-allowed", "cancel", "405" }, /* stanza_err_NOT_ALLOWED */ { "payment-required", "auth", "402" }, /* stanza_err_PAYMENT_REQUIRED */ { "recipient-unavailable", "wait", "404" }, /* stanza_err_RECIPIENT_UNAVAILABLE */ { "redirect", "modify", "302" }, /* stanza_err_REDIRECT */ { "registration-required", "auth", "407" }, /* stanza_err_REGISTRATION_REQUIRED */ { "remote-server-not-found", "cancel", "404" }, /* stanza_err_REMOTE_SERVER_NOT_FOUND */ { "remote-server-timeout", "wait", "502" }, /* stanza_err_REMOTE_SERVER_TIMEOUT */ { "resource-constraint", "wait", "500" }, /* stanza_err_RESOURCE_CONSTRAINT */ { "service-unavailable", "cancel", "503" }, /* stanza_err_SERVICE_UNAVAILABLE */ { "subscription-required", "auth", "407" }, /* stanza_err_SUBSCRIPTION_REQUIRED */ { "undefined-condition", NULL, "500" }, /* stanza_err_UNDEFINED_CONDITION */ { "unexpected-request", "wait", "400" }, /* stanza_err_UNEXPECTED_REQUEST */ { NULL, NULL, "401" }, /* stanza_err_OLD_UNAUTH */ { "unknown-sender", "modify", "400" }, /* stanza_err_UNKNOWN_SENDER */ { NULL, NULL, NULL } }; /** error the packet */ nad_t stanza_error(nad_t nad, int elem, int err) { int ns; assert((int) (nad != NULL)); assert((int) (elem >= 0)); assert((int) (err >= stanza_err_BAD_REQUEST && err < stanza_err_LAST)); err = err - stanza_err_BAD_REQUEST; nad_set_attr(nad, elem, -1, "type", "error", 5); elem = nad_insert_elem(nad, elem, 0, "error", NULL); if(_stanza_errors[err].code != NULL) nad_set_attr(nad, elem, -1, "code", _stanza_errors[err].code, 0); if(_stanza_errors[err].type != NULL) nad_set_attr(nad, elem, -1, "type", _stanza_errors[err].type, 0); if(_stanza_errors[err].name != NULL) { ns = nad_add_namespace(nad, uri_STANZA_ERR, NULL); nad_insert_elem(nad, elem, ns, _stanza_errors[err].name, NULL); } return nad; } /** flip the to and from attributes on this elem */ nad_t stanza_tofrom(nad_t nad, int elem) { int attr; char to[3072], from[3072]; assert((int) (nad != NULL)); to[0] = '\0'; from[0] = '\0'; attr = nad_find_attr(nad, elem, -1, "to", NULL); if(attr >= 0) snprintf(to, 3072, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); attr = nad_find_attr(nad, elem, -1, "from", NULL); if(attr >= 0) snprintf(from, 3072, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_set_attr(nad, elem, -1, "to", from[0] != '\0' ? from : NULL, 0); nad_set_attr(nad, elem, -1, "from", to[0] != '\0' ? to : NULL, 0); return nad; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/str.c�������������������������������������������������������������������0000664�0000000�0000000�00000016361�12614627753�0016537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "pool.h" #include "util.h" char *j_strdup(const char *str) { if(str == NULL) return NULL; else return strdup(str); } char *j_strcat(char *dest, const char *txt) { if(!txt) return(dest); while(*txt) *dest++ = *txt++; *dest = '\0'; return(dest); } int j_strcmp(const char *a, const char *b) { if(a == NULL || b == NULL) return -1; while(*a == *b && *a != '\0' && *b != '\0'){ a++; b++; } if(*a == *b) return 0; return -1; } int j_strcasecmp(const char *a, const char *b) { if(a == NULL || b == NULL) return -1; else return strcasecmp(a, b); } int j_strncmp(const char *a, const char *b, int i) { if(a == NULL || b == NULL) return -1; else return strncmp(a, b, i); } int j_strncasecmp(const char *a, const char *b, int i) { if(a == NULL || b == NULL) return -1; else return strncasecmp(a, b, i); } int j_strlen(const char *a) { if(a == NULL) return 0; else return strlen(a); } int j_atoi(const char *a, int def) { if(a == NULL) return def; else return atoi(a); } char *j_attr(const char** atts, const char *attr) { int i = 0; while(atts[i] != '\0') { if(j_strcmp(atts[i],attr) == 0) return (char*)atts[i+1]; i += 2; } return NULL; } /** like strchr, but only searches n chars */ char *j_strnchr(const char *s, int c, int n) { int count; for(count = 0; count < n; count++) if(s[count] == (char) c) return &((char *)s)[count]; return NULL; } spool spool_new(pool_t p) { spool s; s = pmalloc(p, sizeof(struct spool_struct)); s->p = p; s->len = 0; s->last = NULL; s->first = NULL; return s; } static void _spool_add(spool s, const char *goodstr) { struct spool_node *sn; sn = pmalloc(s->p, sizeof(struct spool_node)); sn->c = goodstr; sn->next = NULL; s->len += strlen(goodstr); if(s->last != NULL) s->last->next = sn; s->last = sn; if(s->first == NULL) s->first = sn; } void spool_add(spool s, const char *str) { if(str == NULL || strlen(str) == 0) return; _spool_add(s, pstrdup(s->p, str)); } void spool_escape(spool s, const char *raw, int len) { if(raw == NULL || len <= 0) return; _spool_add(s, strescape(s->p, raw, len)); } void spooler(spool s, ...) { va_list ap; char *arg = NULL; if(s == NULL) return; va_start(ap, s); /* loop till we hit our end flag, the first arg */ while(1) { arg = va_arg(ap,char *); if((spool)arg == s) break; else spool_add(s, arg); } va_end(ap); } const char *spool_print(spool s) { char *ret,*tmp; struct spool_node *next; if(s == NULL || s->len == 0 || s->first == NULL) return NULL; ret = pmalloc(s->p, s->len + 1); *ret = '\0'; next = s->first; tmp = ret; while(next != NULL) { tmp = j_strcat(tmp,next->c); next = next->next; } return ret; } /** convenience :) */ const char *spools(pool_t p, ...) { va_list ap; spool s; char *arg = NULL; if(p == NULL) return NULL; s = spool_new(p); va_start(ap, p); /* loop till we hit our end flag, the first arg */ while(1) { arg = va_arg(ap,char *); if((pool_t)arg == p) break; else spool_add(s, arg); } va_end(ap); return spool_print(s); } char *strunescape(pool_t p, char *buf) { int i,j=0; char *temp; if (buf == NULL) return(NULL); if (strchr(buf,'&') == NULL) return(buf); if(p != NULL) temp = pmalloc(p,strlen(buf)+1); else temp = malloc(strlen(buf)+1); if (temp == NULL) return(NULL); for(i=0;i<strlen(buf);i++) { if (buf[i]=='&') { if (strncmp(&buf[i],"&amp;",5)==0) { temp[j] = '&'; i += 4; } else if (strncmp(&buf[i],"&quot;",6)==0) { temp[j] = '\"'; i += 5; } else if (strncmp(&buf[i],"&apos;",6)==0) { temp[j] = '\''; i += 5; } else if (strncmp(&buf[i],"&lt;",4)==0) { temp[j] = '<'; i += 3; } else if (strncmp(&buf[i],"&gt;",4)==0) { temp[j] = '>'; i += 3; } } else { temp[j]=buf[i]; } j++; } temp[j]='\0'; return(temp); } char *strescape(pool_t p, const char *buf, int len) { int i,j,newlen = len; char *temp; if (buf == NULL || len < 0) return NULL; for(i=0;i<len;i++) { switch(buf[i]) { case '&': newlen+=5; break; case '\'': newlen+=6; break; case '\"': newlen+=6; break; case '<': newlen+=4; break; case '>': newlen+=4; break; } } if(p != NULL) temp = pmalloc(p,newlen+1); else temp = malloc(newlen+1); if(newlen == len) { memcpy(temp,buf,len); temp[len] = '\0'; return temp; } for(i=j=0;i<len;i++) { switch(buf[i]) { case '&': memcpy(&temp[j],"&amp;",5); j += 5; break; case '\'': memcpy(&temp[j],"&apos;",6); j += 6; break; case '\"': memcpy(&temp[j],"&quot;",6); j += 6; break; case '<': memcpy(&temp[j],"&lt;",4); j += 4; break; case '>': memcpy(&temp[j],"&gt;",4); j += 4; break; default: temp[j++] = buf[i]; } } temp[j] = '\0'; return temp; } /** convenience (originally by Thomas Muldowney) */ void shahash_r(const char* str, char hashbuf[41]) { unsigned char hashval[20]; shahash_raw(str, hashval); hex_from_raw(hashval, 20, hashbuf); } void shahash_raw(const char* str, unsigned char hashval[20]) { #ifdef HAVE_SSL /* use OpenSSL functions when available */ # include <openssl/sha.h> SHA1((unsigned char *)str, strlen(str), hashval); #else sha1_hash((unsigned char *)str, strlen(str), hashval); #endif } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/uri.h�������������������������������������������������������������������0000664�0000000�0000000�00000010516�12614627753�0016527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/uri.h * @brief common URIs * @author Robert Norris * $Revision: 1.1 $ * $Date: 2004/04/30 00:53:54 $ */ #ifndef INCL_UTIL_URI_H #define INCL_UTIL_URI_H 1 #define uri_XML "http://www.w3.org/XML/1998/namespace" /* known namespace uri */ #define uri_STREAMS "http://etherx.jabber.org/streams" #define uri_CLIENT "jabber:client" #define uri_SERVER "jabber:server" #define uri_DIALBACK "jabber:server:dialback" #define uri_DIALBACK_L 22 /* strlen(uri_DIALBACK) */ #define uri_URN_DIALBACK "urn:xmpp:features:dialback" #define uri_TLS "urn:ietf:params:xml:ns:xmpp-tls" #define uri_SASL "urn:ietf:params:xml:ns:xmpp-sasl" #define uri_BIND "urn:ietf:params:xml:ns:xmpp-bind" #define uri_XSESSION "urn:ietf:params:xml:ns:xmpp-session" #define uri_XFRAMING "urn:ietf:params:xml:ns:xmpp-framing" #define uri_COMPRESS "http://jabber.org/protocol/compress" #define uri_COMPRESS_FEATURE "http://jabber.org/features/compress" #define uri_ACK "http://www.xmpp.org/extensions/xep-0198.html#ns" #define uri_IQAUTH "http://jabber.org/features/iq-auth" #define uri_IQREGISTER "http://jabber.org/features/iq-register" #define uri_STREAM_ERR "urn:ietf:params:xml:ns:xmpp-streams" #define uri_STANZA_ERR "urn:ietf:params:xml:ns:xmpp-stanzas" #define uri_COMPONENT "http://jabberd.jabberstudio.org/ns/component/1.0" #define uri_SESSION "http://jabberd.jabberstudio.org/ns/session/1.0" #define uri_RESOLVER "http://jabberd.jabberstudio.org/ns/resolver/1.0" #define uri_XDATA "jabber:x:data" #define uri_OOB "jabber:x:oob" #define uri_ADDRESS_FEATURE "http://affinix.com/jabber/address" #define uri_ROSTERVER "urn:xmpp:features:rosterver" /* these are used by SM mainly */ #define uri_AUTH "jabber:iq:auth" #define uri_REGISTER "jabber:iq:register" #define uri_ROSTER "jabber:iq:roster" #define uri_AGENTS "jabber:iq:agents" #define uri_DELAY "jabber:x:delay" #define uri_URN_DELAY "urn:xmpp:delay" #define uri_TIME "jabber:iq:time" #define urn_TIME "urn:xmpp:time" #define uri_VERSION "jabber:iq:version" #define uri_BROWSE "jabber:iq:browse" #define uri_EVENT "jabber:x:event" #define uri_GATEWAY "jabber:iq:gateway" #define uri_EXPIRE "jabber:x:expire" #define uri_PRIVACY "jabber:iq:privacy" #define urn_BLOCKING "urn:xmpp:blocking" #define urn_BLOCKING_ERR "urn:xmpp:blocking:errors" #define uri_SEARCH "jabber:iq:search" #define urn_PING "urn:xmpp:ping" #define uri_DISCO "http://jabber.org/protocol/disco" #define uri_DISCO_ITEMS "http://jabber.org/protocol/disco#items" #define uri_DISCO_INFO "http://jabber.org/protocol/disco#info" #define uri_SERVERINFO "http://jabber.org/network/serverinfo" #define urn_SOFTWAREINFO "urn:xmpp:dataforms:softwareinfo" #define uri_AMP "http://jabber.org/protocol/amp" #define uri_AMP_ERRORS "http://jabber.org/protocol/amp#errors" #define uri_AMP_ACTION_DROP "http://jabber.org/protocol/amp?action=drop" #define uri_AMP_ACTION_ERROR "http://jabber.org/protocol/amp?action=error" #define uri_AMP_ACTION_NOTIFY "http://jabber.org/protocol/amp?action=notify" #define uri_AMP_CONDITION_DELIVER "http://jabber.org/protocol/amp?condition=deliver" #define uri_AMP_CONDITION_EXPIREAT "http://jabber.org/protocol/amp?condition=expire-at" #define uri_AMP_CONDITION_MATCHRESOURCE "http://jabber.org/protocol/amp?condition=match-resource" #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/util.h������������������������������������������������������������������0000664�0000000�0000000�00000034603�12614627753�0016710�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "ac-stdint.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <errno.h> #include <assert.h> #include <expat.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #if defined(HAVE_SYS_TIME_H) # include <sys/time.h> #elif defined(HAVE_SYS_TIMEB_H) # include <sys/timeb.h> #endif #ifdef HAVE_SYSLOG_H # include <syslog.h> #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #include <ctype.h> #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #ifdef HAVE_ARPA_INET_H # include <arpa/inet.h> #endif #ifndef PATH_MAX #ifndef MAXPATHLEN # define PATH_MAX 512 #else # define PATH_MAX MAXPATHLEN #endif #endif #ifdef USE_LIBSUBST #include "subst/subst.h" #endif #include "util/util_compat.h" #ifndef INCL_UTIL_H #define INCL_UTIL_H /* jabberd2 Windows DLL */ #ifndef JABBERD2_API # ifdef _WIN32 # ifdef JABBERD2_EXPORTS # define JABBERD2_API __declspec(dllexport) # else /* JABBERD2_EXPORTS */ # define JABBERD2_API __declspec(dllimport) # endif /* JABBERD2_EXPORTS */ # else /* _WIN32 */ # define JABBERD2_API extern # endif /* _WIN32 */ #endif /* JABBERD2_API */ #ifdef __cplusplus extern "C" { #endif /* crypto hashing utils */ #include "sha1.h" #include "md5.h" #include <util/nad.h> #include <util/pool.h> #include <util/xhash.h> /* --------------------------------------------------------- */ /* */ /* String management routines */ /* */ /** --------------------------------------------------------- */ JABBERD2_API char *j_strdup(const char *str); /* provides NULL safe strdup wrapper */ JABBERD2_API char *j_strcat(char *dest, const char *txt); /* strcpy() clone */ JABBERD2_API int j_strcmp(const char *a, const char *b); /* provides NULL safe strcmp wrapper */ JABBERD2_API int j_strcasecmp(const char *a, const char *b); /* provides NULL safe strcasecmp wrapper */ JABBERD2_API int j_strncmp(const char *a, const char *b, int i); /* provides NULL safe strncmp wrapper */ JABBERD2_API int j_strncasecmp(const char *a, const char *b, int i); /* provides NULL safe strncasecmp wrapper */ JABBERD2_API int j_strlen(const char *a); /* provides NULL safe strlen wrapper */ JABBERD2_API int j_atoi(const char *a, int def); /* checks for NULL and uses default instead, convienence */ JABBERD2_API char *j_attr(const char** atts, const char *attr); /* decode attr's (from expat) */ JABBERD2_API char *j_strnchr(const char *s, int c, int n); /* like strchr, but only searches n chars */ /** old convenience function, now in str.c */ JABBERD2_API void shahash_r(const char* str, char hashbuf[41]); JABBERD2_API void shahash_raw(const char* str, unsigned char hashval[20]); /* --------------------------------------------------------- */ /* */ /* XML escaping utils */ /* */ /* --------------------------------------------------------- */ JABBERD2_API char *strescape(pool_t p, const char *buf, int len); /* Escape <>&'" chars */ JABBERD2_API char *strunescape(pool_t p, char* buf); /* --------------------------------------------------------- */ /* */ /* String pools (spool) functions */ /* */ /* --------------------------------------------------------- */ struct spool_node { const char *c; struct spool_node *next; }; typedef struct spool_struct { pool_t p; int len; struct spool_node *last; struct spool_node *first; } *spool; JABBERD2_API spool spool_new(pool_t p); /* create a string pool */ JABBERD2_API void spooler(spool s, ...); /* append all the char * args to the pool, terminate args with s again */ JABBERD2_API const char *spool_print(spool s); /* return a big string */ JABBERD2_API void spool_add(spool s, const char *str); /* add a single string to the pool */ JABBERD2_API void spool_escape(spool s, const char *raw, int len); /* add and xml escape a single string to the pool */ JABBERD2_API const char *spools(pool_t p, ...); /* wrap all the spooler stuff in one function, the happy fun ball! */ /* known namespace uri */ #include "util/uri.h" /* JID manipulation */ #include "util/jid.h" /* logging */ typedef enum { log_STDOUT, log_SYSLOG, log_FILE } log_type_t; typedef struct log_st { log_type_t type; FILE *file; } *log_t; typedef struct log_facility_st { const char *facility; int number; } log_facility_t; JABBERD2_API log_t log_new(log_type_t type, const char *ident, const char *facility); JABBERD2_API void log_write(log_t log, int level, const char *msgfmt, ...); JABBERD2_API void log_free(log_t log); /* config files */ typedef struct config_elem_st *config_elem_t; typedef struct config_st *config_t; /** holder for the config hash and nad */ struct config_st { xht hash; nad_t nad; }; /** a single element */ struct config_elem_st { const char **values; int nvalues; const char ***attrs; }; JABBERD2_API config_t config_new(void); JABBERD2_API int config_load(config_t c, const char *file); JABBERD2_API int config_load_with_id(config_t c, const char *file, const char *id); JABBERD2_API config_elem_t config_get(config_t c, const char *key); JABBERD2_API const char *config_get_one(config_t c, const char *key, int num); JABBERD2_API const char *config_get_one_default(config_t c, const char *key, int num, const char *default_value); JABBERD2_API int config_count(config_t c, const char *key); JABBERD2_API char *config_get_attr(config_t c, const char *key, int num, const char *attr); JABBERD2_API char *config_expand(config_t c, const char *value); //! Replaces $(some.value) with config_get_one(c, "some.value", 0) JABBERD2_API void config_free(config_t); /* * IP-based access controls */ typedef struct access_rule_st { struct sockaddr_storage ip; int mask; } *access_rule_t; typedef struct access_st { int order; /* 0 = allow,deny 1 = deny,allow */ access_rule_t allow; int nallow; access_rule_t deny; int ndeny; } *access_t; JABBERD2_API access_t access_new(int order); JABBERD2_API void access_free(access_t access); JABBERD2_API int access_allow(access_t access, const char *ip, const char *mask); JABBERD2_API int access_deny(access_t access, const char *ip, const char *mask); JABBERD2_API int access_check(access_t access, const char *ip); /* * rate limiting */ typedef struct rate_st { int total; /* if we exceed this many events */ int seconds; /* in this many seconds */ int wait; /* then go bad for this many seconds */ time_t time; /* time we started counting events */ int count; /* event count */ time_t bad; /* time we went bad, or 0 if we're not */ } *rate_t; JABBERD2_API rate_t rate_new(int total, int seconds, int wait); JABBERD2_API void rate_free(rate_t rt); JABBERD2_API void rate_reset(rate_t rt); /** * Add a number of events to the counter. This takes care of moving * the sliding window, if we've moved outside the previous window. */ JABBERD2_API void rate_add(rate_t rt, int count); /** * @return The amount of events we have left before we hit the rate * limit. This could be number of bytes, or number of * connection attempts, etc. */ JABBERD2_API int rate_left(rate_t rt); /** * @return 1 if we're under the rate limit and everything is fine or * 0 if the rate limit has been exceeded and we should throttle * something. */ JABBERD2_API int rate_check(rate_t rt); /* * helpers for ip addresses */ #include "inaddr.h" /* used in mio as well */ /* * serialisation helper functions */ JABBERD2_API int ser_string_get(char **dest, int *source, const char *buf, int len); JABBERD2_API int ser_int_get(int *dest, int *source, const char *buf, int len); JABBERD2_API void ser_string_set(const char *source, int *dest, char **buf, int *len); JABBERD2_API void ser_int_set(int source, int *dest, char **buf, int *len); /* * priority queues */ typedef struct _jqueue_node_st *_jqueue_node_t; struct _jqueue_node_st { void *data; int priority; _jqueue_node_t next; _jqueue_node_t prev; }; typedef struct _jqueue_st { pool_t p; _jqueue_node_t cache; _jqueue_node_t front; _jqueue_node_t back; int size; char *key; time_t init_time; } *jqueue_t; JABBERD2_API jqueue_t jqueue_new(void); JABBERD2_API void jqueue_free(jqueue_t q); JABBERD2_API void jqueue_push(jqueue_t q, void *data, int pri); JABBERD2_API void *jqueue_pull(jqueue_t q); JABBERD2_API int jqueue_size(jqueue_t q); JABBERD2_API time_t jqueue_age(jqueue_t q); /* ISO 8601 / JEP-0082 date/time manipulation */ typedef enum { dt_DATE = 1, dt_TIME = 2, dt_DATETIME = 3, dt_LEGACY = 4 } datetime_t; JABBERD2_API time_t datetime_in(char *date); JABBERD2_API void datetime_out(time_t t, datetime_t type, char *date, int datelen); /* base64 functions */ JABBERD2_API int apr_base64_decode_len(const char *bufcoded, int buflen); JABBERD2_API int apr_base64_decode(char *bufplain, const char *bufcoded, int buflen); JABBERD2_API int apr_base64_encode_len(int len); JABBERD2_API int apr_base64_encode(char *encoded, const char *string, int len); /* convenience, result string must be free()'d by caller */ JABBERD2_API char *b64_encode(char *buf, int len); JABBERD2_API char *b64_decode(char *buf); /* stanza manipulation */ #define stanza_err_BAD_REQUEST (100) #define stanza_err_CONFLICT (101) #define stanza_err_FEATURE_NOT_IMPLEMENTED (102) #define stanza_err_FORBIDDEN (103) #define stanza_err_GONE (104) #define stanza_err_INTERNAL_SERVER_ERROR (105) #define stanza_err_ITEM_NOT_FOUND (106) #define stanza_err_JID_MALFORMED (107) #define stanza_err_NOT_ACCEPTABLE (108) #define stanza_err_NOT_ALLOWED (109) #define stanza_err_PAYMENT_REQUIRED (110) #define stanza_err_RECIPIENT_UNAVAILABLE (111) #define stanza_err_REDIRECT (112) #define stanza_err_REGISTRATION_REQUIRED (113) #define stanza_err_REMOTE_SERVER_NOT_FOUND (114) #define stanza_err_REMOTE_SERVER_TIMEOUT (115) #define stanza_err_RESOURCE_CONSTRAINT (116) #define stanza_err_SERVICE_UNAVAILABLE (117) #define stanza_err_SUBSCRIPTION_REQUIRED (118) #define stanza_err_UNDEFINED_CONDITION (119) #define stanza_err_UNEXPECTED_REQUEST (120) #define stanza_err_OLD_UNAUTH (121) #define stanza_err_UNKNOWN_SENDER (122) #define stanza_err_LAST (123) JABBERD2_API nad_t stanza_error(nad_t nad, int elem, int err); JABBERD2_API nad_t stanza_tofrom(nad_t nad, int elem); typedef struct _stanza_error_st { const char *name; const char *type; const char *code; } *stanza_error_t; JABBERD2_API struct _stanza_error_st _stanza_errors[]; /* hex conversion utils */ JABBERD2_API void hex_from_raw(const unsigned char* in, int inlen, char* out); JABBERD2_API int hex_to_raw(const char *in, int inlen, char *out); /* xdata in a seperate file */ #include "xdata.h" /* debug logging */ JABBERD2_API int get_debug_flag(void); JABBERD2_API void set_debug_flag(int v); JABBERD2_API void debug_log(const char *file, int line, const char *msgfmt, ...); JABBERD2_API void set_debug_file(const char *filename); JABBERD2_API void set_debug_log_from_config(config_t c); #define ZONE __FILE__,__LINE__ #define MAX_DEBUG 8192 /* if no debug, basically compile it out */ #ifdef DEBUG #define log_debug if(get_debug_flag()) debug_log #else #define log_debug if(0) debug_log #endif /* Portable signal function */ typedef void jsighandler_t(int); JABBERD2_API jsighandler_t* jabber_signal(int signo, jsighandler_t *func); #ifdef _WIN32 /* Windows service wrapper function */ typedef int (jmainhandler_t)(int argc, char** argv); JABBERD2_API int jabber_wrap_service(int argc, char** argv, jmainhandler_t *wrapper, LPCTSTR name, LPCTSTR display, LPCTSTR description, LPCTSTR depends); #define JABBER_MAIN(name, display, description, depends) jabber_main(int argc, char** argv); \ main(int argc, char** argv) { return jabber_wrap_service(argc, argv, jabber_main, name, display, description, depends); } \ jabber_main(int argc, char** argv) #else /* _WIN32 */ #define JABBER_MAIN(name, display, description, depends) int main(int argc, char** argv) #endif /* _WIN32 */ #ifdef __cplusplus } #endif #if XML_MAJOR_VERSION > 1 /* XML_StopParser is present in expat 2.x */ #define HAVE_XML_STOPPARSER #if XML_MINOR_VERSION > 0 /* XML_SetHashSalt is present in expat 2.1.x */ #define HAVE_XML_SETHASHSALT #endif #endif /* define TRUE and FALSE if not yet defined */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #endif /* INCL_UTIL_H */ �����������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/util_compat.h�����������������������������������������������������������0000664�0000000�0000000�00000006440�12614627753�0020251�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #ifndef INCL_UTIL_COMPAT_H #define INCL_UTIL_COMPAT_H #ifdef __cplusplus extern "C" { #endif /** * @file util/util_compat.h * @brief define the structures that could be missing in old libc implementations */ #ifndef PF_INET6 # define PF_INET6 10 /**< protcol family for IPv6 */ #endif #ifndef AF_INET6 # define AF_INET6 PF_INET6 /**< address family for IPv6 */ #endif #ifndef INET6_ADDRSTRLEN # define INET6_ADDRSTRLEN 46 /**< maximum length of the string representation of an IPv6 address */ #endif #ifndef IN6_IS_ADDR_V4MAPPED /** check if an IPv6 is just a mapped IPv4 address */ #define IN6_IS_ADDR_V4MAPPED(a) \ ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \ (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \ (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) #endif #ifndef HAVE_SA_FAMILY_T typedef unsigned short sa_family_t; #endif #ifndef HAVE_STRUCT_IN6_ADDR /** * structure that contains a plain IPv6 address (only defined if * not contained in the libc */ struct in6_addr { uint8_t s6_addr[16]; /**< IPv6 address */ }; #endif /* NO_IN6_ADDR */ #ifndef HAVE_STRUCT_SOCKADDR_IN6 /** * structure that contains an IPv6 including some additional attributes * (only defined if not contained in the libc) */ struct sockaddr_in6 { #ifdef SIN6_LEN uint8_t sin6_len; /**< length of this struct */ #endif /* SIN6_LEN */ sa_family_t sin6_family; /**< address family (AF_INET6) */ in_port_t sin6_port; /**< transport layer port # */ uint32_t sin6_flowinfo; /**< IPv6 traffic class and flow info */ struct in6_addr sin6_addr; /**< IPv6 address */ uint32_t sin6_scope_id; /**< set of interfaces for a scope */ }; #endif /* NO_SOCKADDR_IN6 */ #ifndef HAVE_STRUCT_SOCKADDR_STORAGE /** * container for sockaddr_in and sockaddr_in6 structures, handled like * an object in jabberd2 code * (this definition is not fully compatible with RFC 2553, * but it is enough for us) */ #define _SS_PADSIZE (128-sizeof(sa_family_t)) struct sockaddr_storage { sa_family_t ss_family; /**< address family */ char __ss_pad[_SS_PADSIZE]; /**< padding to a size of 128 bytes */ }; #endif /* NO_SOCKADDR_STORAGE */ #ifndef SSL_OP_NO_TICKET #define SSL_OP_NO_TICKET 0x00004000L #endif #ifdef __cplusplus } #endif #endif /* INCL_UTIL_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/xdata.c�����������������������������������������������������������������0000664�0000000�0000000�00000030531�12614627753�0017023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* xdata, whee! */ #include "util.h" /** creation */ xdata_t xdata_new(xdata_type_t type, const char *title, const char *instructions) { pool_t p; xdata_t xd; assert((int) type); p = pool_new(); xd = pmalloco(p, sizeof(struct _xdata_st)); xd->p = p; xd->type = type; if(title != NULL) xd->title = pstrdup(xd->p, title); if(instructions != NULL) xd->instructions = pstrdup(xd->p, instructions); log_debug(ZONE, "created new xd; title=%s, instructions=%s", title, instructions); return xd; } /** new field */ xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, const char *var, const char *label, const char *desc, int required) { xdata_field_t xdf; assert((int) (xd != NULL)); assert((int) type); assert((int) (var != NULL)); xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st)); xdf->p = xd->p; xdf->type = type; xdf->var = pstrdup(xdf->p, var); if(label != NULL) xdf->label = pstrdup(xdf->p, label); if(desc != NULL) xdf->desc = pstrdup(xdf->p, desc); xdf->required = required; return xdf; } /** new item */ xdata_item_t xdata_item_new(xdata_t xd) { xdata_item_t xdi; assert((int) (xd != NULL)); xdi = pmalloco(xd->p, sizeof(struct _xdata_item_st)); xdi->p = xd->p; return xdi; } /** field insertion */ void xdata_add_field(xdata_t xd, xdata_field_t xdf) { assert((int) (xd != NULL)); assert((int) (xdf != NULL)); if(xd->fields == NULL) xd->fields = xd->flast = xdf; else { xd->flast->next = xdf; xd->flast = xdf; } } void xdata_add_rfield(xdata_t xd, xdata_field_t xdf) { assert((int) (xd != NULL)); assert((int) (xdf != NULL)); if(xd->rfields == NULL) xd->rfields = xd->rflast = xdf; else { xd->rflast->next = xdf; xd->rflast = xdf; } } void xdata_add_field_item(xdata_item_t xdi, xdata_field_t xdf) { assert((int) (xdi != NULL)); assert((int) (xdf != NULL)); if(xdi->fields == NULL) xdi->fields = xdi->flast = xdf; else { xdi->flast->next = xdf; xdi->flast = xdf; } } /** item insertion */ void xdata_add_item(xdata_t xd, xdata_item_t xdi) { assert((int) (xd != NULL)); assert((int) (xdi != NULL)); if(xd->items == NULL) xd->items = xd->ilast = xdi; else { xd->ilast->next = xdi; xd->ilast = xdi; } } /** option insertion */ static void xdata_option_new(xdata_field_t xdf, const char *value, int lvalue, const char *label, int llabel) { xdata_option_t xdo; assert((int) (xdf != NULL)); assert((int) (value != NULL)); xdo = pmalloco(xdf->p, sizeof(struct _xdata_option_st)); xdo->p = xdf->p; if(lvalue <= 0) lvalue = strlen(value); xdo->value = pstrdupx(xdo->p, value, lvalue); if(label != NULL) { if(llabel <= 0) llabel = strlen(label); xdo->label = pstrdupx(xdo->p, label, llabel); } xdf->olast->next = xdo; xdf->olast = xdo; if(xdf->options == NULL) xdf->options = xdo; } /** value insertion */ void xdata_add_value(xdata_field_t xdf, const char *value, int vlen) { int first = 0; assert((int) (xdf != NULL)); assert((int) (value != NULL)); if(vlen <= 0) vlen = strlen(value); if(xdf->values == NULL) first = 1; xdf->values = (char **) realloc(xdf->values, sizeof(char *) * (xdf->nvalues + 1)); xdf->values[xdf->nvalues] = pstrdupx(xdf->p, value, vlen); xdf->nvalues++; if(first) pool_cleanup(xdf->p, free, xdf->values); } /** rip out a field */ static xdata_field_t _xdata_field_parse(xdata_t xd, nad_t nad, int root) { xdata_field_t xdf; int attr, elem, eval; xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st)); xdf->p = xd->p; attr = nad_find_attr(nad, root, -1, "var", NULL); if(attr >= 0) xdf->var = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); attr = nad_find_attr(nad, root, -1, "label", NULL); if(attr >= 0) xdf->label = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); attr = nad_find_attr(nad, root, -1, "desc", NULL); if(attr >= 0) xdf->desc = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); if(nad_find_elem(nad, root, NAD_ENS(nad, root), "required", 1) >= 0) xdf->required = 1; attr = nad_find_attr(nad, root, -1, "type", NULL); if(attr >= 0) { if(NAD_AVAL_L(nad, attr) == 7 && strncmp("boolean", NAD_AVAL(nad, attr), 7) == 0) xdf->type = xd_field_BOOLEAN; else if(NAD_AVAL_L(nad, attr) == 5 && strncmp("fixed", NAD_AVAL(nad, attr), 5) == 0) xdf->type = xd_field_FIXED; else if(NAD_AVAL_L(nad, attr) == 6 && strncmp("hidden", NAD_AVAL(nad, attr), 6) == 0) xdf->type = xd_field_HIDDEN; else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("jid-multi", NAD_AVAL(nad, attr), 9) == 0) xdf->type = xd_field_JID_MULTI; else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("jid-single", NAD_AVAL(nad, attr), 10) == 0) xdf->type = xd_field_JID_SINGLE; else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("list-multi", NAD_AVAL(nad, attr), 10) == 0) xdf->type = xd_field_LIST_MULTI; else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("list-single", NAD_AVAL(nad, attr), 11) == 0) xdf->type = xd_field_LIST_SINGLE; else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("text-multi", NAD_AVAL(nad, attr), 10) == 0) xdf->type = xd_field_TEXT_MULTI; else if(NAD_AVAL_L(nad, attr) == 12 && strncmp("text-private", NAD_AVAL(nad, attr), 12) == 0) xdf->type = xd_field_TEXT_PRIVATE; else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("text-single", NAD_AVAL(nad, attr), 11) == 0) xdf->type = xd_field_TEXT_SINGLE; else { log_debug(ZONE, "unknown field type '%.*s'", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); return NULL; } } elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "value", 1); while(elem >= 0) { if(NAD_CDATA_L(nad, elem) <= 0) { log_debug(ZONE, "value element requires cdata"); return NULL; } xdata_add_value(xdf, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)); elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 0); } elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "options", 1); while(elem >= 0) { eval = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 1); if(eval < 0) { log_debug(ZONE, "option requires value subelement"); return NULL; } if(NAD_CDATA_L(nad, eval) <= 0) { log_debug(ZONE, "value element requires cdata"); return NULL; } attr = nad_find_attr(nad, elem, -1, "label", NULL); if(attr < 0) xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NAD_AVAL(nad, eval), NAD_AVAL_L(nad, eval)); else xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NULL, 0); elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "options", 0); } return xdf; } /** parse a nad and build */ xdata_t xdata_parse(nad_t nad, int root) { xdata_t xd; int atype, elem, field; xdata_field_t xdf; assert((int) (nad != NULL)); assert((int) (root >= 0)); log_debug(ZONE, "building xd from nad"); if(root >= nad->ecur || NAD_NURI_L(nad, NAD_ENS(nad, root)) != strlen(uri_XDATA) || strncmp(uri_XDATA, NAD_NURI(nad, NAD_ENS(nad, root)), strlen(uri_XDATA) != 0) || NAD_ENAME_L(nad, root) != 1 || (NAD_ENAME(nad, root))[0] != 'x') { log_debug(ZONE, "elem %d does not exist, or is not {x:data}x", root); return NULL; } atype = nad_find_attr(nad, root, -1, "type", NULL); if(atype < 0) { log_debug(ZONE, "no type attribute"); return NULL; } if(NAD_AVAL_L(nad, atype) == 4 && strncmp("form", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0) xd = xdata_new(xd_type_FORM, NULL, NULL); else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("result", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0) xd = xdata_new(xd_type_RESULT, NULL, NULL); else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("submit", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0) xd = xdata_new(xd_type_SUBMIT, NULL, NULL); else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("cancel", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0) xd = xdata_new(xd_type_CANCEL, NULL, NULL); else { log_debug(ZONE, "unknown xd type %.*s", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype)); return NULL; } elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "title", 1); if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) { log_debug(ZONE, "no cdata on x/title element"); pool_free(xd->p); return NULL; } xd->title = pmalloco(xd->p, sizeof(char) * (NAD_CDATA_L(nad, elem) + 1)); strncpy(xd->title, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)); elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "instructions", 1); if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) { log_debug(ZONE, "no cdata on x/instructions element"); pool_free(xd->p); return NULL; } xd->instructions = pstrdupx(xd->p, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)); switch(xd->type) { case xd_type_FORM: case xd_type_SUBMIT: /* form and submit just have fields, one level */ field = nad_find_elem(nad, root, NAD_ENS(nad, root), "field", 1); while(field >= 0) { xdf = _xdata_field_parse(xd, nad, field); if(xdf == NULL) { log_debug(ZONE, "field parse failed"); pool_free(xd->p); return NULL; } xdata_add_field(xd, xdf); field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0); } break; case xd_type_RESULT: /* result has reported and item */ elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "reported", 1); if(elem >= 0) { field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1); while(field >= 0) { xdf = _xdata_field_parse(xd, nad, field); if(xdf == NULL) { log_debug(ZONE, "field parse failed"); pool_free(xd->p); return NULL; } xdata_add_field(xd, xdf); field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0); } } elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "item", 1); if(elem >= 0) { field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1); while(field >= 0) { xdf = _xdata_field_parse(xd, nad, field); if(xdf == NULL) { log_debug(ZONE, "field parse failed"); pool_free(xd->p); return NULL; } xdata_add_field(xd, xdf); field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0); } } break; case xd_type_CANCEL: /* nothing to do with cancel, its all based on context */ break; case xd_type_NONE: break; } return xd; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/xdata.h�����������������������������������������������������������������0000664�0000000�0000000�00000006644�12614627753�0017040�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /* prototypes for xdata */ #ifndef INCL_XDATA_H #define INCL_XDATA_H #include "util.h" typedef struct _xdata_st *xdata_t; typedef struct _xdata_field_st *xdata_field_t; typedef struct _xdata_option_st *xdata_option_t; typedef struct _xdata_item_st *xdata_item_t; typedef enum { xd_type_NONE, xd_type_FORM, xd_type_RESULT, xd_type_SUBMIT, xd_type_CANCEL } xdata_type_t; struct _xdata_st { pool_t p; xdata_type_t type; char *title; char *instructions; xdata_field_t fields, flast; xdata_field_t rfields, rflast; /* reported fields */ xdata_item_t items, ilast; }; typedef enum { xd_field_NONE, xd_field_BOOLEAN, xd_field_FIXED, xd_field_HIDDEN, xd_field_JID_MULTI, xd_field_JID_SINGLE, xd_field_LIST_MULTI, xd_field_LIST_SINGLE, xd_field_TEXT_MULTI, xd_field_TEXT_PRIVATE, xd_field_TEXT_SINGLE } xdata_field_type_t; struct _xdata_field_st { pool_t p; xdata_field_type_t type; char *var; char *label; char *desc; int required; char **values; int nvalues; xdata_option_t options, olast; xdata_field_t next; }; struct _xdata_option_st { pool_t p; char *label; char *value; xdata_option_t next; }; struct _xdata_item_st { pool_t p; xdata_field_t fields, flast; xdata_item_t next; }; /** creation */ JABBERD2_API xdata_t xdata_new(xdata_type_t type, const char *title, const char *instructions); JABBERD2_API xdata_t xdata_parse(nad_t nad, int root); /** new field */ JABBERD2_API xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, const char *var, const char *label, const char *desc, int required); /** new item */ JABBERD2_API xdata_item_t xdata_item_new(xdata_t xd); /** field insertion */ JABBERD2_API void xdata_add_field(xdata_t xd, xdata_field_t xdf); JABBERD2_API void xdata_add_rfield(xdata_t xd, xdata_field_t xdf); JABBERD2_API void xdata_add_field_item(xdata_item_t item, xdata_field_t xdf); /** item insertion */ JABBERD2_API void xdata_add_item(xdata_t xd, xdata_item_t xdi); /** option insertion */ JABBERD2_API void xdata_add_option(xdata_field_t xdf, const char *value, int lvalue, const char *label, int llabel); /** value insertion */ JABBERD2_API void xdata_add_value(xdata_field_t xdf, const char *value, int vlen); #endif ��������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/util/xhash.c�����������������������������������������������������������������0000664�0000000�0000000�00000020737�12614627753�0017044�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ #include "xhash.h" #include "util.h" /* Generates a hash code for a string. * This function uses the ELF hashing algorithm as reprinted in * Andrew Binstock, "Hashing Rehashed," Dr. Dobb's Journal, April 1996. */ static int _xhasher(const char *s, int len) { /* ELF hash uses unsigned chars and unsigned arithmetic for portability */ const unsigned char *name = (const unsigned char *)s; unsigned long h = 0, g; int i; for(i=0;i<len;i++) { /* do some fancy bitwanking on the string */ h = (h << 4) + (unsigned long)(name[i]); if ((g = (h & 0xF0000000UL))!=0) h ^= (g >> 24); h &= ~g; } return (int)h; } static xhn _xhash_node_new(xht h, int index) { xhn n; int i = index % h->prime; /* track total */ h->count++; #ifdef XHASH_DEBUG h->stat[i]++; #endif // if the zen[i] is empty, reuse it, else get a new one. n = &h->zen[i]; if( n->key != NULL ) { if( h->free_list ) { n = h->free_list; h->free_list = h->free_list->next; }else n = pmalloco(h->p, sizeof(_xhn)); //add it to the bucket list head. n->prev = &h->zen[i]; n->next = h->zen[i].next; if( n->next ) n->next->prev = n; h->zen[i].next = n; } return n; } static xhn _xhash_node_get(xht h, const char *key, int len, int index) { xhn n; int i = index % h->prime; for(n = &h->zen[i]; n != NULL; n = n->next) if(n->key != NULL && (n->keylen==len) && (strncmp(key, n->key, len) == 0)) return n; return NULL; } xht xhash_new(int prime) { xht xnew; pool_t p; /* log_debug(ZONE,"creating new hash table of size %d",prime); */ /** * NOTE: * all xhash's memory should be allocated from the pool by using pmalloco()/pmallocx(), * so that the xhash_free() can just call pool_free() simply. */ p = pool_heap(sizeof(_xhn)*prime + sizeof(_xht)); xnew = pmalloco(p, sizeof(_xht)); xnew->prime = prime; xnew->p = p; xnew->zen = pmalloco(p, sizeof(_xhn)*prime); /* array of xhn size of prime */ xnew->free_list = NULL; xnew->iter_bucket = -1; xnew->iter_node = NULL; #ifdef XHASH_DEBUG xnew->stat = pmalloco(p, sizeof(int)*prime ); #else xnew->stat = NULL; #endif return xnew; } void xhash_putx(xht h, const char *key, int len, void *val) { int index; xhn n; if(h == NULL || key == NULL) return; index = _xhasher(key,len); /* dirty the xht */ h->dirty++; /* if existing key, replace it */ if((n = _xhash_node_get(h, key, len, index)) != NULL) { /* log_debug(ZONE,"replacing %s with new val %X",key,val); */ n->key = key; n->keylen = len; n->val = val; return; } /* log_debug(ZONE,"saving %s val %X",key,val); */ /* new node */ n = _xhash_node_new(h, index); n->key = key; n->keylen = len; n->val = val; } void xhash_put(xht h, const char *key, void *val) { if(h == NULL || key == NULL) return; xhash_putx(h,key,strlen(key),val); } void *xhash_getx(xht h, const char *key, int len) { xhn n; if(h == NULL || key == NULL || len <= 0 || (n = _xhash_node_get(h, key, len, _xhasher(key,len))) == NULL) { /* log_debug(ZONE,"failed lookup of %s",key); */ return NULL; } /* log_debug(ZONE,"found %s returning %X",key,n->val); */ return n->val; } void *xhash_get(xht h, const char *key) { if(h == NULL || key == NULL) return NULL; return xhash_getx(h,key,strlen(key)); } void xhash_zap_inner( xht h, xhn n, int index) { int i = index % h->prime; // if element:n is in bucket list and it's not the current iter if( &h->zen[i] != n && h->iter_node != n ) { if(n->prev) n->prev->next = n->next; if(n->next) n->next->prev = n->prev; // add it to the free_list head. n->prev = NULL; n->next = h->free_list; h->free_list = n; } //empty the value. n->key = NULL; n->val = NULL; /* dirty the xht and track the total */ h->dirty++; h->count--; #ifdef XHASH_DEBUG h->stat[i]--; #endif } void xhash_zapx(xht h, const char *key, int len) { xhn n; int index; if( !h || !key ) return; index = _xhasher(key,len); n = _xhash_node_get(h, key, len, index); if( !n ) return; /* log_debug(ZONE,"zapping %s",key); */ xhash_zap_inner(h ,n, index ); } void xhash_zap(xht h, const char *key) { if(h == NULL || key == NULL) return; xhash_zapx(h,key,strlen(key)); } void xhash_free(xht h) { /* log_debug(ZONE,"hash free %X",h); */ /// want to do more things? Please see the note in xhash_new() first. if(h) pool_free(h->p); } void xhash_stat( xht h ) { #ifdef XHASH_DEBUG if( !h ) return; fprintf(stderr, "XHASH: table prime: %d , number of elements: %d\n", h->prime, h->count ); int i; for( i = 0; i< h->prime ; ++i ) { if( h->stat[i] > 1 ) fprintf(stderr, "%d: %d\t", i, h->stat[i]); } fprintf(stderr, "\n"); #endif } void xhash_walk(xht h, xhash_walker w, void *arg) { int i; xhn n; if(h == NULL || w == NULL) return; /* log_debug(ZONE,"walking %X",h); */ for(i = 0; i < h->prime; i++) for(n = &h->zen[i]; n != NULL; n = n->next) if(n->key != NULL && n->val != NULL) (*w)(n->key, n->keylen, n->val, arg); } /** return the dirty flag (and reset) */ int xhash_dirty(xht h) { int dirty; if(h == NULL) return 1; dirty = h->dirty; h->dirty = 0; return dirty; } /** return the total number of entries in this xht */ int xhash_count(xht h) { if(h == NULL) return 0; return h->count; } /** get our pool */ pool_t xhash_pool(xht h) { return h->p; } /** iteration */ int xhash_iter_first(xht h) { if(h == NULL) return 0; h->iter_bucket = -1; h->iter_node = NULL; return xhash_iter_next(h); } int xhash_iter_next(xht h) { if(h == NULL) return 0; /* next in this bucket */ h->iter_node = h->iter_node ? h->iter_node->next : NULL; while(h->iter_node != NULL) { xhn n = h->iter_node; if(n->key != NULL && n->val != NULL) return 1; h->iter_node = n->next; if (n != &h->zen[h->iter_bucket]) { if(n->prev) n->prev->next = n->next; if(n->next) n->next->prev = n->prev; // add it to the free_list head. n->prev = NULL; n->next = h->free_list; h->free_list = n; } } /* next bucket */ for(h->iter_bucket++; h->iter_bucket < h->prime; h->iter_bucket++) { h->iter_node = &h->zen[h->iter_bucket]; while(h->iter_node != NULL) { if(h->iter_node->key != NULL && h->iter_node->val != NULL) return 1; h->iter_node = h->iter_node->next; } } /* there is no next */ h->iter_bucket = -1; h->iter_node = NULL; return 0; } void xhash_iter_zap(xht h) { int index; if( !h || !h->iter_node ) return; index = _xhasher( h->iter_node->key, h->iter_node->keylen ); xhash_zap_inner( h ,h->iter_node, index); } int xhash_iter_get(xht h, const char **key, int *keylen, void **val) { if(h == NULL || (key == NULL && val == NULL) || (key != NULL && keylen == NULL)) return 0; if(h->iter_node == NULL) { if(key != NULL) *key = NULL; if(val != NULL) *val = NULL; return 0; } if(key != NULL) { *key = h->iter_node->key; *keylen = h->iter_node->keylen; } if(val != NULL) *val = h->iter_node->val; return 1; } ���������������������������������jabberd2-jabberd-2.3.4/util/xhash.h�����������������������������������������������������������������0000664�0000000�0000000�00000004703�12614627753�0017044�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2004 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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, MA02111-1307USA */ /** @file util/xhash.h * @brief hashtables * $Date: 2004/04/30 00:53:55 $ * $Revision: 1.1 $ */ #ifndef INCL_UTIL_XHASH_H #define INCL_UTIL_XHASH_H 1 #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "pool.h" typedef struct xhn_struct { struct xhn_struct *next; struct xhn_struct *prev; const char *key; int keylen; void *val; } *xhn, _xhn; typedef struct xht_struct { pool_t p; int prime; int dirty; int count; struct xhn_struct *zen; struct xhn_struct *free_list; // list of zaped elements to be reused. int iter_bucket; xhn iter_node; int *stat; } *xht, _xht; JABBERD2_API xht xhash_new(int prime); JABBERD2_API void xhash_put(xht h, const char *key, void *val); JABBERD2_API void xhash_putx(xht h, const char *key, int len, void *val); JABBERD2_API void *xhash_get(xht h, const char *key); JABBERD2_API void *xhash_getx(xht h, const char *key, int len); JABBERD2_API void xhash_zap(xht h, const char *key); JABBERD2_API void xhash_zapx(xht h, const char *key, int len); JABBERD2_API void xhash_stat(xht h); JABBERD2_API void xhash_free(xht h); typedef void (*xhash_walker)(const char *key, int keylen, void *val, void *arg); JABBERD2_API void xhash_walk(xht h, xhash_walker w, void *arg); JABBERD2_API int xhash_dirty(xht h); JABBERD2_API int xhash_count(xht h); JABBERD2_API pool_t xhash_pool(xht h); /* iteration functions */ JABBERD2_API int xhash_iter_first(xht h); JABBERD2_API int xhash_iter_next(xht h); JABBERD2_API void xhash_iter_zap(xht h); JABBERD2_API int xhash_iter_get(xht h, const char **key, int *keylen, void **val); #endif �������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0015541�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/c2s/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016230�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/c2s/c2s.vcproj���������������������������������������������������������0000664�0000000�0000000�00000015565�12614627753�0020160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="c2s" ProjectGUID="{07A3A407-B1FC-4E63-8F14-9EEAF205610B}" RootNamespace="c2s" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libidn.lib ws2_32.lib" OutputFile="../bin/debug/$(ProjectName).exe" LinkIncremental="2" AdditionalLibraryDirectories="../lib/debug;../lib" GenerateDebugInformation="true" SubSystem="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/debug/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libidn.lib ws2_32.lib" OutputFile="../bin/$(ProjectName).exe" LinkIncremental="1" AdditionalLibraryDirectories="../lib" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\c2s\authreg.c" > </File> <File RelativePath="..\..\c2s\bind.c" > </File> <File RelativePath="..\..\c2s\c2s.c" > </File> <File RelativePath="..\..\c2s\main.c" > </File> <File RelativePath="..\..\c2s\sm.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > <File RelativePath="..\include\ac-stdint.h" > </File> <File RelativePath="..\..\c2s\c2s.h" > </File> <File RelativePath="..\include\config.h" > </File> <File RelativePath="..\include\win32_port.h" > </File> </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\..\etc\c2s.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> </File> <File RelativePath="..\jabberd2.rc" > </File> <File RelativePath="..\setup\server.pem" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/���������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017164�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/ac-stdint.h����������������������������������������������������0000664�0000000�0000000�00000000647�12614627753�0021232�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _AC_STDINT_H #define _AC_STDINT_H 1 #ifndef _GENERATED_STDINT_H #define _GENERATED_STDINT_H #define uint8_t unsigned char #define uint16_t unsigned short #define uint32_t unsigned int #define int8_t signed char #define int16_t signed short #define int32_t signed int #define gint16 int16_t #ifdef _WIN64 typedef __int64 ssize_t; #else typedef _W64 int ssize_t; #endif #endif #endif �����������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/config.h�������������������������������������������������������0000664�0000000�0000000�00000046467�12614627753�0020623�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* config.h. Generated by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if you want to get debug output with -D. */ /* #undef DEBUG */ /* Define to 1 if you want to compile-in experimental XEP handlers. */ /* #undef ENABLE_EXPERIMENTAL */ /* Define to 1 if you want to compile-in superseded XEP handlers. */ #define ENABLE_SUPERSEDED 1 /* Define to 1 if you have the `alarm' function. */ /* #undef HAVE_ALARM */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 #define alloca _alloca /* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */ /* #undef HAVE_ALLOCA_H */ /* Define to 1 if you have the <arpa/inet.h> header file. */ /* #undef HAVE_ARPA_INET_H */ /* Define to 1 if you have the <arpa/nameser.h> header file. */ /* #undef HAVE_ARPA_NAMESER_H */ /* Define to 1 if 'snprintf' cannot handle NULL arguments. */ /* #undef HAVE_BROKEN_SNPRINTF */ /* Define to 1 if 'vsnprintf' cannot handle NULL arguments. */ /* #undef HAVE_BROKEN_VSNPRINTF */ /* Define to 1 if you have the `btowc' function. */ #define HAVE_BTOWC 1 /* Define to 1 if you have the 'close' function. */ #define HAVE_CLOSE 1 /* Define to 1 if you have the <db.h> header file. */ /* #undef HAVE_DB_H */ /* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. */ #define HAVE_DECL_GETENV 1 /* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. */ /* #undef HAVE_DECL_TZNAME */ /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. */ /* #undef HAVE_DIRENT_H */ /* Define to 1 if you have the <dlfcn.h> header file. */ /* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the 'DnsQuery' function. */ #define HAVE_DNSQUERY 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the `epoll_create' function. */ /* #undef HAVE_EPOLL_CREATE */ /* Define to 1 if you have the `fcntl' function. */ /* #undef HAVE_FCNTL */ /* Define to 1 if you have the <fcntl.h> header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fork' function. */ /* #undef HAVE_FORK */ /* Define to 1 if you have the `gethostname' function. */ #define HAVE_GETHOSTNAME 1 /* Define to 1 if you have the `getopt' function. */ /* #undef HAVE_GETOPT */ /* Define to 1 if you have the `getpagesize' function. */ /* #undef HAVE_GETPAGESIZE */ /* Define to 1 if you have the `getpid' function. */ #define HAVE_GETPID 1 /* Define to 1 if you have the `gettimeofday' function. */ /* #undef HAVE_GETTIMEOFDAY */ /* Define to 1 if you have the <gsasl.h> header file. */ #define HAVE_GSASL_H 1 /* Define to 1 if you have the `inet_aton' function. */ /* #undef HAVE_INET_ATON */ /* Define to 1 if you have the `inet_ntoa' function. */ /* #undef HAVE_INET_NTOA */ /* Define to 1 if you have the `inet_ntop' function. */ /* #undef HAVE_INET_NTOP */ /* Define to 1 if you have the `inet_pton' function. */ /* #undef HAVE_INET_PTON */ /* Define to 1 if you have the <inttypes.h> header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if the system has the type `in_port_t'. */ /* #undef HAVE_IN_PORT_T */ /* Define to 1 if you have the 'ioctl' function. */ #define HAVE_IOCTL 1 /* Define to 1 if you have the `isascii' function. */ #define HAVE_ISASCII 1 /* Define to 1 if you have the <lber.h> header file. */ /* #undef HAVE_LBER_H */ /* Define to 1 if you have the <ldap.h> header file. */ /* #undef HAVE_LDAP_H */ /* Define to 1 if you have the `bind' library (-lbind). */ /* #undef HAVE_LIBBIND */ /* Define to 1 if you have the `clntsh' library (-lclntsh). */ /* #undef HAVE_LIBCLNTSH */ /* Define to 1 if you have the `crypto' library (-lcrypto). */ /* #undef HAVE_LIBCRYPTO */ /* Define to 1 if you have the `expat' library (-lexpat). */ #define HAVE_LIBEXPAT 1 /* Define to 1 if you have the `gsasl' library (-lgsasl). */ #define HAVE_LIBGSASL 1 /* Define to 1 if you have the `idn' library (-lidn). */ #define HAVE_LIBIDN 1 /* Define to 1 if you have the `lber' library (-llber). */ /* #undef HAVE_LIBLBER */ /* Define to 1 if you have the `ldap' library (-lldap). */ /* #undef HAVE_LIBLDAP */ /* Define to 1 if you have the `mysqlclient' library (-lmysqlclient). */ /* #undef HAVE_LIBMYSQLCLIENT */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `pam' library (-lpam). */ /* #undef HAVE_LIBPAM */ /* Define to 1 if you have the `pq' library (-lpq). */ /* #undef HAVE_LIBPQ */ /* Define to 1 if you have the <libpq-fe.h> header file. */ /* #undef HAVE_LIBPQ_FE_H */ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `ssl' library (-lssl). */ /* #undef HAVE_LIBSSL */ /* Define to 1 if you have the `udns' library (-ludns). */ #define HAVE_LIBUDNS 1 /* Define to 1 if you have the `ws2_32' library (-lws2_32). */ #define HAVE_LIBWS2_32 1 /* if zlib is available */ #define HAVE_LIBZ 1 /* Define to 1 if you have the `mbsrtowcs' function. */ #define HAVE_MBSRTOWCS 1 /* Define to 1 if <wchar.h> declares mbstate_t. */ /* #undef HAVE_MBSTATE_T */ /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the `memchr' function. */ #define HAVE_MEMCHR 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the <memory.h> header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mempcpy' function. */ /* #undef HAVE_MEMPCPY */ /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have the `modf' function. */ #define HAVE_MODF 1 /* Define to 1 if you have the <mysql.h> header file. */ /* #undef HAVE_MYSQL_H */ /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the <netdb.h> header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the <netinet/in.h> header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define if you have oci.h */ /* #undef HAVE_OCI_H */ /* Define to 1 if you have the <openssl/crypto.h> header file. */ #define HAVE_OPENSSL_CRYPTO_H 1 /* Define to 1 if you have the <openssl/ssl.h> header file. */ #define HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the `pipe' function. */ /* #undef HAVE_PIPE */ /* Define to 1 if you have the `poll' function. */ /* #undef HAVE_POLL */ /* Define to 1 if you have the <poll.h> header file. */ /* #undef HAVE_POLL_H */ /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the 'ReportEvent' function. */ #define HAVE_REPORTEVENT 1 /* Define to 1 if you have the <resolv.h> header file. */ /* #undef HAVE_RESOLV_H */ /* Define to 1 if you have the 'res_query' function. */ /* #undef HAVE_RES_QUERY */ /* Define to 1 if you have the <sasl/sasl.h> header file. */ /* #undef HAVE_SASL_SASL_H */ /* Define to 1 if the system has the type `sa_family_t'. */ /* #undef HAVE_SA_FAMILY_T */ /* Define to 1 if you have the <security/pam_appl.h> header file. */ /* #undef HAVE_SECURITY_PAM_APPL_H */ /* Define to 1 if you have the `select' function. */ /* #undef HAVE_SELECT */ /* Define to 1 if you have the `setenv' function. */ /* #undef HAVE_SETENV */ /* Define to 1 if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H 1 /* Define to 1 if you have the `Sleep' function. */ #define HAVE_SLEEP 1 /* Define to 1 if you have the `snprintf' function. */ /* #undef HAVE_SNPRINTF */ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the <sqlite3.h> header file. */ #define HAVE_SQLITE3_H 1 /* Define to 1 if OpenSSL is available. */ #define HAVE_SSL 1 /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ /* #undef HAVE_STAT_EMPTY_STRING_BUG */ /* Define to 1 if you have the <stdarg.h> header file. */ /* #undef HAVE_STDARG_H */ /* Define to 1 if you have the <stdint.h> header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ #define HAVE_STRICMP 1 /* Define to 1 if you have the <stringprep.h> header file. */ /* #undef HAVE_STRINGPREP_H */ /* Define to 1 if you have the <strings.h> header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the <string.h> header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strndup' function. */ /* #undef HAVE_STRNDUP */ /* Define to 1 if you have the `strnicmp' function. */ #define HAVE_STRNICMP 1 /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if the system has the type `struct in6_addr'. */ #define HAVE_STRUCT_IN6_ADDR 1 /* Define to 1 if the system has the type `struct sockaddr_in6'. */ #define HAVE_STRUCT_SOCKADDR_IN6 1 /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if `tm_zone' is member of `struct tm'. */ /* #undef HAVE_STRUCT_TM_TM_ZONE */ /* Define to 1 if you have the `syslog' function. */ /* #undef HAVE_SYSLOG */ /* Define to 1 if you have the <syslog.h> header file. */ /* #undef HAVE_SYSLOG_H */ /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the <sys/epoll.h> header file. */ /* #undef HAVE_SYS_EPOLL_H */ /* Define to 1 if you have the <sys/filio.h> header file. */ /* #undef HAVE_SYS_FILIO_H */ /* Define to 1 if you have the <sys/ioctl.h> header file. */ /* #undef HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the <sys/select.h> header file. */ /* #undef HAVE_SYS_SELECT_H */ /* Define to 1 if you have the <sys/socket.h> header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the <sys/stat.h> header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the <sys/timeb.h> header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the <sys/time.h> header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the <sys/types.h> header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the <sys/utsname.h> header file. */ /* #undef HAVE_SYS_UTSNAME_H */ /* Define to 1 if you have the <sys/wait.h> header file. */ /* #undef HAVE_SYS_WAIT_H */ /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE' instead. */ /* #undef HAVE_TM_ZONE */ /* Define to 1 if you don't have `tm_zone' but do have the external array `tzname'. */ /* #undef HAVE_TZNAME */ /* Define to 1 if you have the `tzset' function. */ #define HAVE_TZSET 1 /* Define to 1 if you have the `uname' function. */ /* #undef HAVE_UNAME */ /* Define to 1 if you have the <unistd.h> header file. */ /* #undef HAVE_UNISTD_H */ /* Define to 1 if you have the `vfork' function. */ /* #undef HAVE_VFORK */ /* Define to 1 if you have the <vfork.h> header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `vsnprintf' function. */ /* #undef HAVE_VSNPRINTF */ /* Define to 1 if you have the `vsyslog' function. */ /* #undef HAVE_VSYSLOG */ /* Define to 1 if you have the `wait' function. */ /* #undef HAVE_WAIT */ /* Define to 1 if you have the <wchar.h> header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the <wctype.h> header file. */ #define HAVE_WCTYPE_H 1 /* Define to 1 if you have the <windns.h> header file. */ #define HAVE_WINDNS_H 1 /* Define to 1 if you have the <windows.h> header file. */ #define HAVE_WINDOWS_H 1 /* Define to 1 if you have the <winsock2.h> header file. */ #define HAVE_WINSOCK2_H 1 /* Define to 1 if you have the `wmempcpy' function. */ /* #undef HAVE_WMEMPCPY */ /* Define to 1 if `fork' works. */ /* #undef HAVE_WORKING_FORK */ /* Define to 1 if `vfork' works. */ /* #undef HAVE_WORKING_VFORK */ /* if you have the zlib.h header file */ #define HAVE_ZLIB_H 1 /* Define to 1 if you have the `_findfirst' function. */ #define HAVE__FINDFIRST 1 /* Define to 1 if you have the `_getpid' function. */ #define HAVE__GETPID 1 /* Define to 1 if you have the `_mkdir' function. */ #define HAVE__MKDIR 1 /* Define to 1 if you have the `strndup' function. */ /* #undef HAVE_STRNDUP */ /* Define to 1 if you have the `timegm' function. */ /* #undef HAVE_TIMEGM */ /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ /* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ /* Define to 1 if you want to enable managed IO debug output. */ #ifdef _DEBUG #define MIO_DEBUG 1 #endif /* Define to 1 if you want to use 'epoll' for non-blocking I/O. */ /* #undef MIO_EPOLL */ /* Define to 1 if you want to use 'poll' for non-blocking I/O. */ /* #undef MIO_POLL */ /* Define to 1 if you want to use 'select' for non-blocking I/O. */ /* #undef MIO_SELECT */ /* Define to 1 if you want to use WSAAsyncSelect for non-blocking I/O. */ /* #undef MIO_WSASYNC */ /* Define to 1 if you want to enable NAD pointer tracking. */ /* #undef NAD_DEBUG */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "jabberd" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define PACKAGE_NAME "jabberd" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "jabberd 2.2SVN" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "jabberd" /* Define to the version of this package. */ #define PACKAGE_VERSION "2.2SVN" /* Define to 1 if you want to enable memory pool statistics. */ /* #undef POOL_DEBUG */ /* Define as the return type of signal handlers (`int' or `void'). */ /* #undef RETSIGTYPE */ /* Define to the type of arg 1 for `select'. */ /* #undef SELECT_TYPE_ARG1 */ /* Define to the type of args 2, 3 and 4 for `select'. */ /* #undef SELECT_TYPE_ARG234 */ /* Define to the type of arg 5 for `select'. */ /* #undef SELECT_TYPE_ARG5 */ /* The number of bytes in type char */ /* #undef SIZEOF_CHAR */ /* The number of bytes in type int */ /* #undef SIZEOF_INT */ /* The number of bytes in type long */ /* #undef SIZEOF_LONG */ /* The number of bytes in type short */ /* #undef SIZEOF_SHORT */ /* The number of bytes in type void* */ /* #undef SIZEOF_VOIDP */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you want anonymous auth. */ /* #undef STORAGE_ANON */ /* Define to 1 if you want to use Berkeley DB for auth/reg/storage. */ /* #undef STORAGE_DB */ /* Define to 1 if you want to use the filesystem for storage. */ /* #undef STORAGE_FS */ /* Define to 1 if you want to use OpenLDAP for auth/reg. */ /* #undef STORAGE_LDAP */ /* Define to 1 if you want to use MySQL for auth/reg/storage. */ #define STORAGE_MYSQL 1 /* Define to 1 if you want to use Oracle for auth/reg/storage. */ /* #undef STORAGE_ORACLE */ /* Define to 1 if you want to use PAM for auth/reg. */ /* #undef STORAGE_PAM */ /* Define to 1 if you want to use Windows SSPI for auth/reg. */ #define STORAGE_SSPI 1 /* Define to 1 if you want to use NT Logon for auth/reg. */ #define STORAGE_NTLOGON 1 /* Define to 1 if you want to use PostgreSQL for auth/reg/storage. */ /* #undef STORAGE_PGSQL */ /* Define to 1 if you want to use pipes for auth/reg. */ /* #undef STORAGE_PIPE */ /* Define to 1 if you want to use PostgreSQL for storage. */ /* #undef STORAGE_POSTGRES */ /* Define to 1 if you want to use SQLite 3 for storage. */ #define STORAGE_SQLITE 1 /* Define to 1 if you want to get SX debug output with -D. */ #ifdef _DEBUG #define SX_DEBUG 1 #endif /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 if your <sys/time.h> declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Version number of package */ #define VERSION "2.0s8 win32" /* Define to a function than can provide close(2) functionality. */ /* #undef close */ /* Define to a function than can provide getpid(2) functionality. */ /* #undef getpid */ /* Define to a function than can provide ioctl(2) functionality. */ #define ioctl ioctlsocket /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ /* Define to `int' if <sys/types.h> does not define. */ /* #undef mode_t */ /* Define to `long' if <sys/types.h> does not define. */ #define off_t _off_t /* Define to `int' if <sys/types.h> does not define. */ #define pid_t int /* Define to rpl_realloc if the replacement function should be used. */ /* #undef realloc */ /* Define to `unsigned' if <sys/types.h> does not define. */ /* #undef size_t */ /* Define to a function than can provide sleep(2) functionality. */ #define sleep(x) Sleep((x)*1000); /* type to use in place of socklen_t if not defined */ /* #undef socklen_t */ /* Define to '__ss_family' if 'struct sockaddr_storage' defines '__ss_family' instead of 'ss_family'. */ /* #undef ss_family */ /* Define to '__ss_len' if 'struct sockaddr_storage' defines '__ss_len' instead of 'ss_len'. */ /* #undef ss_len */ /* Define to a function than can provide strcasecmp(3) functionality. */ #define strcasecmp stricmp /* Define to a function than can provide strncasecmp(3) functionality. */ #define strncasecmp strnicmp /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ /* #undef uint16_t */ /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ /* #undef uint32_t */ /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ /* #undef uint8_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include <win32_port.h> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/idn-int.h������������������������������������������������������0000664�0000000�0000000�00000000104�12614627753�0020672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define LOCALEDIR "." #include "config.h" #include "ac-stdint.h" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/unistd.h�������������������������������������������������������0000664�0000000�0000000�00000000000�12614627753�0020631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/version.h.in���������������������������������������������������0000775�0000000�0000000�00000000220�12614627753�0021424�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define SVN_REVISION $WCREV$ #define SVN_VERSION "2.2svn$WCREV$" #define SVN_FILEVERSION 2,2,0,$WCREV$ #define SVN_URL "$WCURL$" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/version.wxi.in�������������������������������������������������0000775�0000000�0000000�00000000361�12614627753�0022012�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <Include Id="VersionInclude"> <?define ProductRevision = "$WCREV$" ?> <?define ProductVersion = "2.2svn$WCREV$" ?> <?define ProductFileVersion = "1.0.$WCREV$" ?> <?define ProductURL = "$WCURL$" ?> </Include> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/include/win32_port.h���������������������������������������������������0000664�0000000�0000000�00000001151�12614627753�0021341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _WIN32_PORT_H #define _WIN32_PORT_H #define FD_SETSIZE 16384 /* Declare we support Win2000 & IE4. * Needed to avoid inet_ntop & inet_ption Vista SDK inclusion. */ #define WINVER 0x0500 #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0400 #define _RICHEDIT_VER 0x0100 #include <winsock2.h> #include <io.h> #include <process.h> #include <sys/types.h> #define CONFIG_DIR "." #define LIBRARY_DIR "." #ifndef S_IRUSR #define S_IRUSR 0 #endif #ifndef S_IWUSR #define S_IWUSR 0 #endif #ifndef S_IRGRP #define S_IRGRP 0 #endif #ifdef _DEBUG #define DEBUG 1 #endif #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/jabberd2.ico�����������������������������������������������������������0000664�0000000�0000000�00000036746�12614627753�0017730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �h��F��� ��� �����00��� �%��V�� �����:��(������ ���� �����@�������������������������������� ��x��̴��̡��̆��,������������������������������������������̬��r�� ��U��k��*��Z��������������������������������������$��̖��̤��o��_��-��b��������������������������������������n��6��b��̚��̉�����̦��������������������������������������2����4����������������Q���������������������������������������������������#����̔������������������������������������2������������ ��̰��̧��������������������������������-�"����������������\�����������������������������o��v��������������Q������������������������������� ��������������������������������������������������������������������������������������7������������������������������������������������������������̗��s������������������������������������������������������ ����� ����������������������̳������������������������2����W������������������������������̆��\��a��w��̭����Q������������������������������>��̘����������̋��&����������������������?��?��������G��s��s����������������(��� ���@���� �������������������������������������������������������������2��~��̾��������n���������������������������������������������������������������������������������������������:��̼������̗��\��;��F��̏��W��������������������������������������������������������������������������������������B������c�����������������������������̅��,������������������������������������������������������������������������������̃����<������=��̃��̷������̤�������F������������������������������������������������������������������������������ ��.��0��̸��������̯��̴��̣�������4����������������������������������������������������������������������������������f������v��.�����������������������)������������������������������������������������������������������������������W����u�������U��x��̋��[����������V������������������������������������������������������������������������������/��6����̚������̗��̌��Ͷ��̰������̸��̬���������������������������������������������������������������������������������� ������̆�������������������������g����T����������������������������������������������������������������������������������ˊ������������������������������������~�������������������������������������������������������������������������̿��̋��������������������������������������6������̿��������������������������������������������������������������������������������������������b������������������(�������� ���������������������������������������������������������������������������������������:��������������������̾������ ��������������������������������������������������������������������������������j�� ���������������������̫�������������������������������������������������������������������.�����������������i�����������������������������̉�������������������������������������������������������������6������;�����n������������������������������������������������������������������������������������������<�����r����������������������������������̕����̋��������������������������������������������������������������r��v������������������������������.�����������������������������������������������������������������(�f��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������$����̰����������������������������������������������������������������������������������������������������������������������\����j����������������������������������������������������������������������������������������������������������������������̘����$������������������������������������������������������������������������������������������������������������������ ����̷����������������������������������������������������������������������������������������������������������������������q����1����������������������������������������������������������������������������������������������������������������������̧������������������������������������������������������̮��F������������������������������������������������������������$����������������������������������������������������������&����������������������������������������������3������̊����������������������������������������������������������������d�������������������������������H��̫������̣���������������������������������������������������������������������������̰����������������̏�����������������������������������������������������������������F����������������������������7��������������������������������������������������������������������������������c��̮������������̓��P�������������������������������������������������������?@�@�?|?~?~??���(���0���`���� �����%����������������������������������������������������������������������������)��g��̤��������̴��̜��(�������������������������������������������������������������������������������������������������������������������������������������������������� ��r����������������������̂�����������������������������������������������������������������������������������������������������������������������������������������̀����������̨��^�����������������U��̖������������������������������������������������������������������������������������������������������������������������������������̯��������}��������������������������������������������]��V����������������������������������������������������������������������������������������������������������������������]�������� ���������������������4��Z��P��C��������� ����̼����������������������������������������������������������������������������������������������������������������������S������6����������2��̕������������������.����̳��������������������������������������������������������������������������������������������������������������������������T��.������)��̫����������������������@����̞������������������������������������������������������������������������������������������������������������������������������ ��̞��������̼��k��C������� ����������@����̈����������������������������������������������������������������������������������������������������������������������������������̐��&��������������������������������������@����̈������������������������������������������������������������������������������������������������������������������������������7��������������� ��+��N��V��!��������������?��������������������������������������������������������������������������������������������������������������������������e����̶����������̈́����������������̒���������������������������������������������������������������������������������������������������������������������������������� ����� ��y����������r��]��T��v��̵���������������x��������������������������������������������������������������������������������������������������������������������������#����������D��������������������������������������n������'�����������������������������������������������������������������������������������������������������������������������������0��������������������������������������������������+��������������������������������������������������������������������������������������������������������������[��������3��������������������������������������������������p��������\����������������������������������������������������������������������������������������������������������_������9����������������������������������������������������������̥��������̧��������������������������������������������������������������������������������������������������������G�� �����������������������������������������������������������������̚����������2���������������������������������������������������������������������������������������������������������������������������������������-������������������������������V����������5����������������������������������������������������������������������������������������������������������������������������������������������������������������������3����������7���������������������������������������������������������������������������������������������������������N�&�����������������r������������������������������������!����������:����������������������������������������������������������������������������������������������������������������������������G��������������������������������������������(���������������������������������������������������������������������������������������������4�����������������������+��������������������������������������������������������������������������������������������������������������������������������������������V�����������/����������������������������������������������������;��������i�����������������������������������������������������������������������������������������p��}����������������7��R������������������������������������������~����������������������������������������������������������������������������������������������c�������������d�s����������������������������������������������������H�������������������������������������������������������������������������������������D������)�������Z����������������������������������������������̟������̞���������������������������������������������������������������������������������������������������������� ����������������������������������������������<������̶������������������������������������������������������������������������������������������x��Q������������������������������������������������������������������������(����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.������̝����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������e������S����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������̥������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������*������o����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������̢������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'������̑����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������̦������#������������������������������������������������������������������������������������������������������������������������������������������������������������������������������B������̒������������������������������������������������������������������������������̔��̛�����������������������������������������������������������������������������������������$�������� ����������������������������������������������������������������������������������̑����������������������������������������������������������������������������������J��������G����������������������������������������������������������������������������������������e�������������������������������������������������������������������������̍��������̉����������������������������������������������������������������������������������������������̏�� ��������������������������������������������������������w����������̕������������������������������������������������������������������������������������������������������̢��d��2������������������������I��s��̰������������̠�������������������������������������������������������������������������������������������������������������������������������������������m�������������������������������������������������������������������������������������������������F������������������������������������������̰����������������������������������������������������������������������������������������������������������������8��̌��������������������������������̒��9����������������������������������������������������������������������������������������������������������������������������������!��k��̰��������������̶��̎��`��1��������������������������������������������������������������������������������������������8������ ������������������������?����������������������?������������������������?������?���>����������������?��(��� ���@�������������������������������������������������������������������������UUUXUUUUXUUXXUXUUUUXUUUUUUXUUUXUUUUUXUUUUUXUUUUUUXUUX8UU3UUX338UUD#8UU8338UX2338UX3338UX38UXUXUXUXUXUUUXUUXUXUUUUXUUUUUUUUUUUXUUUUUUUXUUUUUX�@���?x?|?~??�����������������������������jabberd2-jabberd-2.3.4/win32/jabberd2.rc������������������������������������������������������������0000664�0000000�0000000�00000002257�12614627753�0017550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "include/version.h" 1 ICON "jabberd2.ico" 1 VERSIONINFO FILEVERSION SVN_FILEVERSION PRODUCTVERSION SVN_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004b0" BEGIN VALUE "Comments", "Licensed under the terms of the GNU General Public License" VALUE "CompanyName", "jabberd2" VALUE "FileDescription", "Jabber Open Source Server" VALUE "FileVersion", SVN_VERSION VALUE "InternalName", "jabberd2" VALUE "LegalCopyright", "Copyright 2002-2007 Jeremie Miller, Thomas Muldowney, Ryan Eatmon, Robert Norris, Tomasz Sterna, Adam Strzelecki" VALUE "LegalTrademarks", "" VALUE "OriginalFilename", "" VALUE "PrivateBuild", "" VALUE "ProductName", "jabberd2" VALUE "ProductVersion", SVN_VERSION VALUE "SpecialBuild", "" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0, 1200 END END �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/jabberd2.sln�����������������������������������������������������������0000664�0000000�0000000�00000102353�12614627753�0017736�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{748E13A9-CB00-4155-BF1F-577157A8645F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libraries", "libraries", "{FFA1FCE5-6E7F-4147-A9F7-FCE221877A6D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "services", "services", "{BE878F38-A049-4E47-979E-2AB6003DB0D7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mod", "mod", "{2962D7DD-D503-43EF-AA84-7CC9975B9B2D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "authreg", "authreg", "{3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "storage", "storage", "{5206401A-8DFD-44E2-B956-B12559C314F7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "setup", "setup", "{19C6C799-93B4-4E76-82E8-138843083850}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jabberd2", "jabberd2\jabberd2.vcproj", "{98466767-1F2C-4134-A331-A05502191A29}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "c2s", "c2s\c2s.vcproj", "{07A3A407-B1FC-4E63-8F14-9EEAF205610B}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "s2s", "s2s\s2s.vcproj", "{457A89D2-B3D8-4FD6-A2AA-E111B1956E90}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sm", "sm\sm.vcproj", "{FD37421A-5883-48EE-8AF7-342839ED5564}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "router", "router\router.vcproj", "{03878EE6-16D4-49D1-BDCB-B367FF14B876}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_active", "modules\mod_active\mod_active.vcproj", "{F2D80B75-C182-4649-A5E7-93F32A1BDC4A}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_amp", "modules\mod_amp\mod_amp.vcproj", "{EB55996A-AF6E-4299-97F8-6B964E97972E}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_announce", "modules\mod_announce\mod_announce.vcproj", "{51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_deliver", "modules\mod_deliver\mod_deliver.vcproj", "{D15B8250-8C12-4366-AF6B-D2469E5A97FE}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_disco", "modules\mod_disco\mod_disco.vcproj", "{5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_disco-publish", "modules\mod_disco-publish\mod_disco-publish.vcproj", "{5322CD01-ABB4-4A83-8F78-63693DF2B636}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_echo", "modules\mod_echo\mod_echo.vcproj", "{CFB7876F-7309-488D-8083-193F0FCC8DAE}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_help", "modules\mod_help\mod_help.vcproj", "{9407EA4B-2DAC-4953-9AFD-42991B6E1C37}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-last", "modules\mod_iq-last\mod_iq-last.vcproj", "{C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-ping", "modules\mod_iq-ping\mod_iq-ping.vcproj", "{4CD8DE9E-DF42-41A6-8640-59677900803F}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-private", "modules\mod_iq-private\mod_iq-private.vcproj", "{9B15291E-6B91-4D95-AF66-AF2A1CF64E84}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-time", "modules\mod_iq-time\mod_iq-time.vcproj", "{EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-vcard", "modules\mod_iq-vcard\mod_iq-vcard.vcproj", "{99FBBE98-FCD6-437E-9216-4491FD5BFD9F}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iq-version", "modules\mod_iq-version\mod_iq-version.vcproj", "{58FA2672-021D-487D-A7B0-0974782B35AE}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_offline", "modules\mod_offline\mod_offline.vcproj", "{7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_presence", "modules\mod_presence\mod_presence.vcproj", "{6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_privacy", "modules\mod_privacy\mod_privacy.vcproj", "{2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_roster", "modules\mod_roster\mod_roster.vcproj", "{E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_session", "modules\mod_session\mod_session.vcproj", "{A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_status", "modules\mod_status\mod_status.vcproj", "{064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_template-roster", "modules\mod_template-roster\mod_template-roster.vcproj", "{A3AC8D01-CD56-4B1E-9906-41A8BCC29114}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_vacation", "modules\mod_vacation\mod_vacation.vcproj", "{052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_validate", "modules\mod_validate\mod_validate.vcproj", "{C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}" ProjectSection(ProjectDependencies) = postProject {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "authreg_anon", "modules\authreg_anon\authreg_anon.vcproj", "{ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}" ProjectSection(ProjectDependencies) = postProject {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "authreg_mysql", "modules\authreg_mysql\authreg_mysql.vcproj", "{502EF023-5147-4F18-B75A-35F8A1D94014}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "authreg_ntlogon", "modules\authreg_ntlogon\authreg_ntlogon.vcproj", "{624AA7FC-2797-477A-B8EE-83560151AF12}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "authreg_sspi", "modules\authreg_sspi\authreg_sspi.vcproj", "{DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "authreg_sqlite", "modules\authreg_sqlite\authreg_sqlite.vcproj", "{71BD9348-8C42-4BE2-AAC7-41D2AF498553}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "storage_mysql", "modules\storage_mysql\storage_mysql.vcproj", "{DE396A11-85A7-4BD7-95AB-7325955F350C}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "storage_sqlite", "modules\storage_sqlite\storage_sqlite.vcproj", "{929E41F9-EB67-4F61-8B85-15CFBB11349B}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} EndProjectSection EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "setup", "setup\setup.wixproj", "{8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD}" ProjectSection(ProjectDependencies) = postProject {5322CD01-ABB4-4A83-8F78-63693DF2B636} = {5322CD01-ABB4-4A83-8F78-63693DF2B636} {5A4E0332-82FA-42BA-BB3A-109FFD09E637} = {5A4E0332-82FA-42BA-BB3A-109FFD09E637} {A3AC8D01-CD56-4B1E-9906-41A8BCC29114} = {A3AC8D01-CD56-4B1E-9906-41A8BCC29114} {4AC65E06-5A7F-4E52-9623-CE18666AFF52} = {4AC65E06-5A7F-4E52-9623-CE18666AFF52} {624AA7FC-2797-477A-B8EE-83560151AF12} = {624AA7FC-2797-477A-B8EE-83560151AF12} {929E41F9-EB67-4F61-8B85-15CFBB11349B} = {929E41F9-EB67-4F61-8B85-15CFBB11349B} {03878EE6-16D4-49D1-BDCB-B367FF14B876} = {03878EE6-16D4-49D1-BDCB-B367FF14B876} {457A89D2-B3D8-4FD6-A2AA-E111B1956E90} = {457A89D2-B3D8-4FD6-A2AA-E111B1956E90} {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4} = {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4} {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC} = {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC} {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2} = {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2} {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467} = {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467} {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA} = {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA} {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8} = {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8} {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2} = {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2} {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17} = {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17} {4CD8DE9E-DF42-41A6-8640-59677900803F} = {4CD8DE9E-DF42-41A6-8640-59677900803F} {99FBBE98-FCD6-437E-9216-4491FD5BFD9F} = {99FBBE98-FCD6-437E-9216-4491FD5BFD9F} {F2D80B75-C182-4649-A5E7-93F32A1BDC4A} = {F2D80B75-C182-4649-A5E7-93F32A1BDC4A} {58FA2672-021D-487D-A7B0-0974782B35AE} = {58FA2672-021D-487D-A7B0-0974782B35AE} {CFB7876F-7309-488D-8083-193F0FCC8DAE} = {CFB7876F-7309-488D-8083-193F0FCC8DAE} {EB55996A-AF6E-4299-97F8-6B964E97972E} = {EB55996A-AF6E-4299-97F8-6B964E97972E} {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46} = {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46} {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0} = {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0} {D15B8250-8C12-4366-AF6B-D2469E5A97FE} = {D15B8250-8C12-4366-AF6B-D2469E5A97FE} {9407EA4B-2DAC-4953-9AFD-42991B6E1C37} = {9407EA4B-2DAC-4953-9AFD-42991B6E1C37} {71BD9348-8C42-4BE2-AAC7-41D2AF498553} = {71BD9348-8C42-4BE2-AAC7-41D2AF498553} {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE} = {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE} {502EF023-5147-4F18-B75A-35F8A1D94014} = {502EF023-5147-4F18-B75A-35F8A1D94014} {9B15291E-6B91-4D95-AF66-AF2A1CF64E84} = {9B15291E-6B91-4D95-AF66-AF2A1CF64E84} {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3} = {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3} {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214} = {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214} {DE396A11-85A7-4BD7-95AB-7325955F350C} = {DE396A11-85A7-4BD7-95AB-7325955F350C} {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47} = {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {07A3A407-B1FC-4E63-8F14-9EEAF205610B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ca", "setup\ca\ca.vcproj", "{4AC65E06-5A7F-4E52-9623-CE18666AFF52}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_roster-publish", "modules\mod_roster-publish\mod_roster-publish.vcproj", "{5A4E0332-82FA-42BA-BB3A-109FFD09E637}" ProjectSection(ProjectDependencies) = postProject {98466767-1F2C-4134-A331-A05502191A29} = {98466767-1F2C-4134-A331-A05502191A29} {FD37421A-5883-48EE-8AF7-342839ED5564} = {FD37421A-5883-48EE-8AF7-342839ED5564} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {98466767-1F2C-4134-A331-A05502191A29}.Debug|Win32.ActiveCfg = Debug|Win32 {98466767-1F2C-4134-A331-A05502191A29}.Debug|Win32.Build.0 = Debug|Win32 {98466767-1F2C-4134-A331-A05502191A29}.Release|Win32.ActiveCfg = Release|Win32 {98466767-1F2C-4134-A331-A05502191A29}.Release|Win32.Build.0 = Release|Win32 {07A3A407-B1FC-4E63-8F14-9EEAF205610B}.Debug|Win32.ActiveCfg = Debug|Win32 {07A3A407-B1FC-4E63-8F14-9EEAF205610B}.Debug|Win32.Build.0 = Debug|Win32 {07A3A407-B1FC-4E63-8F14-9EEAF205610B}.Release|Win32.ActiveCfg = Release|Win32 {07A3A407-B1FC-4E63-8F14-9EEAF205610B}.Release|Win32.Build.0 = Release|Win32 {457A89D2-B3D8-4FD6-A2AA-E111B1956E90}.Debug|Win32.ActiveCfg = Debug|Win32 {457A89D2-B3D8-4FD6-A2AA-E111B1956E90}.Debug|Win32.Build.0 = Debug|Win32 {457A89D2-B3D8-4FD6-A2AA-E111B1956E90}.Release|Win32.ActiveCfg = Release|Win32 {457A89D2-B3D8-4FD6-A2AA-E111B1956E90}.Release|Win32.Build.0 = Release|Win32 {FD37421A-5883-48EE-8AF7-342839ED5564}.Debug|Win32.ActiveCfg = Debug|Win32 {FD37421A-5883-48EE-8AF7-342839ED5564}.Debug|Win32.Build.0 = Debug|Win32 {FD37421A-5883-48EE-8AF7-342839ED5564}.Release|Win32.ActiveCfg = Release|Win32 {FD37421A-5883-48EE-8AF7-342839ED5564}.Release|Win32.Build.0 = Release|Win32 {03878EE6-16D4-49D1-BDCB-B367FF14B876}.Debug|Win32.ActiveCfg = Debug|Win32 {03878EE6-16D4-49D1-BDCB-B367FF14B876}.Debug|Win32.Build.0 = Debug|Win32 {03878EE6-16D4-49D1-BDCB-B367FF14B876}.Release|Win32.ActiveCfg = Release|Win32 {03878EE6-16D4-49D1-BDCB-B367FF14B876}.Release|Win32.Build.0 = Release|Win32 {F2D80B75-C182-4649-A5E7-93F32A1BDC4A}.Debug|Win32.ActiveCfg = Debug|Win32 {F2D80B75-C182-4649-A5E7-93F32A1BDC4A}.Debug|Win32.Build.0 = Debug|Win32 {F2D80B75-C182-4649-A5E7-93F32A1BDC4A}.Release|Win32.ActiveCfg = Release|Win32 {F2D80B75-C182-4649-A5E7-93F32A1BDC4A}.Release|Win32.Build.0 = Release|Win32 {EB55996A-AF6E-4299-97F8-6B964E97972E}.Debug|Win32.ActiveCfg = Debug|Win32 {EB55996A-AF6E-4299-97F8-6B964E97972E}.Debug|Win32.Build.0 = Debug|Win32 {EB55996A-AF6E-4299-97F8-6B964E97972E}.Release|Win32.ActiveCfg = Release|Win32 {EB55996A-AF6E-4299-97F8-6B964E97972E}.Release|Win32.Build.0 = Release|Win32 {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}.Debug|Win32.ActiveCfg = Debug|Win32 {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}.Debug|Win32.Build.0 = Debug|Win32 {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}.Release|Win32.ActiveCfg = Release|Win32 {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}.Release|Win32.Build.0 = Release|Win32 {D15B8250-8C12-4366-AF6B-D2469E5A97FE}.Debug|Win32.ActiveCfg = Debug|Win32 {D15B8250-8C12-4366-AF6B-D2469E5A97FE}.Debug|Win32.Build.0 = Debug|Win32 {D15B8250-8C12-4366-AF6B-D2469E5A97FE}.Release|Win32.ActiveCfg = Release|Win32 {D15B8250-8C12-4366-AF6B-D2469E5A97FE}.Release|Win32.Build.0 = Release|Win32 {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}.Debug|Win32.ActiveCfg = Debug|Win32 {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}.Debug|Win32.Build.0 = Debug|Win32 {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}.Release|Win32.ActiveCfg = Release|Win32 {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}.Release|Win32.Build.0 = Release|Win32 {5322CD01-ABB4-4A83-8F78-63693DF2B636}.Debug|Win32.ActiveCfg = Debug|Win32 {5322CD01-ABB4-4A83-8F78-63693DF2B636}.Debug|Win32.Build.0 = Debug|Win32 {5322CD01-ABB4-4A83-8F78-63693DF2B636}.Release|Win32.ActiveCfg = Release|Win32 {5322CD01-ABB4-4A83-8F78-63693DF2B636}.Release|Win32.Build.0 = Release|Win32 {CFB7876F-7309-488D-8083-193F0FCC8DAE}.Debug|Win32.ActiveCfg = Debug|Win32 {CFB7876F-7309-488D-8083-193F0FCC8DAE}.Debug|Win32.Build.0 = Debug|Win32 {CFB7876F-7309-488D-8083-193F0FCC8DAE}.Release|Win32.ActiveCfg = Release|Win32 {CFB7876F-7309-488D-8083-193F0FCC8DAE}.Release|Win32.Build.0 = Release|Win32 {9407EA4B-2DAC-4953-9AFD-42991B6E1C37}.Debug|Win32.ActiveCfg = Debug|Win32 {9407EA4B-2DAC-4953-9AFD-42991B6E1C37}.Debug|Win32.Build.0 = Debug|Win32 {9407EA4B-2DAC-4953-9AFD-42991B6E1C37}.Release|Win32.ActiveCfg = Release|Win32 {9407EA4B-2DAC-4953-9AFD-42991B6E1C37}.Release|Win32.Build.0 = Release|Win32 {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}.Debug|Win32.ActiveCfg = Debug|Win32 {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}.Debug|Win32.Build.0 = Debug|Win32 {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}.Release|Win32.ActiveCfg = Release|Win32 {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}.Release|Win32.Build.0 = Release|Win32 {4CD8DE9E-DF42-41A6-8640-59677900803F}.Debug|Win32.ActiveCfg = Debug|Win32 {4CD8DE9E-DF42-41A6-8640-59677900803F}.Debug|Win32.Build.0 = Debug|Win32 {4CD8DE9E-DF42-41A6-8640-59677900803F}.Release|Win32.ActiveCfg = Release|Win32 {4CD8DE9E-DF42-41A6-8640-59677900803F}.Release|Win32.Build.0 = Release|Win32 {9B15291E-6B91-4D95-AF66-AF2A1CF64E84}.Debug|Win32.ActiveCfg = Debug|Win32 {9B15291E-6B91-4D95-AF66-AF2A1CF64E84}.Debug|Win32.Build.0 = Debug|Win32 {9B15291E-6B91-4D95-AF66-AF2A1CF64E84}.Release|Win32.ActiveCfg = Release|Win32 {9B15291E-6B91-4D95-AF66-AF2A1CF64E84}.Release|Win32.Build.0 = Release|Win32 {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}.Debug|Win32.ActiveCfg = Debug|Win32 {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}.Debug|Win32.Build.0 = Debug|Win32 {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}.Release|Win32.ActiveCfg = Release|Win32 {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}.Release|Win32.Build.0 = Release|Win32 {99FBBE98-FCD6-437E-9216-4491FD5BFD9F}.Debug|Win32.ActiveCfg = Debug|Win32 {99FBBE98-FCD6-437E-9216-4491FD5BFD9F}.Debug|Win32.Build.0 = Debug|Win32 {99FBBE98-FCD6-437E-9216-4491FD5BFD9F}.Release|Win32.ActiveCfg = Release|Win32 {99FBBE98-FCD6-437E-9216-4491FD5BFD9F}.Release|Win32.Build.0 = Release|Win32 {58FA2672-021D-487D-A7B0-0974782B35AE}.Debug|Win32.ActiveCfg = Debug|Win32 {58FA2672-021D-487D-A7B0-0974782B35AE}.Debug|Win32.Build.0 = Debug|Win32 {58FA2672-021D-487D-A7B0-0974782B35AE}.Release|Win32.ActiveCfg = Release|Win32 {58FA2672-021D-487D-A7B0-0974782B35AE}.Release|Win32.Build.0 = Release|Win32 {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}.Debug|Win32.ActiveCfg = Debug|Win32 {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}.Debug|Win32.Build.0 = Debug|Win32 {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}.Release|Win32.ActiveCfg = Release|Win32 {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}.Release|Win32.Build.0 = Release|Win32 {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}.Debug|Win32.ActiveCfg = Debug|Win32 {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}.Debug|Win32.Build.0 = Debug|Win32 {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}.Release|Win32.ActiveCfg = Release|Win32 {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}.Release|Win32.Build.0 = Release|Win32 {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}.Debug|Win32.ActiveCfg = Debug|Win32 {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}.Debug|Win32.Build.0 = Debug|Win32 {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}.Release|Win32.ActiveCfg = Release|Win32 {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}.Release|Win32.Build.0 = Release|Win32 {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}.Debug|Win32.ActiveCfg = Debug|Win32 {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}.Debug|Win32.Build.0 = Debug|Win32 {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}.Release|Win32.ActiveCfg = Release|Win32 {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}.Release|Win32.Build.0 = Release|Win32 {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}.Debug|Win32.ActiveCfg = Debug|Win32 {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}.Debug|Win32.Build.0 = Debug|Win32 {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}.Release|Win32.ActiveCfg = Release|Win32 {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}.Release|Win32.Build.0 = Release|Win32 {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}.Debug|Win32.ActiveCfg = Debug|Win32 {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}.Debug|Win32.Build.0 = Debug|Win32 {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}.Release|Win32.ActiveCfg = Release|Win32 {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}.Release|Win32.Build.0 = Release|Win32 {A3AC8D01-CD56-4B1E-9906-41A8BCC29114}.Debug|Win32.ActiveCfg = Debug|Win32 {A3AC8D01-CD56-4B1E-9906-41A8BCC29114}.Debug|Win32.Build.0 = Debug|Win32 {A3AC8D01-CD56-4B1E-9906-41A8BCC29114}.Release|Win32.ActiveCfg = Release|Win32 {A3AC8D01-CD56-4B1E-9906-41A8BCC29114}.Release|Win32.Build.0 = Release|Win32 {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}.Debug|Win32.ActiveCfg = Debug|Win32 {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}.Debug|Win32.Build.0 = Debug|Win32 {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}.Release|Win32.ActiveCfg = Release|Win32 {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}.Release|Win32.Build.0 = Release|Win32 {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}.Debug|Win32.ActiveCfg = Debug|Win32 {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}.Debug|Win32.Build.0 = Debug|Win32 {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}.Release|Win32.ActiveCfg = Release|Win32 {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}.Release|Win32.Build.0 = Release|Win32 {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}.Debug|Win32.ActiveCfg = Debug|Win32 {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}.Debug|Win32.Build.0 = Debug|Win32 {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}.Release|Win32.ActiveCfg = Release|Win32 {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}.Release|Win32.Build.0 = Release|Win32 {502EF023-5147-4F18-B75A-35F8A1D94014}.Debug|Win32.ActiveCfg = Debug|Win32 {502EF023-5147-4F18-B75A-35F8A1D94014}.Debug|Win32.Build.0 = Debug|Win32 {502EF023-5147-4F18-B75A-35F8A1D94014}.Release|Win32.ActiveCfg = Release|Win32 {502EF023-5147-4F18-B75A-35F8A1D94014}.Release|Win32.Build.0 = Release|Win32 {624AA7FC-2797-477A-B8EE-83560151AF12}.Debug|Win32.ActiveCfg = Debug|Win32 {624AA7FC-2797-477A-B8EE-83560151AF12}.Debug|Win32.Build.0 = Debug|Win32 {624AA7FC-2797-477A-B8EE-83560151AF12}.Release|Win32.ActiveCfg = Release|Win32 {624AA7FC-2797-477A-B8EE-83560151AF12}.Release|Win32.Build.0 = Release|Win32 {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}.Debug|Win32.ActiveCfg = Debug|Win32 {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}.Debug|Win32.Build.0 = Debug|Win32 {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}.Release|Win32.ActiveCfg = Release|Win32 {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}.Release|Win32.Build.0 = Release|Win32 {71BD9348-8C42-4BE2-AAC7-41D2AF498553}.Debug|Win32.ActiveCfg = Debug|Win32 {71BD9348-8C42-4BE2-AAC7-41D2AF498553}.Debug|Win32.Build.0 = Debug|Win32 {71BD9348-8C42-4BE2-AAC7-41D2AF498553}.Release|Win32.ActiveCfg = Release|Win32 {71BD9348-8C42-4BE2-AAC7-41D2AF498553}.Release|Win32.Build.0 = Release|Win32 {DE396A11-85A7-4BD7-95AB-7325955F350C}.Debug|Win32.ActiveCfg = Debug|Win32 {DE396A11-85A7-4BD7-95AB-7325955F350C}.Debug|Win32.Build.0 = Debug|Win32 {DE396A11-85A7-4BD7-95AB-7325955F350C}.Release|Win32.ActiveCfg = Release|Win32 {DE396A11-85A7-4BD7-95AB-7325955F350C}.Release|Win32.Build.0 = Release|Win32 {929E41F9-EB67-4F61-8B85-15CFBB11349B}.Debug|Win32.ActiveCfg = Debug|Win32 {929E41F9-EB67-4F61-8B85-15CFBB11349B}.Debug|Win32.Build.0 = Debug|Win32 {929E41F9-EB67-4F61-8B85-15CFBB11349B}.Release|Win32.ActiveCfg = Release|Win32 {929E41F9-EB67-4F61-8B85-15CFBB11349B}.Release|Win32.Build.0 = Release|Win32 {8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD}.Debug|Win32.ActiveCfg = Debug|x86 {8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD}.Debug|Win32.Build.0 = Debug|x86 {8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD}.Release|Win32.ActiveCfg = Release|x86 {8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD}.Release|Win32.Build.0 = Release|x86 {4AC65E06-5A7F-4E52-9623-CE18666AFF52}.Debug|Win32.ActiveCfg = Debug|Win32 {4AC65E06-5A7F-4E52-9623-CE18666AFF52}.Debug|Win32.Build.0 = Debug|Win32 {4AC65E06-5A7F-4E52-9623-CE18666AFF52}.Release|Win32.ActiveCfg = Release|Win32 {4AC65E06-5A7F-4E52-9623-CE18666AFF52}.Release|Win32.Build.0 = Release|Win32 {5A4E0332-82FA-42BA-BB3A-109FFD09E637}.Debug|Win32.ActiveCfg = Debug|Win32 {5A4E0332-82FA-42BA-BB3A-109FFD09E637}.Debug|Win32.Build.0 = Debug|Win32 {5A4E0332-82FA-42BA-BB3A-109FFD09E637}.Release|Win32.ActiveCfg = Release|Win32 {5A4E0332-82FA-42BA-BB3A-109FFD09E637}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} = {748E13A9-CB00-4155-BF1F-577157A8645F} {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} = {748E13A9-CB00-4155-BF1F-577157A8645F} {5206401A-8DFD-44E2-B956-B12559C314F7} = {748E13A9-CB00-4155-BF1F-577157A8645F} {98466767-1F2C-4134-A331-A05502191A29} = {FFA1FCE5-6E7F-4147-A9F7-FCE221877A6D} {07A3A407-B1FC-4E63-8F14-9EEAF205610B} = {BE878F38-A049-4E47-979E-2AB6003DB0D7} {457A89D2-B3D8-4FD6-A2AA-E111B1956E90} = {BE878F38-A049-4E47-979E-2AB6003DB0D7} {FD37421A-5883-48EE-8AF7-342839ED5564} = {BE878F38-A049-4E47-979E-2AB6003DB0D7} {03878EE6-16D4-49D1-BDCB-B367FF14B876} = {BE878F38-A049-4E47-979E-2AB6003DB0D7} {F2D80B75-C182-4649-A5E7-93F32A1BDC4A} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {EB55996A-AF6E-4299-97F8-6B964E97972E} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {D15B8250-8C12-4366-AF6B-D2469E5A97FE} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {5BD89D57-0339-4A43-AB3D-1F42A13DFBB0} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {5322CD01-ABB4-4A83-8F78-63693DF2B636} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {CFB7876F-7309-488D-8083-193F0FCC8DAE} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {9407EA4B-2DAC-4953-9AFD-42991B6E1C37} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {C19413CB-69C8-4AC4-83EA-8500C8E3CEC4} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {4CD8DE9E-DF42-41A6-8640-59677900803F} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {9B15291E-6B91-4D95-AF66-AF2A1CF64E84} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {99FBBE98-FCD6-437E-9216-4491FD5BFD9F} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {58FA2672-021D-487D-A7B0-0974782B35AE} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {7D2EC117-BFC4-4AA5-8F17-01E67A3A9214} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {E65054BF-F8B4-47CE-AE8B-CF304FF06EAC} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {A83C3AB7-87E7-4758-AAD4-AEA5CE34D467} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {A3AC8D01-CD56-4B1E-9906-41A8BCC29114} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {C1D1D430-C051-4CC3-A5F1-E62788FFCBFE} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {5A4E0332-82FA-42BA-BB3A-109FFD09E637} = {2962D7DD-D503-43EF-AA84-7CC9975B9B2D} {ED3C330D-5C59-4C10-AA0B-7EF5FB575A47} = {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} {502EF023-5147-4F18-B75A-35F8A1D94014} = {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} {624AA7FC-2797-477A-B8EE-83560151AF12} = {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} {DBA74B58-93C6-4BE5-A6E0-2A91F176BE46} = {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} {71BD9348-8C42-4BE2-AAC7-41D2AF498553} = {3DB4EFDA-D609-4EB0-A848-CF18B2F1EDC4} {DE396A11-85A7-4BD7-95AB-7325955F350C} = {5206401A-8DFD-44E2-B956-B12559C314F7} {929E41F9-EB67-4F61-8B85-15CFBB11349B} = {5206401A-8DFD-44E2-B956-B12559C314F7} {8504D60E-B1C4-4FE8-A5C2-3F36B1A5E2BD} = {19C6C799-93B4-4E76-82E8-138843083850} {4AC65E06-5A7F-4E52-9623-CE18666AFF52} = {19C6C799-93B4-4E76-82E8-138843083850} EndGlobalSection EndGlobal �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/jabberd2/��������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017214�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/jabberd2/jabberd2.vcproj�����������������������������������������������0000664�0000000�0000000�00000030372�12614627753�0022121�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="jabberd2" ProjectGUID="{98466767-1F2C-4134-A331-A05502191A29}" RootNamespace="jabberd2" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="SX_DEBUG;MIO_DEBUG;MIO_WSASYNC;WIN32;_DEBUG;_USRDLL;JABBERD2_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libidn.lib libgsasl.lib libeay32.lib ssleay32.lib dnsapi.lib ws2_32.lib libexpat.lib zlib1.lib" OutputFile="../bin/debug/$(ProjectName).dll" AdditionalLibraryDirectories="../lib/debug;../lib" GenerateDebugInformation="true" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/debug/$(TargetName).lib" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="MIO_WSASYNC;WIN32;NDEBUG;_USRDLL;JABBERD2_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libidn.lib libgsasl.lib libeay32.lib ssleay32.lib dnsapi.lib ws2_32.lib libexpat.lib zlib1.lib" OutputFile="../bin/$(ProjectName).dll" AdditionalLibraryDirectories="../lib" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/$(TargetName).lib" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <Filter Name="util" > <File RelativePath="..\..\util\access.c" > </File> <File RelativePath="..\..\util\base64.c" > </File> <File RelativePath="..\..\util\config.c" > </File> <File RelativePath="..\..\util\datetime.c" > </File> <File RelativePath="..\..\util\hex.c" > </File> <File RelativePath="..\..\util\inaddr.c" > </File> <File RelativePath="..\..\util\jid.c" > </File> <File RelativePath="..\..\util\jqueue.c" > </File> <File RelativePath="..\..\util\jsignal.c" > </File> <File RelativePath="..\..\util\log.c" > </File> <File RelativePath="..\..\util\md5.c" > </File> <File RelativePath="..\..\util\misc.c" > </File> <File RelativePath="..\..\util\nad.c" > </File> <File RelativePath="..\..\util\pool.c" > </File> <File RelativePath="..\..\util\pqueue.c" > </File> <File RelativePath="..\..\util\rate.c" > </File> <File RelativePath="..\..\util\serial.c" > </File> <File RelativePath="..\..\util\stanza.c" > </File> <File RelativePath="..\..\util\str.c" > </File> <File RelativePath="..\..\util\xconfig.c" > </File> <File RelativePath="..\..\util\xdata.c" > </File> <File RelativePath="..\..\util\xhash.c" > </File> </Filter> <Filter Name="mio" > <File RelativePath="..\..\mio\mio.c" > </File> <File RelativePath="..\..\mio\mio_select.c" > </File> <File RelativePath="..\..\mio\mio_wsasync.c" > </File> </Filter> <Filter Name="subst" > <File RelativePath="..\..\subst\dirent.c" > </File> <File RelativePath="..\..\subst\getopt.c" > </File> <File RelativePath="..\..\subst\gettimeofday.c" > </File> <File RelativePath="..\..\subst\inet_aton.c" > </File> <File RelativePath="..\..\subst\inet_ntop.c" > </File> <File RelativePath="..\..\subst\inet_pton.c" > </File> <File RelativePath="..\..\subst\snprintf.c" > </File> <File RelativePath="..\..\subst\strndup.c" > </File> <File RelativePath="..\..\subst\syslog.c" > </File> <File RelativePath="..\..\subst\timegm.c" > </File> </Filter> <Filter Name="sx" > <File RelativePath="..\..\sx\callback.c" > </File> <File RelativePath="..\..\sx\chain.c" > </File> <File RelativePath="..\..\sx\client.c" > </File> <File RelativePath="..\..\sx\compress.c" > </File> <File RelativePath="..\..\sx\env.c" > </File> <File RelativePath="..\..\sx\error.c" > </File> <File RelativePath="..\..\sx\io.c" > </File> <File RelativePath="..\..\sx\sasl_gsasl.c" > </File> <File RelativePath="..\..\sx\server.c" > </File> <File RelativePath="..\..\sx\ssl.c" > </File> <File RelativePath="..\..\sx\sx.c" > </File> </Filter> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > <File RelativePath="..\include\ac-stdint.h" > </File> <File RelativePath="..\include\config.h" > </File> <File RelativePath="..\include\win32_port.h" > </File> <Filter Name="util" > <File RelativePath="..\..\util\base64.h" > </File> <File RelativePath="..\..\util\datetime.h" > </File> <File RelativePath="..\..\util\inaddr.h" > </File> <File RelativePath="..\..\util\jid.h" > </File> <File RelativePath="..\..\util\log.h" > </File> <File RelativePath="..\..\util\md5.h" > </File> <File RelativePath="..\..\util\misc.h" > </File> <File RelativePath="..\..\util\nad.h" > </File> <File RelativePath="..\..\util\pool.h" > </File> <File RelativePath="..\..\util\pqueue.h" > </File> <File RelativePath="..\..\util\sha1.h" > </File> <File RelativePath="..\..\util\uri.h" > </File> <File RelativePath="..\..\util\util.h" > </File> <File RelativePath="..\..\util\util_compat.h" > </File> <File RelativePath="..\..\util\xconfig.h" > </File> <File RelativePath="..\..\util\xdata.h" > </File> <File RelativePath="..\..\util\xhash.h" > </File> </Filter> <Filter Name="mio" > <File RelativePath="..\..\mio\mio.h" > </File> <File RelativePath="..\..\mio\mio_impl.h" > </File> <File RelativePath="..\..\mio\mio_select.h" > </File> <File RelativePath="..\..\mio\mio_wsasync.h" > </File> </Filter> <Filter Name="subst" > <File RelativePath="..\..\subst\dirent.h" > </File> <File RelativePath="..\..\subst\getopt.h" > </File> <File RelativePath="..\..\subst\ip6_misc.h" > </File> <File RelativePath="..\..\subst\subst.h" > </File> <File RelativePath="..\..\subst\syslog.h" > </File> </Filter> <Filter Name="sx" > <File RelativePath="..\..\sx\sasl.h" > </File> <File RelativePath="..\..\sx\ssl.h" > </File> <File RelativePath="..\..\sx\sx.h" > </File> </Filter> <Filter Name="version" > <File RelativePath="..\include\version.h" > </File> <File RelativePath="..\include\version.h.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Updating $(InputDir)$(InputName)" CommandLine="subwcrev ..\.. $(InputPath) $(InputDir)$(InputName)&#x0D;&#x0A;" AdditionalDependencies="$(InputDir)..\.svn\entries" Outputs="$(InputDir)$(InputName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Updating $(InputDir)$(InputName)" CommandLine="subwcrev ..\.. $(InputPath) $(InputDir)$(InputName)&#x0D;&#x0A;" AdditionalDependencies="$(InputDir)..\.svn\entries" Outputs="$(InputDir)$(InputName)" /> </FileConfiguration> </File> <File RelativePath="..\include\version.wxi" > </File> <File RelativePath="..\include\version.wxi.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Updating $(InputDir)$(InputName)" CommandLine="subwcrev ..\.. $(InputPath) $(InputDir)$(InputName)&#x0D;&#x0A;" AdditionalDependencies="$(InputDir)..\.svn\entries" Outputs="$(InputDir)$(InputName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Updating $(InputDir)$(InputName)" CommandLine="subwcrev ..\.. $(InputPath) $(InputDir)$(InputName)&#x0D;&#x0A;" AdditionalDependencies="$(InputDir)..\.svn\entries" Outputs="$(InputDir)$(InputName)" /> </FileConfiguration> </File> </Filter> </Filter> <Filter Name="Resource Files" > <File RelativePath="..\jabberd2.rc" > </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/���������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017211�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_anon/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021663�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_anon/authreg_anon.vcproj�������������������������������0000664�0000000�0000000�00000011340�12614627753�0025561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="authreg_anon" ProjectGUID="{ED3C330D-5C59-4C10-AA0B-7EF5FB575A47}" RootNamespace="authreg_anon" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\authreg_anon.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_mysql/�������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022075�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_mysql/authreg_mysql.vcproj�����������������������������0000664�0000000�0000000�00000011427�12614627753�0026213�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="authreg_mysql" ProjectGUID="{502EF023-5147-4F18-B75A-35F8A1D94014}" RootNamespace="authreg_mysql" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib c2s.lib jabberd2.lib libeay32.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib c2s.lib jabberd2.lib libeay32.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\authreg_mysql.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_ntlogon/�����������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022410�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_ntlogon/authreg_ntlogon.vcproj�������������������������0000664�0000000�0000000�00000011351�12614627753�0027035�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="authreg_ntlogon" ProjectGUID="{624AA7FC-2797-477A-B8EE-83560151AF12}" RootNamespace="authreg_ntlogon" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\authreg_ntlogon.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_sqlite/������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022231�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_sqlite/authreg_sqlite.vcproj���������������������������0000664�0000000�0000000�00000011376�12614627753�0026506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="authreg_sqlite" ProjectGUID="{71BD9348-8C42-4BE2-AAC7-41D2AF498553}" RootNamespace="authreg_sqlite" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sqlite3.lib c2s.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sqlite3.lib c2s.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\authreg_sqlite.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_sspi/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021706�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/authreg_sspi/authreg_sspi.vcproj�������������������������������0000664�0000000�0000000�00000011340�12614627753�0025627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="authreg_sspi" ProjectGUID="{DBA74B58-93C6-4BE5-A6E0-2A91F176BE46}" RootNamespace="authreg_sspi" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../c2s" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHREG_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="c2s.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\authreg_sspi.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_active/����������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021323�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_active/mod_active.vcproj�����������������������������������0000664�0000000�0000000�00000011311�12614627753�0024657�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_active" ProjectGUID="{F2D80B75-C182-4649-A5E7-93F32A1BDC4A}" RootNamespace="mod_active" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_active.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_amp/�������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0020625�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_amp/mod_amp.vcproj�����������������������������������������0000664�0000000�0000000�00000011300�12614627753�0023461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_amp" ProjectGUID="{EB55996A-AF6E-4299-97F8-6B964E97972E}" RootNamespace="mod_amp" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_amp.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_announce/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021656�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_announce/mod_announce.vcproj�������������������������������0000664�0000000�0000000�00000011317�12614627753�0025553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_announce" ProjectGUID="{51BCD5BD-558B-43F3-979F-3FB0A7ECD8A2}" RootNamespace="mod_announce" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_announce.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_deliver/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021502�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_deliver/mod_deliver.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025220�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_deliver" ProjectGUID="{D15B8250-8C12-4366-AF6B-D2469E5A97FE}" RootNamespace="mod_deliver" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_deliver.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_disco-publish/���������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022615�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_disco-publish/mod_disco-publish.vcproj���������������������0000664�0000000�0000000�00000011336�12614627753�0027452�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_disco-publish" ProjectGUID="{5322CD01-ABB4-4A83-8F78-63693DF2B636}" RootNamespace="mod_disco-publish" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_disco_publish.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_disco/�����������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021151�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_disco/mod_disco.vcproj�������������������������������������0000664�0000000�0000000�00000011306�12614627753�0024337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_disco" ProjectGUID="{5BD89D57-0339-4A43-AB3D-1F42A13DFBB0}" RootNamespace="mod_disco" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_disco.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_echo/������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0020766�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_echo/mod_echo.vcproj���������������������������������������0000664�0000000�0000000�00000011303�12614627753�0023766�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_echo" ProjectGUID="{CFB7876F-7309-488D-8083-193F0FCC8DAE}" RootNamespace="mod_echo" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_echo.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_help/������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021000�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_help/mod_help.vcproj���������������������������������������0000664�0000000�0000000�00000011303�12614627753�0024012�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_help" ProjectGUID="{9407EA4B-2DAC-4953-9AFD-42991B6E1C37}" RootNamespace="mod_help" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_help.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-last/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021422�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-last/mod_iq-last.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025060�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-last" ProjectGUID="{C19413CB-69C8-4AC4-83EA-8500C8E3CEC4}" RootNamespace="mod_iq-last" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_last.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-ping/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021414�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-ping/mod_iq-ping.vcproj���������������������������������0000664�0000000�0000000�00000011313�12614627753�0025043�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-ping" ProjectGUID="{4CD8DE9E-DF42-41A6-8640-59677900803F}" RootNamespace="mod_iqping" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_ping.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-private/������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022131�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-private/mod_iq-private.vcproj���������������������������0000664�0000000�0000000�00000011325�12614627753�0026300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-private" ProjectGUID="{9B15291E-6B91-4D95-AF66-AF2A1CF64E84}" RootNamespace="mod_iq-private" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_private.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-time/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021415�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-time/mod_iq-time.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-time" ProjectGUID="{EC544DAB-5FDF-422F-81D2-75C5BB6B3CA2}" RootNamespace="mod_iq-time" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_time.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-vcard/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021556�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-vcard/mod_iq-vcard.vcproj�������������������������������0000664�0000000�0000000�00000011317�12614627753�0025353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-vcard" ProjectGUID="{99FBBE98-FCD6-437E-9216-4491FD5BFD9F}" RootNamespace="mod_iq-vcard" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_vcard.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-version/������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022144�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_iq-version/mod_iq-version.vcproj���������������������������0000664�0000000�0000000�00000011325�12614627753�0026326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_iq-version" ProjectGUID="{58FA2672-021D-487D-A7B0-0974782B35AE}" RootNamespace="mod_iq-version" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_iq_version.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_offline/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021472�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_offline/mod_offline.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025200�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_offline" ProjectGUID="{7D2EC117-BFC4-4AA5-8F17-01E67A3A9214}" RootNamespace="mod_offline" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_offline.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_presence/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021654�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_presence/mod_presence.vcproj�������������������������������0000664�0000000�0000000�00000011317�12614627753�0025547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_presence" ProjectGUID="{6DC9D2B4-A0A5-4EC3-B17A-3D2D91BBE9EA}" RootNamespace="mod_presence" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_presence.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_privacy/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021525�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_privacy/mod_privacy.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_privacy" ProjectGUID="{2F564FB2-1A89-4FD8-A94B-77DBE5B9E0C8}" RootNamespace="mod_privacy" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_privacy.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_roster-publish/��������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0023032�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_roster-publish/mod_roster-publish.vcproj�������������������0000664�0000000�0000000�00000011341�12614627753�0030100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_roster-publish" ProjectGUID="{5A4E0332-82FA-42BA-BB3A-109FFD09E637}" RootNamespace="mod_roster-publish" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_roster_publish.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_roster/����������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021366�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_roster/mod_roster.vcproj�����������������������������������0000664�0000000�0000000�00000011311�12614627753�0024765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_roster" ProjectGUID="{E65054BF-F8B4-47CE-AE8B-CF304FF06EAC}" RootNamespace="mod_roster" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_roster.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_session/���������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021533�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_session/mod_session.vcproj���������������������������������0000664�0000000�0000000�00000011314�12614627753�0025302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_session" ProjectGUID="{A83C3AB7-87E7-4758-AAD4-AEA5CE34D467}" RootNamespace="mod_session" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_session.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_status/����������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021373�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_status/mod_status.vcproj�����������������������������������0000664�0000000�0000000�00000011311�12614627753�0024777�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_status" ProjectGUID="{064ADF1D-E6C7-4FAF-AF06-3FFF180B4BB3}" RootNamespace="mod_status" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_status.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_template-roster/�������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0023177�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_template-roster/mod_template-roster.vcproj�����������������0000664�0000000�0000000�00000011344�12614627753�0030415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_template-roster" ProjectGUID="{A3AC8D01-CD56-4B1E-9906-41A8BCC29114}" RootNamespace="mod_template-roster" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_template_roster.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_vacation/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021654�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_vacation/mod_vacation.vcproj�������������������������������0000664�0000000�0000000�00000011317�12614627753�0025547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_vacation" ProjectGUID="{052E3EA4-6BFD-41FA-9C68-C48CB0CDEC17}" RootNamespace="mod_vacation" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_vacation.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_validate/��������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0021641�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/mod_validate/mod_validate.vcproj�������������������������������0000664�0000000�0000000�00000011317�12614627753�0025521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="mod_validate" ProjectGUID="{C1D1D430-C051-4CC3-A5F1-E62788FFCBFE}" RootNamespace="mod_validate" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\sm\mod_validate.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/storage_mysql/�������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022102�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/storage_mysql/storage_mysql.vcproj�����������������������������0000664�0000000�0000000�00000014330�12614627753�0026221�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="storage_mysql" ProjectGUID="{DE396A11-85A7-4BD7-95AB-7325955F350C}" RootNamespace="storage_mysql" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STORAGE_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STORAGE_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="0" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="libmysql.lib sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\storage_mysql.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\..\..\tools\db-setup.mysql" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> </File> <File RelativePath="..\..\..\tools\db-update.mysql" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/storage_sqlite/������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0022236�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/modules/storage_sqlite/storage_sqlite.vcproj���������������������������0000664�0000000�0000000�00000014643�12614627753�0026520�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="storage_sqlite" ProjectGUID="{929E41F9-EB67-4F61-8B85-15CFBB11349B}" RootNamespace="storage_sqlite" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STORAGE_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sqlite3.lib sm.lib jabberd2.lib" OutputFile="../../bin/debug/modules/$(ProjectName).dll" LinkIncremental="2" AdditionalLibraryDirectories="../../lib/debug;../../lib" GenerateDebugInformation="true" SubSystem="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/debug/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=".;../../include;../../..;../../../sm" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STORAGE_EXPORTS;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="0" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="sqlite3.lib sm.lib jabberd2.lib" OutputFile="../../bin/modules/$(ProjectName).dll" LinkIncremental="1" AdditionalLibraryDirectories="../../lib" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../../lib/$(TargetName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\..\storage\storage_sqlite.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\..\..\tools\db-setup.sqlite" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing initial database with: $(InputFileName)" CommandLine="sqlite3 -bail $(TargetDir)..\sqlite.db &lt; $(InputPath)&#x0D;&#x0A;copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName);$(TargetDir)..\sqlite.db" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing initial database with: $(InputFileName)" CommandLine="sqlite3 -bail $(TargetDir)..\sqlite.db &lt; $(InputPath)&#x0D;&#x0A;copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName);$(TargetDir)..\sqlite.db" /> </FileConfiguration> </File> <File RelativePath="..\..\..\tools\db-update.sqlite" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Preparing SQL setup file: $(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)..\$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)..\$(InputFileName)" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ���������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/router/����������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017061�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/router/fnmatch.c�������������������������������������������������������0000664�0000000�0000000�00000014046�12614627753�0020652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1991 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include <errno.h> #include "fnmatch.h" #ifdef USE_CWGUSI #include <sys/errno.h> #endif #if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS) # if !defined (errno) extern int errno; # endif /* !errno */ #endif /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ int fnmatch (pattern, string, flags) char *pattern; char *string; int flags; { register char *p = pattern, *n = string; register char c; if ((flags & ~__FNM_FLAGS) != 0) { errno = EINVAL; return (-1); } while ((c = *p++) != '\0') { switch (c) { case '?': if (*n == '\0') return (FNM_NOMATCH); else if ((flags & FNM_PATHNAME) && *n == '/') /* If we are matching a pathname, `?' can never match a `/'. */ return (FNM_NOMATCH); else if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) /* `?' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ return (FNM_NOMATCH); break; case '\\': if (!(flags & FNM_NOESCAPE)) { c = *p++; if (c == '\0') return (FNM_NOMATCH); } if (*n != c) return (FNM_NOMATCH); break; case '*': if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) /* `*' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ return (FNM_NOMATCH); /* Collapse multiple consecutive, `*' and `?', but make sure that one character of the string is consumed for each `?'. */ for (c = *p++; c == '?' || c == '*'; c = *p++) { if ((flags & FNM_PATHNAME) && *n == '/') /* A slash does not match a wildcard under FNM_PATHNAME. */ return (FNM_NOMATCH); else if (c == '?') { if (*n == '\0') return (FNM_NOMATCH); /* One character of the string is consumed in matching this ? wildcard, so *??? won't match if there are fewer than three characters. */ n++; } } if (c == '\0') return (0); /* General case, use recursion. */ { char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; for (--p; *n != '\0'; ++n) /* Only call fnmatch if the first character indicates a possible match. */ if ((c == '[' || *n == c1) && fnmatch (p, n, flags & ~FNM_PERIOD) == 0) return (0); return (FNM_NOMATCH); } case '[': { /* Nonzero if the sense of the character class is inverted. */ register int not; if (*n == '\0') return (FNM_NOMATCH); /* A character class cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) return (FNM_NOMATCH); /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that is not preceded by a backslash and is not part of a bracket expression produces undefined results.' This implementation treats the `[' as just a character to be matched if there is not a closing `]'. This code will have to be changed when POSIX.2 character classes are implemented. */ { register char *np; for (np = p; np && *np && *np != ']'; np++) ; if (np && !*np) { if (*n != '[') return (FNM_NOMATCH); break; } } not = (*p == '!' || *p == '^'); if (not) ++p; c = *p++; for (;;) { register char cstart, cend; /* Initialize cstart and cend in case `-' is the last character of the pattern. */ cstart = cend = c; if (!(flags & FNM_NOESCAPE) && c == '\\') { if (*p == '\0') return FNM_NOMATCH; cstart = cend = *p++; } if (c == '\0') /* [ (unterminated) loses. */ return (FNM_NOMATCH); c = *p++; if ((flags & FNM_PATHNAME) && c == '/') /* [/] can never match. */ return (FNM_NOMATCH); /* This introduces a range, unless the `-' is the last character of the class. Find the end of the range and move past it. */ if (c == '-' && *p != ']') { cend = *p++; if (!(flags & FNM_NOESCAPE) && cend == '\\') cend = *p++; if (cend == '\0') return (FNM_NOMATCH); c = *p++; } if (*n >= cstart && *n <= cend) goto matched; if (c == ']') break; } if (!not) return (FNM_NOMATCH); break; matched: /* Skip the rest of the [...] that already matched. */ while (c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return (FNM_NOMATCH); c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') { if (*p == '\0') return FNM_NOMATCH; /* XXX 1003.2d11 is unclear if this is right. */ ++p; } } if (not) return (FNM_NOMATCH); } break; default: if (c != *n) return (FNM_NOMATCH); } ++n; } if (*n == '\0') return (0); return (FNM_NOMATCH); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/router/fnmatch.h�������������������������������������������������������0000664�0000000�0000000�00000002645�12614627753�0020661�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1991 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _FNMATCH_H #define _FNMATCH_H 1 /* Bits set in the FLAGS argument to `fnmatch'. */ #define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ #define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ #define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) /* Value returned by `fnmatch' if STRING does not match PATTERN. */ #define FNM_NOMATCH 1 /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ extern int fnmatch(); #endif /* fnmatch.h */ �������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/router/router.vcproj���������������������������������������������������0000664�0000000�0000000�00000021625�12614627753�0021634�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="router" ProjectGUID="{03878EE6-16D4-49D1-BDCB-B367FF14B876}" RootNamespace="router" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib ws2_32.lib" OutputFile="../bin/debug/$(ProjectName).exe" LinkIncremental="2" AdditionalLibraryDirectories="../lib/debug;../lib" GenerateDebugInformation="true" SubSystem="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/debug/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib ws2_32.lib" OutputFile="../bin/router.exe" LinkIncremental="1" AdditionalLibraryDirectories="../lib" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\router\aci.c" > </File> <File RelativePath="..\..\router\filter.c" > </File> <File RelativePath=".\fnmatch.c" > </File> <File RelativePath="..\..\router\main.c" > </File> <File RelativePath="..\..\router\router.c" > </File> <File RelativePath="..\..\router\user.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > <File RelativePath="..\include\ac-stdint.h" > </File> <File RelativePath="..\include\config.h" > </File> <File RelativePath=".\fnmatch.h" > </File> <File RelativePath="..\..\router\router.h" > </File> <File RelativePath="..\include\win32_port.h" > </File> </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\jabberd2.rc" > </File> <File RelativePath="..\..\etc\router-filter.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName)-filter.xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName)-filter.xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName)-filter.xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName)-filter.xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName)-filter.xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName)-filter.xml" /> </FileConfiguration> </File> <File RelativePath="..\..\etc\router-users.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName)-users.xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName)-users.xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName)-users.xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName)-users.xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName)-users.xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName)-users.xml" /> </FileConfiguration> </File> <File RelativePath="..\..\etc\router.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> </File> <File RelativePath="..\setup\server.pem" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> �����������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/s2s/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016250�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/s2s/s2s.vcproj���������������������������������������������������������0000664�0000000�0000000�00000015760�12614627753�0020215�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="s2s" ProjectGUID="{457A89D2-B3D8-4FD6-A2AA-E111B1956E90}" RootNamespace="s2s" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;UDNS_DYNAMIC_LIBRARY" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libidn.lib udns.lib ws2_32.lib" OutputFile="../bin/debug/$(ProjectName).exe" LinkIncremental="2" AdditionalLibraryDirectories="../lib/debug;../lib" GenerateDebugInformation="true" SubSystem="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/debug/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;UDNS_DYNAMIC_LIBRARY" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libidn.lib udns.lib ws2_32.lib" OutputFile="../bin/$(ProjectName).exe" LinkIncremental="1" AdditionalLibraryDirectories="../lib" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\s2s\db.c" > </File> <File RelativePath="..\..\s2s\in.c" > </File> <File RelativePath="..\..\s2s\main.c" > </File> <File RelativePath="..\..\s2s\out.c" > </File> <File RelativePath="..\..\s2s\router.c" > </File> <File RelativePath="..\..\s2s\util.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > <File RelativePath="..\include\ac-stdint.h" > </File> <File RelativePath="..\include\config.h" > </File> <File RelativePath="..\..\s2s\s2s.h" > </File> <File RelativePath="..\include\win32_port.h" > </File> </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\jabberd2.rc" > </File> <File RelativePath="..\..\etc\s2s.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> </File> <File RelativePath="..\setup\server.pem" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ����������������jabberd2-jabberd-2.3.4/win32/setup/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016701�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/bitmaps/���������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0020340�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/bitmaps/background.jpg�������������������������������������������0000664�0000000�0000000�00000031327�12614627753�0023167�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���C� �C   �8�������������  �K�  ����!1 "AQaqu27bv#$36BRr4CSTUs�������������F� ����!1AQa"2BRqb#3r$C4Ss� ��?������������������p,s0����������������������������������������������������P!egl?w���������������������������������������?i|ˈ չfv7ֲzii{Y0f{^Uq.1n?V^\"0sxA{JR4m:}TCCsʷE>+�39T7&myԘnʽg,ӳ]/ /d9=~�Իoo;AgсݡۢUqm1mXpI/T-G/qm;}[v\-W#l}DŽ}o[Ԭ\(tRήVMb)MQWE.ٮ[4d^`����� B>~.3��������������������������������������=쉏G8jGvDDꪪb5uqY]Wglius7c2IKmG44Q2Z|fQO 1|st%烏Bm^M>Xog75%ݛd'2'2b<vrݒlFO8kG>5V! ���̲*.x~QbMdr.et.jzzs1acr6:EnSTEQ{M[fm%cTdծk(vO$R>gyN{+\6^ f*'{'H]޿v$iBښF5|zʋU^bR[Fw=r zD8WWst����p,s0�������������������������������������uV}/ԋ;mx(<1Unڮ{mr>1&X﷛q]yq{5 $]<yXU艺:CnW*ݦ5.3gj(SN|ڳWS<G&:qO>$}_gSMff%OoLh<{Chor'͝3b<GP|ONySiT M9mcyG/lcȍze V>+�˗?*�>�N?h}:?J+du˿dثij!EzG=·{5ST~}M(\~Q? =j|y3rEnz.uSkX]{f+M20&#&+t^~6E y]Mwٵ/#Y!UszPp7ߴO޶2=3uަ\z*飄bS 1܆z+KW滹r+\WkV],UcDWnq?1:E_m9ZXufE5(˩Er'Y"Oۿ,)\+}_G&t힯5 3Ϯϛ_wW_)sv��(~�������������������������������������7\t_WmEWWaWvw-vLllkb73sJ/[u_+ (ZzUw^c[),V1U+ (i.bamUzQMƳ3"G\&a 52_dmj;eGnƽ㼥yVYN>\8oYpy�Lpmͪ����p[U6ۭ [YoC+FVШ|4ٮ+f Tê&|6[558[eFӗ{5of|gZpG佶'j ru?t}w<V:}SQurNsEkQSԨDk^n8i.ZOM:NtZ,{4]ٕB5U?ul<0e|o:nFb6~?z{LlP��8eQvwp9��������������������������������������CUjz:)znױ鳚TT4Ls)VUq1Z[!c^#2 犍\yU/Nmx<u׿ԝ/H ~iiQouլϯHҝzFD������&mWpJExː[o[վD度/{ڜUw<ʼ5>*9stWӕތ?O?U<'Jۭ=|7uDG?3 \k;&o/3<ۑ\8[_W_ 4|F&{_Ol^5pڮ+]㚞$R1}kP*c~\Ҫfbccǽ� B>~.3������������������������������������������������6ƴIb\7>v&7h{+))||=W y5q;#;b.ηviUTL%oqUzsto]:AH_.KEZ׿zIOԏHwl9O:e߰fq<LDk=)W4w<2 (=a������������������������������������������������83(%i <M:%-div�Lmarw9w&|K?53cLcriOXEje5Zkoz*E_CTz~Fm^#ZDŽGӽOX+`TnA>X~.6������������������������������������������������õ 5\:f6+Q߮S_]刷mGlL69F:p88jZ_%l9I cڿ쨥Tؘ;Tɩ:5D=uG-TZV塁Q_l|z!Y\e# :~3 e4 @6Ϥs�����������������������������������������������}Yu_SZr6 Mӻzgx| sҵDwUk4XIu'SJmj3{l56<tU>4~5SzW-]u)?b����������������������������������������LjT~/g,ITGn5z+)Cn0zxzzj;p5NτGT 9o~8iOk\r/~weeO+84V.U5i9Q?)>EbaQWlyο^,kʝ7Sv?+^�Bm(lܚwo[\uk<ǟ)<,嗷u֊?)̵jŊ%7n.DH_D}HmJvErpGҚ{艘ѕl#OģyϪ>sQU[J'iήj/+Uxl?JV6K&iMZsQ1TG;"x3͖.i~L~<t7 w!QS ,TJ)gX&rΏ4SW^ْ~G76UmUCET�Tޯ~xi-Y2iZbx8lxlu&*M�رPq97p>NU<tS?� ުq:e_g_w����������������������������������������z=ϲzHbzXt~GתidQL.eִ}RFG nF:hƢ-Xɢidh1WګϾ^|v,acSqL"jNSq�nfy=NTD\&8Sٯ+vs,6TU=׻^nsmmk涾teWtEu6پ/lۚtu:Ow혞 &eչ{Npn=S햨I^ӷ;'#ջwAvws*8Zjm75gNDZqⲚio_nJU٬iNmN6=bgfm_S8]ʊ{ 6yy}VWE{79qEʣV4W'ħWU2ۤZY%4H|HcZꪻ!_Dkw.Sn#CoEpif`r՞..jV;jӽꅡ,o>=6o9g]s1WMJ8wrpX*?�����������������������������������������X<[=ةgM݊qK_W颯erlfc,U<獮�L 'LJw맲tl!D^+QFlbmj'UTX<es3N3M#Mi3,lExjp߫޾=_CcĪմQ;6=gdYm]\=*1&SՎf:SzkC#-I%e\sKXW+#ʮqZܪ{kX33W]8\c׸[&*`̳s�/YYsя)UrN֧{TkZ\DNy޽M&Hn]_qa\tG97]/|@j]3vvX7,OvEoD;Iy_]F[8wf}k;;ӆ|ү{=\=M[i\U5fMmҢ?lnxZ~3/L_v }m}[Uʩa]̫6/����������������������������������������42mEQOV%CbW;r3V߳UDULnUxLƑ<_c;Ek-]:LvmMɖm>n&#7-,,%>:)^b~*�]J|{X9F ꪊcYƠպSY̒{m<Y'NC<MVivGO eoM 7pcZюϯl`6bIke5Ω?S[ܟK[9Ӈ7'ʽ*�O*}UwUb&ʘ쏬z/i*2Whl%TV5<O;ֵ\O;iL\Fa~>\?<#gG|q_ŖC-_XPIW#wjV",dUXkՌHDr`:?v|%zW<jBWHKuGQ5|.C#=trFs kܧ=fvw8gWdwzSD$ΟzW%JLz dgȉ$U{nt,|6yCbuν\{i .W]؀��������������������������������������("ibjY^ֵUU{4S1SO*o9'tMQ}~X(XYR)^oipW1~#jt庩용^61U5DϲZLtlZYħ}ȱQE;Rӣjwf�*b8ξ\rƘ>m-865=Z?Ss*"\}|\kdnuV\FF~N٫-a)ֹrlc<ȧ=g@@)<B _PHce#th9Lroj5IW1kW.[l`vn޹>U�M=ǷY wPLZNcLv^OWwz2\Ck6o ~u|#ʮ~T;H=\#Bp1.GM{TlˍO.4OZKS;pX+xJ7(�668LSLy4S9-2I\xmwβqX&���������������������������������������:rLKUpfMNsc8}RrÑΛ\[O'Y^YW\Dݦw;bgO臡$qS|-=mK ̞ĊZUU+ؽ3oEV責ҬzO<z@K;G޷N&"KU=SZY/vl,7[MeLxV1ry+RNV4L1<cO*5pq5֮4޳*:{Kqa5M([oSwEr;[}QޘlF]<|Xʽ{\%y9FL,U߲;BYY/W9jtkZKdDخ^sUS˴r a-#=3<˰>Y&l~j<IW3;}�ƾFtq˶~=?OPmK|,S_;t9;ı [mݎ-夶ƌbz\;9ʮrUU&Vj#HsVabs \rs?:\z0W5pW5p;]V/@�������������������������������������p5~iF- Od[mխ}5l;xT]aE_ZLl^M[w'#ыTuUL{:O8|K=+MUag7w\#o+r|蜼nZU\=M.XJsQ?:{*<2r=ɼw$Ҋٕ5M.蘒TMWwĪrNWnʳzW?W,m ~Ɣb9W_ʮqu]iެYi[h(tɵL� E3eާ kNʹA.,]Sr.~2' apI97 zV~ݯ.\ext醳]_y}x+讖= ʒVO=7k5VTSҚ91/YsEfɉVz:LwM=%ҳvҿq~1�re�OϑT[egֽGC]^veo3-ԯNh^ʋ�ndyLSL^gwYtEZ[ʣϫF9UN\IJJ&J&J&b߿guf�������������������������������������*bD35󙾎%f9i[u'uR~G#]Λ|veb&&8iꍔ؍{wmf*鹧Nci:i.43 # ɨ,m*h25?*ysѤnɷm f6qnզ]3SSbfOvWW\Gz/NSUֽU_3cM!OL VQWStl�MػQڋɫٸx:<_bh_KW&�iZc_T�Ĭ7J{5ѻvm'S_μ olv^ Vu֯O|˗ga5�_jؗͶ.9Wr\[]W"/{UH{Oݬvuu5cf/ 7p{"wim{q{Z VUUwힶ}%LWTuGruMuؘaӃ?پgwi3zMW4TSDF8lۯf=zv<Qӵ|ݤq=W?jL]d9x;{wU:QGf% l2bj2(؜kS""w"cff_p|I\I\I\~|O,nl�����������������������������������?c*5�lM1'-qZ|N߲sƫN#\82ڹObU[_Oƙ&LuU <?k Y==]MCKVK,^hC6u<ɶɷMX/_eQMj0MzoGn<*5'gx4}\ş[F֧VmOmpIrc{'B<T̾W>5gOGdC\/X|ZdN{nG E).zPf}mg?s�鵇IZPӺd �3fT3fyWO{;۝*މT|篚#heӵ?u\}yҌ%�x6^ڎ_*lI,㑊_J1uXj>,걝a^ioۊxL~ba�8ą1$6Wd_9Cv{�.=R鞙&cg�e;W"&J&j$j`lܖ?������������������������������������U㈮0\23<`Mbn:Z~mCsQțl`9oD43G;OFOk٦wcY](tD:LvÖS}Dm!E*dsӤ^dt}Wv.QG:?=R6eq[%ڪ3jpVʺzcIѠuwJ]4Ywi_<vt{ڞf8sݟ|}Rݞ0iF>O-o_lu.)C5z\1ڶO^~£^ȱVWUccƻ6ToSMu}`K4Q-oofb;\lqV <)viDkofU~t;YJuy{VY$]1zh߯{VQnӯ]]ͤٮ!izo1*NH^ݻz*؜K9٫6hxݣnyoMqiRݥxӸGD\mU/Ez5DJ1{c.KLunj W#W5pW5pUP0U=wrrX&�����������������������������������󪁂W5pOqE05Hhy1šj&cQWC܎{7=rM"KUʦ}qџIpVi˳Ҋx[m]Qt~j.i{.73.=մF?mӴ=FnE޻ZxU+2_~9OdĻ^_ ~#t7[Zl%ʾwuc{_a6^'9}?B8UMymȹO_\woy5{w`ݤ�mA2SvaluZ^IXٿUleL�+]ۧѭ?WM \nvM uURco=QUE1,ٮQEfGd5j_p0ْdy*ih;XbsXEW٥<+r8ijX^k?Ig[4[ttY:Sˮ!n 4ȵ{wJLR^ibkUZ͋"YݻeµZ3ۢOtcrї(1LziNZΜgBܫ4M\@* + ]Lܶ?@�����������������������������������JM\I\iMU�H:r>Λ!z[I(ڨUToo0Y}O)\kL^igƢx{cIu˨~ JQWZ{M OGR5�o6btt+sJ/QN w#_"WK[ͷE/m\1tyLJ;{+nVboX"eq'hjIB07C6 8D\{0Lwj=~<\G_HJe{ZҾ/Towڇ9F;>>?-EvS%~ɻ5z6m[vÏ g6*$sk �,4hC(zQ+jr6oq{Mr"ܱLMǏT|#906"j&@T @ + a+g{P6�����������������������������������1\M\M\M\M\M\MT W5pW%pWe2˽ch����������������������������������� J&J&j$j$J& T 5pW%pW%pW>_k']�ۀ�����������������������������������qpW%pW5pW%pW%pUP0Uj&J&J&J& _@6�����������������������������������]\I\I\I\@5P&J&J&j$j$f~} �����������������������������������W5pW5pW5pUP0Uj&J&J&J&J&J<杮na'�܀�����������������������������������ppW%pW5P& `I\I\I\I\I\I\ Ӆ,=d�����������������������������������J&j` M\M\M\M\M\M\I\@kט07H�����������������������������������\@` I\I\I\M\M\I\MT L�zuY?>�����������������������������������[*5P0Uj&j$j$J&j$j$j& `r1}d����������������������������������� bM\M\I\I\I\I\MT *%pW˴w3/u:�����������������������������������U + + + + + +T + gkO{07�����������������������������������\I\I\I\I\M\@T @W5pW5pWwɳ?vY:�����������������������������������N + *5pW%pW%pW%pIW|3e@op�����������������������������������4 + + + +*Uj$j$j&J&fu �����������������������������������W%pW%pW%pW5P0UP&j$j$J&j$j6&~u �����������������������������������W%pW%pW5P0UP&J&j$j$j$j$ l=eې��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/bitmaps/background.png�������������������������������������������0000664�0000000�0000000�00000155630�12614627753�0023177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR����8���vGg���sBIT|d��� pHYs�� �� ~���tEXtCreation Time�06/14/07Qk���tEXtSoftware�Macromedia Fireworks 8hx�� prVWxXۑ0 M9HrE\'N;j&dK:Bg@ʖ-f@~K}W_;bu߶} Ǿ}u_x쟟-`]c J ?#G 7; �~^>�r{�r˿ _8gV4,/D 8KT"p7\@&uxA3_n^ӭYr1)ua:nR< ӀPV`64-kS=sRճ�}q~sk�K <t 3@�>=(;v㬃=˪c5 �%|?:>(�^_zE?vo6=Z t qw4V=WqocKN΢?/s }<_ 9qf$(2;H УzC@ :%(.M-y56�GDoCZ1}~JͷRYRV_M<NgxOoMJm! $^UfK?r=oSUr�6�F[h@N,ݐo vI^;H,!a&>,GR}^\: ?fLx)}x܎{_ @ @ @ �[K���HmkBF�������������������������������������������������������������������)3��BmkTSx]oHL:Ĺb-jYe{"QN:h:j{Y*R$ÝNT`zWUGv9jAǐ ׭j%/[Ԭaߟ\Z=@>Ot.|4wSeK(CUG(#ȹ9!GSBDJz6{L-ﺓ1vF8:'AQ!My%l<yk^ ݣti}g]#Kw+5hhʹN JpSDgI !(p?z։vC̴Uavc.ww316 lT)6a5ð1h&cx 0x iP</T>s}%`BÄne@S,4N;; Bۖ@v,ei8 e}uLxqG-R,5\5%Wtަa1:ny[@F] 6氹!,YSnV{ĹU6<B"to$9(@1 %J m(=Ԣ6�UM'}8=ĥSq6.8bY !F�ROV!5E-`LInip}`  g,}mE8}vF1%5ʠQ4*FeШ 56f{>$| I6@ �|DZF:CHg !!d2ɚp"~sw`+e#)@ju>rE( ϥ|lý(EȔ);@çf65,>o-!I՝X mT ]1!Cn$B2+.de J�dZ m VSFìlH pR ZPMԲ3L/ϖ.Ͼ]p)E&`udyX5q|(GAƜп|!pMCnjDm xiP k,eX13FfnY~R6)W5ő\$ 94jN'r6$$sCk3K D%E0w"XO;w-�S��W}<fJ#2\(JI:tCcKg1 asƈt_6I|!]Z7Kf"XȺírJre2lвTf/0Q x7V<Xg(CQ)&CF\D -�HIx6<L3Z 呧tP,ŕg9[dFE=X#Cs84Lg(!۴ZρIw#~5V0l5k'$#7d=sK0"n>fcw@f;n#\NzSMLw]榻3!%7nPNQ:^P3%S^ťL3.݄0>u9 L,qgMShu+2LC:$sWa]Z`vI&t-I Cq#K<_ )@9C]BFܒf= `u8vȷk 9CGj^o<Eq녎;Hq?r�1DgFS,J[&2)5(%RI#=y{I'nԹcpIJ7]$FREp pm!pYXR$U>[+)s)�4 ko(',jPHKSV1@;R7hۧ EVguf S4"@F (6sɒ/z'1Vs<uG>"h~Ǝ�-.CwҶٴ`,b\I{9@c=.C٬q!rU0AP&aY&NbЖ*0C^lHA)6Aķd+sC6iVU_j`.E\%؅.ia e$s a-Q 3"g PД[GSCБ:=<0\EJ;5fJ< tg�F,lʮb("yVrz'omv?u+Rbf8lйsfr[;S]({r"ٓ)N r_>]tv CxhVxq~4f )ä<%[h>b;7~OH c~&R,HX1KI rPZ%,ky6G扐I30wK;3to>ٝe#&iPL;ikl;2)2SeCZEy4+eA2{Ai+_Ѩ|AGbaQOބ̗'p$FR a/m[y' ܿ$m$2&?^$`X_=`WσsR mԝdlޗj rkc(2]<H=s2vc YNq(|w�<ͳ;g L׋ӸW1 cH{ `p46JN9E5.#ړ@7‹Јr֏b>-tNzڎ.&#J>^sif+CvEEz=w3Lv܋c~c9M)%u GO?#\ާpM!_EI;T~ _W7Ypw+VT bYZ߿y0Oy;Z&,iǷ#|_քbW4~n=<+s`t3*CN 3b@deNs)GQQԫ(Zk:f['N3Qd3+ʕ^;梼i27VIgGomVy?r,F.VjuɈ΢ܙ/GVVj QGHӔ0j9P?[8y#+qD9Z--.eS/%V?:v:n9: i+rp,Gtg9h6b4U4+^~V?M_ZcFqE2vw"0wWr>vFceh'\ F?]_bb[z⛑f& ا�v6}c+(i7@x/ƮFGXa$2F>d'3bMW%0|)r1g@o#"ȶ_6>8ݙu5YYUkU5G"xCl %360eL[&MZL'ʵXp4OtaSxɱG{{h6vSh1L-ڠ^iLMߴRCUKc5Ggkz o#mNCQUg3$mYfR$bOC=8ޫpiF!y-{?uPNzNK>_;QH\.3Tv[f!6\z`&Hgpݨ_`Sߴ<@K=/f3x4_)(5VwSlp?b|Gb]4z<sN:{v8eЋKG!"}ߴ&hr߿]Y4+5oΦ@ CoQm[EeWvv6 з+FŘe l*ҭ9U=d߽vz׎k CɌt> 8:)^׽{ܞӡmTsxuJZP\Ǝս{D/9TZ)SFS{#KtܫAJ9-H<uk6F|A͟o(y/V%TaJΙ+թ)PgZm@/ J{K$BETHئw]H+/>aG;DBDՊz+o#߂޼`xJѦK8&d_4;m* s}Hg΂\-~ < Y݂[O-QXmKF4 YX�.ќ[4ypJ YށbbN"4j4\Tx%S9VX_m˜LsNx{]bhƟýd;"݉\%sps%W.J:Wҹ9V$y8* ]IUKhЕ$t B{%+ r -JBW2 㼄iu]a|ٕ^+]Jf~Ms5<-̞JFW2z2ڬdt%+] ѕ$%QIJBW:N&witҹyWI]:ϸsyWI wts$mλJBWvvU6Hj]%+ GBW;*};dvٕ#ŝw 2yWJF||;;* }$tЕIB3zs'гw.IZ@~GОi"z~/Q{>xYƙt1/sH{!?$x(VxPkNa^CkDsCmq#Z?p~ø.药~!pL-*8M[.?% sDL} ݃'Lѯ[Bf%+ ]I*V\ `&OQ~KԙP^3ً�<1r$?$wM+Ẽ_dmci FP>XX zx9I'˨7z~&Zxƞw?(^͖4JpvlbJ>h55|[\ Ftq Q,dIdUS"eR%Z w:sx eJ|z-켶L.^4rIr6̒XW42!p5~-!!qG>J]:~ ل w']g&_2l/Gܱ*U[3墴3ބ|<L45}: f : xME> Jy=d?x9 7"vIb?e )8Vѧ?)mOGo?9):ͿJC@)C HDO11: Gd?D+㬇z=R,?^ IMFXV: gQJSoܲTG$UcQ:IWcMҌaIywnzzi{Œ`vO,v/616g3ktn(4q >p(vq{'9GR?C'ͷc5rۆlDz>7ҟEtI|8Pu|X $ $5p#xyjmWCEwÍ=%-[)*o*oyK=:5ҺH%YݨlNt߁qcnw؅?JG |>Ԥ58,Zkȷe5X<P#_-g{f)>R>ӪlQ%J`}v|@Ѫ&~ . 5.r?!G�}ɝ0+A&IGcfԱ NR'k={+EC\}%펟Rk ROyXmy|'l+|ɇ%pA@]oG~NY h?j}&iqD .H91a.J'Қe)XهzWkк2@/W#ܸuw} q s*S#_{#+Q\Ǻow3Fo>,@!k&93/$Zq5ҬCqǪ4nW/od2WGY$_R]cОҩ0g'ڥU#sҼsrW? Ed.2yV2Mo |׌Yg7rpx8 Џ=̫e'bF9M:$i_GdwfztSz=qcZǵҐ mrJ1^EtAxȭ^DR}1yJ iN%z KV?Ik^T<_&= zx sLԚ;"c:]`mtc]qZb)Sdyƿz-|>oOpwq] /|s7Oޮ%:걵hvvI٥zH/ِ/pmrq ~=~v|!_kLTe6CY&i ?wź~ָ!h<sv&bcѽD+{hH46|cgAhutiF9WxJݣU~歘>5Jj6Biug~؛-g÷[+Et{iY. M]jR줸zUy#pf9\\ o >1_$.VK7[T_,u#!#q_Odu  HfoQUX r !6.+vI&M.<2SˇNS5hO(q'Scd# $p r۔PsJǼ6}P<f7dZFAwrc�jcԠuM$:6:1(iM%&A;Ov/#Wa3{ Kplm66v_o4vEEz=w@y%Q@ZD{.۩_~{Kq5~]>Sox.Q(1�"[d Tj),?As䂉z 8;jpӾh5|5髬r κ#äۡo]q]ʂF}9}aۤo-J\hf %[XaUw1Z.z’.obwq>6wAsw,Goข.};)&-t\b{.AfAxL27Ji{p֦G-(7R>GG$?SS?L9 #~G0?ÃqJtJt6#"iG0bYd^gg!oQp|d^Oc2J|h,Q6e�prjA|3$#dCc l+.ȉ}iq t_ !f5[{N9fu g'm:|:vnhԹ촇lvz:Nrritjĵ.E|c*=]JO3zR38#PiOpWtmd 76\m6ܩϴZM/pװ ˶ZmۘЙnC{P]@̈́XSw̨Fp@kՍ(b5ۜچmmvT[j~Ay!D,Ht{.3x=t+hAurLZH=4I tfPhuY|?S@UGL|h*K4MYI]ǼׄQZ..g>qg{@F*OWא#&$4Ñ _z`;Vh;,ՏCsl5,c :?R�v_WqT~0xۣ~m騞:#;~^@s6m-4cAvf4fwv܃^zD>9@}KdhPEo=g�70>:S~I133ؿ _}"92O\2N]E`»-���mkBSx]N0�Æ WM- 2*5X|DZ=fLc(F? hҶ BLrGpodgd/e>f 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y X��mkBT�} 8��������������������������������������������������������������������x镫0 @aʣ C/Rn˒-&L›O6 ,qb߅8Nq}NrUvVCn+/qxuzG>4:d #{⿎#dv}i_em}VT?C-([A-F9O^NS[w]C]g>9_m6$>:{^G:N_v?q֜$sus9.zS�py{<ٱ|/{z;-Y3![<kAɫvf9l ?'jvLPDd}EN@_󬶔ےuy Zmy9Y@{K7٘>K;mmٺ5#ֱcZd^շt g۬峊YbSYۍz>NcN7rF1|vMirZ\v3SecY#5Ǚ嘳ܡ3J^8+ڪ태q9w?Oߍھ֏ZϞIGU_ږoS5|㒻+y孽8{5#q>_לٖbb=Hܧ59cR.]\?}>�|з>oG5o"̍^־|"GeoE$||/ЮUk#7rN}|Oc}^Oc?#3~c%ԭ}(>>}<$*ǦorT{ɿ^\W7I��������������������������������������������������������������������������?NWWu*��mkBT�~m��������������������������������������������������������������������xAn@ A==?wN|,i(z9ǫ_ݙw;N{]lvWw;϶~wͮ{߮{߮{߮{߮|u~?6M64w64w6wwoCsmCsmS{?   M64w64w64w64w64w64w64w64w64w64w64w64w�����������������������������������~D ;51�� mkBT�W��������������������������������������������������������������������x흍8 FSHI!)$FRHnw HYx3ꇤ�saaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>�c=1Ow y^- ڶ,Xz�usM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-�(W? źvƔOʙRv[K?[A}?-wmՑ}<GcK1}uxLzަU0 0 Pc[<>g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8g�ʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K�֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL<?<nѯn!>=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-t�ĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3� %���mkBT�}��������������������������������������������������������������������x �� /#@H���������������������������TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUujf0ֈ5!W��mkBT���������������������������������������������������������������������x흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:s�eQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~<Vrv@>!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fz<AǏߊg_ly=Uy3= [6_3]U_k]]ײ2;j->t|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"w<Tk.\rnO>U쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8�֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?�v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ <FVr2nlo؍ا|mo'qbӋr`eef6 0lzsA_x7췣*U}R%+C_ ڟ~I\Q~ky#_jo~DyU^`5pko?:ˮCw>?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}�7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;<sy}ڛk}~|M'8CTo+[WUQr'\'tTYwz.D=W|~q=_�yMǏktbS=2|ұyN_}Oe摽ۏtLS6q`Cjf3#ܰ?z1 H]\"W]O;2'@@~tG:{u7m1Q]PWV2Sz]ϥzs3]vxwҞ:ڗ>y`$jw��ymkBT�6��������������������������������������������������������������������x횉m0]HI!)$FR?6c<lHٱd tC"+RJ)RJkJ߃L_SUn7ss~uU-Uyy9c/Juz?i>>>~�sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{<d6dn;Qm{{5$iѦxg<$"^%=RJ)Ste/֔ a};k_y?9Ԛlz}m#GKk!k(9G1z,Q&liV濊#_<3Ξm$^9g {9&w&:˙uf֚R:ֽL+mWW^z%I2loZf?k4W-# ?V/c^!!{u̵ʴUٷAGe>G}?v✽3X~j{zTAO^ʰ>?sy|G)P</11~2ў׆R/7�Ӿsmsr"(2cϹ;~u-)}<U1g:apb5{3(k!m'mʞ2.~[)}GκbXELp–aԃ77Fy0@ߋL?󞕹Khi@=RJ)RJ)RJ]M;;j;��SmkBT���������������������������������������������������������������������xi`Qqqqq ! COMlS$I$I$I$I$I$IqO9˵wOo]ss,Խu˲<^0 tc}av=7_{V9z}ٿ^s_y~?}ez۶@wE՟k$I$I$I�����������������������������������������@? R*f��mkBT�`��������������������������������������������������������������������xn0 @`d<, )0=I*?4MSM C~tSoG7<ƏYuMۏntȾfۏnֽfۏnֽfܬ{ͺݬwo^z{5+Bo V3vU ]5;BoVN[UFym|}v3ވx}2ޘU5;>+Jzk6 Up[37g7gBol(l zT0v :~;zS'{X%Ct/[%C$t?e+dB?U+dgh {GCSBL!?2eʀ` G΂I[!Y 螤29 '/Vplľt+3fZ!gCܕp'k&t +dl{To+dc wt' Vt oнgZ!?gHgx? ޘ?c?:Ì$t7V04t7fv!?B @d7:. ;ܱBV^tN ;\B@pe':Cd7ά?{DgǑ2DZ z} [!CՠBgXJ+dȰ* 2*BB$۪{7!:+BA߂*-7@߂:;зN hџmu"v!?}.DW Ujvaf_zs50/ݘї\nKoj7VOzۍ'UʝvN?zcur]ҋŮ7u+g}M]Q/zS7sԇ[ڝw{oՕtu ]zCw;CoWU#fU ];BoV͎ЛUVUU5;AoU&*Xw|��mkBT���������������������������������������������������������������������x1N1D=:77D+$| J/u냾;H };Y6-,};Y6-,}NI['Jߤo։7i$[v-Z;A }ھo^kRj{MHYs V4oT@m>oS@3~s{oo$[tMNNҷ:;Jlמ$}]zMI6Kymlm{6~~wvjn}nn}u{՛~^s6?{�����������������������������������tR.��mkBT�w��������������������������������������������������������������������x 0 {3p!ەBzlO'-mZy<.꺮_O")Gs '''''''TjH-Ve " ZY:#E#MH7d}M7]VcZYO=g0דJ~ƞ)P+ܑoqvgȕzIV9tϭa%ZYhn?==DE?>}=FP+}uޤv]#"{{{}iB,ˡV/I)흞}sGX~^I;fVYںz`�B,ّNzktkX{F&%kZYR?VP{F8FJRzz:P+,e3]{ B,Xje:O⿭vM;N B,Ξ^ٿ֔CEw!GX/ϧ=#B,ؗT{Vy󉏇P+l?Kgkg=O{%|N?u^İ؛Zۮ(ח5"G}g/?3N^w;A=lSpyza5_^6% Ix()͏y�$ nA"Ix:$`}=w/0{ZV{@ːjhҾY-C3=%]Sm(jeIV -K ӃkJ1:=Hƨ$ZғkF9ӿYB͑z͢k6VP{nkIҵG>VP{cAҵGV$W,#puB@,i$k.B@(i$I}s\%$wϩU^H.S5y|SSz{ҧ]_ǧESޯVOɋ_{_sSK2Щo��mkBT���������������������������������������������������������������������x흋 DR�rŰ 8~H0ŞREy4 wx<Ɵ }Wwe9' =Y`s_Ozד,0d9' =Y`s_Ozד=-mm jVg.*z߶-mm )nx1Ne=NFnJX]]3k覸Eo5]pj}SF"oo_.SmIvpqVO{#UgUd>߷~+b7o3eue?w |_G8fNWdKc/{_kw~4+?(~ kr ct? UaHa eN#5ߍxX6pm~׫ogo0ݘ]pcec68G\A][?Tf|\ro|K;>K>.{bqkXCF<)c{9On/}_yӁ߯I8~z^!ϐRߝڂ7 WÕ28 9TV\ceCW) C?7ە. RsD|uoiU, _T#+?vT[TOw3 7|/W:<]Viٲק%\;i{'$Ik$2"ςc*ueg�*1Θ$<cZu ?`+/{>?Re/}SgriO5?X>gK1fO];�[_{}=f'˺Y痰f<˕q6mcV^VyU�Iԏ\1/y̬vaReb9~mR_W}Y߶-mm o[ۂ߶-z']Y`s_Ozד,0d9' =Y`s_Ozד,0d9' =Y`s_Ozד,0d9' =Y`s_O?[[J7J7J);ǧ?Hwuz࿝gCwoϓq؏OOw|}YbwO[�i=P:_aec?Wѳ%6Ou ҧy.pҟ>y _\^L8UP#鷼0,{qNmd+|~W~m' OO˝SF. NVS_3]9:!;Y:/柘*owM*i NuOP12sH?1G�?;ƽ`Lpq8GW1OwG~ǖm^rW3q76P\ڼ*6oו6í+Ik}yy=Pk;A8uy|y*<㗮/I2 yϣ\ڼ. X :v53Zlz/;qky'_GZо*K=RKRxjIZKx/KP��qmkBT���������������������������������������������������������������������x홍 F)(^aH)͊q99!_!džldžldžldžldžldžldžlϙ703ɿԗl'͡wf~3d*6&_Bc_뼳B)?_+qOXćФh˭NJS֕~)iB,S'Cz&%~Λ2g%#շ_CR<[z'쑳Xo6Nz?1K9?ʊ*}I,99o/Ƣqk@w\2u8/M XMޱeۺq3>q1˪ZϬ*R,'̍{{Ox/9S %_knm_ѨurϷKOwcƂ)ŵS8O7Uا6mlgcYB{6\t[ҽC/̙uc3ݓvm]ֽ|(}8z0C?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC?6 cC5yk'_xy eS?0wsn'ӿMd5=ݔk[cX9O׵eyKتM/?4-fLmcw[^7rnwv0_|OϿ6ռ=ĞuC\<v;.ouCsseGew/_:}!yL1Hɛ_qRRiݮޫ,=צ{vfڸFo\:,1=h9oq*I}�/bIK>[9qjo"|䝝v3_E�dž=ᙲW̑g{_Yǽ\xO;}a"9;9Akø_?H>he{s:ZGk_ L{_|<Fk^ki׸+BiO��*mkBT��������������������������������������������������������������������x}+(H,"H$"#X$,QԈZs>U{ ..T}6�ڳ-F`p]k�߅~b  О$wݓٱ|sCo�A+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ<Qq  +H} eq~~[).5c6,muO9p\<//?N:M›p) Ĝ-2p'uKq`_/64<~� 77SNBQ맨uM{5%.BNɊ k: kNm9*uU|2%;]Faג) RE%HWc0Mg>)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(?<?-1$pO=�x ]<Jt¡Vg`|I,<丕}FQj]o%[Pa6XY<?Yoh�F067ၭ6JFG[wv)7?,@w nMǦmk>?Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($�Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:><M@J9$q]�}=H k3鲺tQ=, 7߻s >36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv<gz 1F*qm-; I�7 ?O(Yr de F ѥrHaۡ>�,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1<u}E Dzl$H+N_2scۯ-rHV.֏'(} o :]謧6Fhlw@z{6P_?  Eh߹vK /B"Mh;бo)gRm $5, Ex(?:gU뵅F4 ߹E4!q?lAYvs:mR(GZyGq+w0)NzuY-&"Y ='I8{mL/~!.BA=缱Y |z:f#¬oh2XjǼI|1i3A(|vf1 NKLͫ.?r]qBS^#o.l%z⁋ Y~i䔃P�qu&7(U;Bl zFx׎M ,|Pf V֠k'Nb̔/$EN HAiQ =u-/TQAD9gW%YZ\aԥ5Ojru"9Bzp̬vll= ɸYyܾ5t mEz+M>Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft <PJZ@4K|#`}akRN'~IU!kWLZDNK̡U ;gL~a(]!Bjv(f\B}AuHR�gM <7 O:[m6uv;3=wwn3pKM{.�t "nt?dibC6=E ,ѮO 0hvG;=MV%ʪr�4H 8rK썀xA:2 e.ݟ0N<g'6%G1ַm}^jnҽS0 CzLX3UM;^^~XcavGHu" 1kNKT?,r=܎X}6CBW6ۻ�F\3m{4!]9ửJ4n5Jsw^ Dhz8P]z1x~�J8#c%ϾcF{do@w0QsP_́ ?3yB2Đ{|5}>x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ<![NwaZx\Rtv^ZJa\(ZPE 1ޣhy0S�L!yQP̞#R@ӱ&4a9'2ċIE8XIr 4*yb˼/# x;2R~�O7h՘U^k (侠,2)C:(ِ;Q3>4)%b6B8\�pe<S+jsp%<&t{3?|N)p7b?aiDWlXZ>;u)ko)#WSncRx{[sXv195_0Kՙ7>�Tp5ٴl3S"؝LX睫[5m Q�="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# B�Hǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$�պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(�5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"<HN&] 569!I1;"YxAK-ym|h d "]U.akgbbw24j- Q�Od-:N dG˥MI VG=W!r6wH3p"ۋ #g6*x9k{H<WBQߍOMV{Kh^<FW <L:w$|oY-Q]<ʫ!!垹Fq@}3fR%oĿMrD+N|YY6jr11k4i'Xf\:e޼ ~P91ߍ &78Qape5 9osMy K-uu9Bdx7HV&_!ClgL 04yS}|qٳkbs:f'/㼳@!]%z#=Js`3W ez<PIGC0@4 55gxcTGU#RCC?tdxL`Ɓ8dgsT?M6}, _ \k٬lt΄ls:m"25be\]\ ˛{xaLoQlPwK7?M�^a,_lb(1?3݌^7:ރ^usϚqB8*hGxYCm5M~{Sg9nRXC}[hOtC1#W3*:;&_Gۂ&H|5L<4Ƀ\bD?]fM{V6*S<e0,! AؾKmmߍrOoC2 #p'$F˿@!{0VYWoe,'H'`r1#ͿMRSYZBh|xH@ 6YziWlwQ }yqs!`~y#-O ՑIXmy|*0o@]ۓ^(`Pqƒvefv'OA=B݂pCJ#  ֞q5 RwV&) ԩn@po]{3v: Yf*aW_&' Jk0nDx \/HD uqZ\ڌG+啵X ZT>z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)n�Ҁ lEGyl:̑IoB<A\\6dFqϡɅQ[1<kN>S%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣ�OP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/N�W:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI<k¶ ٤^Sx[sGD(�+"EHnֆA_\F Z%?4`w_{7"0Y@f}PEjmv:QrN[wz*5c?jf7?K_P', sZ(oT |Ó\-%蔒hy\ cK/ ˧YGԻڐz&c" *(,yEq(y[q`a7Xļ~R/{hh"g=wݠ՗?̶uNh{g?tqm,u[Yot+!hf.2]ݹ?&wARFľ붾Ue%dliqMs&6Xw-&Y3(G9{cׁ֬ǿM;vn"b)<׾e_1p}11F#YXpq]s,[%*&@DfҹAٙfs ,>3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,�'C4i<Dn#xг Hz5[ _QtmvNC_`x~ Mb s�PEx؇;cW*n\?׿v:O3@fR&em[mٜC5f( MNiYXxШ=4 yHO<0|3[B :d1"ZO$+Kxi̒=sJg ~i[Rz'G#v}>?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|�8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!3<Vyx,!C b.lf'\ ןgu,μw-/3ۥNX(c oMDsa##0{c %uDWCBZAZ6,؏x (Z%wHbhTb2<$*cnk_א#{D+B<!S/gÏ`9.^]ßC+>3+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!�!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w�)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷�m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"�{d#!φt},nyWFKv„X4|<B+8i=-;X 5l=/xlwn] +SӼ,{՞�/ДV�+<< o ԇeNp^OOv qR wHF3݁=o;`~kRwCu¦kjE|qϩKV, *?xk}QxU/M= հp=犐^xBˏKx@[IYB]T➐Kq.ὀPwAG\Wϋ92SA\Y\y=ǨGjբM@tԂvDz+Bĺ\լ6k6LʦR_rnl|UAϯ< |!;8_1gsލC >VB~,˘_&fjp/Wԍwa�O H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)�� mkBT�D��������������������������������������������������������������������x{UU/s Q> $i0.Z2\1iZ*B"2.4$< �g!|P ߗ{z;>9{Y wg}~{m'"4+@\EDA<@<M,'6;&]"4vOt%ZQ.."n##v4;uOkN?#^ o.8iziwJ6^ NE8D,&g *xۉަ.~bcbqԅGiiоaE뉵8ԃY[3we.#C|S:xgJűvOIP*qQ%AE|E:056R1gĝD xV{J%`>ߏcX~q%j Ĕth~Cls\EYD+<Ab.Qi?v !& ԁY V!߸YPRcyl0.,V WsP~ԅ7P'+R&D"yh�ƴ*# MVa<@2'/L-N<?QqA#}K2>ˬ_2h3LҲH?K8�٧HXAhn025 ԁ?HXiV9@+Yy>UVγR-q%*X?:Ƭ'҇ᙰ$S^TfbցHTHK3{*^T9(&Q9NiDQ*f0ǔLfG{ESe.s,!C0XQn6׈"SmFF2mvz~ZkF0mhך5w7u@[6h?iƿ fU_7& kM6:_[�ƿL A{l7f= (5u@[&1ok�׍ zf32-ff]eik / _[607e?).} i1%ƿL`%72߼#'}7Zr2ӿekIO-ƿpTq=X+3ĮMKD;{r1R[J0<׍T=:ec_S?/VJa~;][F||_P>=w7S{QMH|G) ) \O ?f߻D�ctoDJ_Vi^dmlP}'2|'Ve}fGvY̶$nNH3Xr_<^)omOdϠ,OWr~xWH}^e#3>[LWON?wIr`mY 8~<Sd�q_$_' č =j;id?> piֵK>^IM\L׍{=>Cȉrܿ@O'ߴfy|Q.r=>s%w*|?Жo?ߧip[O :#f;śk% kq|Oˮ L| -!ƊM.88Cg27<~N n`hU[G{|}y<@&+=ڞ V9�LU=@|X8 rV,.ԧ9^.MX3/DW]p#Z'؟sX&U=jV|DmA-5}E]D.j<AB96Ĺ ?E,?Y-yi&*x=6Ekk ®%'yEXzy?== py~} *K9ljKc'KBfsϗ]Γ>|oe 衉{y5[x<ük/^Вs}&RN9s< Όq̇BGLrMD2G|~S2Yhg2g5 {\WY8mӍ{6%s]c1Z;xOYjEqO6ޅ9ץ_c8)w~qԿoɊ#h-;ZnW95S}b:^}7Ӎ7ƽ\I=Vm'$oO%F78g?MA7[C#wP>&=gdS h>v$؃ 1NrHSd#ڤA?9!c/3Ͽ3`1wz2?ĭqd#B_GV4"L,[+E1: |n'7S6*qaxd`�byذ�݃[R|<)wy1󂳶4]`]c}9/^IOÌ/48gTg]J@G+K/chܻRf�މ9_`<crqK)Oc:x#h Հ46Y^ړ.LP-|s1#\FhR2l8_tm6}0gzX%Ɛ! 9ۅTW Mޯ;~{G=ܸ1NOeg(ucpT5qEsc?́-\Ƹ?yålxI e E6s2!lH^/LǍrbluO_']q4H�=B9)pnF}cqoMO��mkBT�C��������������������������������������������������������������������xke1BYd!ee+j7Xt!](*0‚,gCHFE˶<{yfgf/>Y<z$O֢=+(j>:o^EwmhZrܜr.wl3 =^D|Lj]sܦuܣ z7s|?e/iǗNC=[zp~odlc;}S.PWБ/r)6w !a~Պ링H[y*V#?y9ܷľϗ|++tIqw ʷ2sZd,2nug@s.[_||9b)͉i) c)/lb:2}=9byG6'uʩ|[q-c:A;LJX8_2V_-d7G mcבܟdfXM ղU \8vy)qJ/_+޽ -Cؾ/}9e넏2?%CYmYs|46NH[r?dn8/,!fߋ"OZ=֝Qm}替 \R?`}N'Pl?=5kz^5fUs7e 39~{6|L.l8*gk2bxA;eX9ͻrlدTnWݰ@Jٷ<M+^n<i0= b;*,P,X̀{p][7W n ,8z[::P[Y_B=06C;6W`5.yq/ݙ0{I2r7# ]cH#|El;rc}g8g: -M|b=x lށfʚ^k{nkoXmݿ,>A>j{'5[.q~aOr���������������������������������������������������������������������Z;Tְ��8mkBT� >��������������������������������������������������������������������x r0��aǁrQ8J C+};iU6m86tm8Lϥ<1Jӿ'&Վ^s~wc~ğ66?ύ1քا`ot&j1{Ʈmb;w4O4FZ<{U|MY cGo'ׇw g,gwMs7/?ρ+y49s#k?snq8],uyf!vy\4]<uϲ0ev?]^I9on'Of7Nӕ9=ƻ?,c]_Zm#54ZW<6 ]j[};nqw!YWn}yOjLǓ!$>Knlg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟg?;Nvӟݙ�76&��mkBT�<i��������������������������������������������������������������������x훁u KF(4F@1Rb{/@8scFw_87ޣn>#~^}Oۅ}j_7kR{оGe&7Gz/海=˷¿6wѴScmp^;y7~RۛFn_[}?oǂ^i^о忂g3,}'@n'm}K]vG7l̍Erq}747h-f+X<^~|T+}u|{~u!^KJm:B\׷om}_;o3uu{\&^|ۯ/Ը?wn/TPrϑk{Ɩاv\Wy�о wkhZr7z3>C}俋e==/ް/;\05>>K%vx~w>D+ncz2nl 䵆}fyL¾kןa8v3wkȺ^_|XK^38wskr}g=z=j 9;6C5}ԑr#pg�r?\KN3ל3֑k,c =b=b.78}9 r} /-ܷ /ݟ / }\}A/x0E_/ Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε Ε?Ε|hb9 9wP_=_Z59_=Cۋ8��mkBT�u��������������������������������������������������������������������xq F] B|{9{3;Y$}|����������������������������x MmCGߴDߵt׏9kOqI];Ո<aO{52FMco?4�vF2zλVINWsڽ_p\0kJ } Iʑ~#TW2˱7,GҴpRLԾ-3M:ohmŠ#.[w˒׽'c7>O}k-dN%j՜6գqMDZFk-MNeoI.>Mq(wYK3mlzjR%{j;#?ѮCE MX%a:֐׼Qm\2Fcڟsc~uW ƜWoE#xKk8O7osw5yvJ˝ٷ,s9LJ㲺[8/ګ׿_O7=oIo|Kqm0ǣsI?ontg ;r'sDֹӘ鿞ȡ3ӽD<VhLc!_ӵ>u!Y5zz3YUn2q9R';~YCʮK #mscxo��\>7oޠA{ 7o����������������������������������������������<:߶|WjHjgZf.4{͞ެyt{Y>tѵiYYQ]jYm:Z7-5v''OdCW01}һŗ;)Ø =[lj[{Vw5ޒ^01PfCWm*kG}WUJ/noŘik-rɍ75Nu*obGLJqԾk]BkYމ1@;͏/?kGj?g|jyqq>;y]stAb,tPsK8lc(+gwXFXvɟ*7 _k>RZ4g(k,m%hwk :6[157Xvq(SA|K,w}1�:$XkUX>T3&>UJ_^|W,${^4kj 3^fO/4һ^DK%ywHNWx$c%8Og}uTqު?<݋]ϑo՟#,KÑf bF̩#O(o>*όI;-aYs1q)J h��mkBT���������������������������������������������������������������������x1 �0 'ݑSő 3[{vo;vo;vo;vo;vo;vo;vo����������������������������������� >) ��� �IDATxy>7faXaAp %^@ąk F17?Cozbc�5.רŀKjEpEP`fYzltu[U]ow?sr ~ϼ]ZEQ@$'|sεf7@DDDbDDD MDD DDD MDD DDD MDD DDD MDD DDD MDD DDD MDD DDD MDD DDD MDD DDD MDD DDD nvF9C=rsuu?(ZX`ZaΆb8a/*b a!(%$Uh+>Z>7h޸55ƞjE7c;neeƞRNBᅬpmss𣭪 mUUh\a{7G=r""2Q%8w-ףw;rrsEȻr^v&vHDD&aB۽m_|˗S[kv;Q55U8j� }Ϝ[nA&wGDD:@Oᥗ7f֝;Qs'j~_[oE8fFDD2۶GP^1ڵ8v-%%3o ֬,;#""9mW\]g^J>-Ž!Cp'R9 ""u簣{fB f$Om-j~c5 W4""o+^/1mwنZ{ Y睇ŋ9n-IL]i|)[k&|u8? n6 GikUӧ{QڞÇ<}:f v3""#Si zQR{I pQT3ҾfߏxNdP]<ᛋ/F_#""F,+C?cY^bCwڪڶ [ں-;w~'qh"x;Q27tϖ.Cތȝ6 B]#/& s[�fokF_ >|GF |9nHBDL}>ՊkA[oEKZl\x!r.% }~?h޸1UxË/w2:uMDD21FV #>/Gԩg(N [cB?bĚ5}e|FDDIжab+ cH?Gq10c窫x<:vHDD205}Qvgcș2ELfO>'r.(yyߞNDDV|>Mym�gYA#K0t: y㍨6Y~A:#""ڶ\ڌѣ1hrXN;O_~ `4{h"4,_nPgDDov^PC֬-'dBʭ[y* tSt""Jxүxu8Б2<[dBc6:?ODD'wh[,s:4�,6= >yDܹwFDDF35BkMb}M8_@Wqg djh;9Vp5#)SPi**y'ڪ bjhgOxq&1͛>|xZs3ΈHovΔ)Ae텅X֬,J<B y Xںu]"""ڎ}�Xb'K] BʕE=:HO6�s8;)mgFɞ4 ~:b'Lm�pšivIף{#տ\[ġ#""ҋM_ל9%>MQI'(.[ں?(V $eEXw�?pODC;FdsNؚ{qԑ:6v2X,eu>zRMDC;eu o9lM poDD1S@wyV\]EEE3o^ؚW^AC`Xņ"n=ȟlȹ&"C;E8Cak>$.ndX鋡B;klDsr.5)$;Aĉakڔk""0SLv8fMTs3N15u9c]]suND$b,N'r/4lMӿ*b [58v ʻ⊈5 ˗Ꚉ()(k_}òe!Ǹ&"2C; #պs'Zc\]"Ꚉ| %ڍ˗suMD$v7.Gڪڲ%s5H C;e1]j0ÚHC;eyfĚ+Wjk""0SXkkjꚈx &�צMaǹ&"v s kffĺ͛UꚈ()#l-62ƌXJ[kXG H C;ŜigCioW=^˹!"�vuض6oꚈd .%%BsB\r.-5DDDVRD eu '"nvd y{�uuQ+q"" `h'(V<aMD C;D>}>-&"?v%�}'N>WDD`h'XCS[+v5Ü($m_ԭm5e�9cYivQ5:9"VrM[5>3-kE@+�<a qϧ^&"W>]a`3뀜zpWV9#4/*a!GK8PS?\]/B[ωݵ6O'7!r v ph9p|+Sd�pPPsGwQ59=#x)oz|~4;oAg`;`L@S:_|!4OƨQ4DD%Oh+@hRzm`5@xOx(5=<bn/u>>�=Sd"{Ѽa|iFE`XK>pQs0~Yϻ-ct=5k.Au8x=JF\Vs;?Պ#4+ڕ7K>*`QQ]n=Ծo_ mPR[/&=m >_}U6m X3351'OlS<gtP /UFOMZ]wND;gLyQ׵(mO#R>V<#vA� GߊBe^]wԞxu(B]yesqMDd퓟=zع�8z}Z)0-WC1Kk꺓ߏ#q֬,^q!um""msڞcB;翏\gMθY&6�@�*=5<ia}JehݹS+%#Cs6cstz:�{vT2?8t)yTΫOفx}9Vs\]#9B[ ڊuیA[�d}=0}m{B|44~ssrANDYr=qgNf0{0%?"�M*7wvVב}AΟkXi=sE>ʞά�&ml�Gu$~ xϖ޷5ND?ڙ!N}+ ?Ilo� RՇ0H5'׭ñ|izz+99kH"xzj_*l`/oY4}Xi'6ibL؈?! 8-?#/B]DDIІ%pkwPKa5RCi>7k+9BE.ZVvݽo] .@o#kGc[-v?jJƨ�צMm½Xobb8WDDrHx!ղ 7]7uw7{66-B.Dg׵/yB;\E>򥁢(}<[F5�G=*|ѣgssMDd$ 퉀5T#EQc  4ZE9sWՊKaq8L d6͚l+NuLkeOՋBP㵜+sݡp<dLhꚁMD$.yB|tL*/nUvDzؠyVZv<V�a5k �GD~g8'"_rvzOjphz?^˹4nTϚol)_? xuXB3\?ю1\]0 mWѷ`zzq9PRu57c̙hZV@[^ GX]3ȉ"Kрn_g h;XW |~3�1G;؎[c&TϘƍ�KZW@ڈW]DDJ;XM s:(c2=^<ZjE >:o'e<ɓɻƉ䐜A8 PƮA q_]@cٚOCoٳ{ꚈHuM[Ha9@(ۍfǎ/[)S »BǼe,9( m;=1;[yʩ"犥cLp{PsPZվ-O<P2}&wIDž�(Oo=r�56?@ӿBA/E43c"DD%eB[s86z]�eǣ8hе|3{Dt,A 7MD?IxofV 2- |,s M(8c4)v,DDrIvL`?X-/A �gaL 2ѣ-hz-m=(/^2lk<ƈ( )C;�<>{DзEs.-aռnjnȍȘ0VO]1zLd m'׭ѷ/:K8[Z0S<w@?C̙3ffjEK#"`RɓQt)2FT=&Q�<ٳ޶M(o㍺c8Fe˰;z6�4v_tڪI;^u`g_tl2äۈ(<B!<uu}; �rw;yh+_kQVz 7DD~?\7-i۽UW\ө\]GVJ|pNŐmPp͚mu͕78Bj%--bkV| #V?`FÀ7ހ<~镟&"\ _ ~sMspbJXB�<<Tl݊X4H+o"" MΟ5KKDeu( 88P/�`q:Q`кupU?юquMD$Bk?0>Nvxh\csxzJ6 7l@w_U&"#]hg+W|>T_wܟ~qXjDɵ~=^I0F1QkKKa55aԩhou5wB}^ulH+o""R'Uhw;CҥlN@嗣>W,5ZJh? /E/SruMDRڋ|uae8󴵡ǑGt.-5R@ΜG ;<V r"Lp/W_UBnbBpB2ޫ&4oaϛ6|8=[`ʛ<5.Ðt�񏨺reZ$'Oaq{MD$ΔB=y2_3t\ڵj8?ʵnv=%/ӟ2$8={Ꚉ(5cYYe7#hz\zqlb쪬;kÆί?:J{;\~_wEVוpmtlj}uǎE޵DvMDWXO#nI8JJw8l8 ~`q8x<66$kjpo�-𷴨gC}dd%� x5dMr\mD9vŊ;wnw�n ZQh߿X`q:1z4Ū;D[op`xԓǖ..zj5--d0;yqC9yrԁmVƻ""bhh {矏}z<n+(@G9!-;}:ǖ,A]7G�)WMBWx"Q Q0CiknٸbEP`5?q7[Qx YyfiRXe}6Jy$qEQ;qm!!kBum"ԦJ[q9)�@%_:]ԩȞ:pѶ{~DXvdN+DáS˖-!ξ⊐ǝ.YV"DDnqֹ~0_>RS54'`+(x.gYJ%cpmMp}!۷Cimܧ5;ٗ\ӑse՜W!˝1#q4z̬sQdv/}yMᅬ5_}[1\ ܋yӧ#ot� -|57r 톯 ~l8 28Hu{LsvuD'T t""11^!a):޳?.?9Jˑ8<F^qǀ3@RCDDQ߈ C֭8~?~LyZ| gD?юqsh 9c} w|a޻wyZo'C]nF uXi; 2W3@RCDD4ޫk5FaڵpG\zX4"<2JCl5BյZm1GȹcZwBM7#p'iÈ1_ccC1]ƴQxaC[^kk֠{C޵}j7**|!pj^SV!a*UruMDBa%UY(^T^ {QG~28 ev(>pzX> ē庶>( (VJ-KP=w𪻃G{T};٧MC…8j)|p.\ヒ{C<^8-e{K;k5ӎ[ᢵ=0?e zt~;Z>Ts~ ףy,EEp^R[q1,V+.|./aqojxkf&X / :-]np⹺&""m|azCn1q"lڄŋQ{75 [9x0n7_}5Ψ5/Xޔ`pDD*S`}16 ; Q=s&ڪTl(T؁o%-M{:h~)2=!JZjDEDDhzXN\�m{܌oݓ&G!'QYUE4ݬ7שܻ* z,kk9*\]+W^%hЀ}gspعEE(կPYUc k~~j1:Zz2߈u{;̛sJ��IDAT0Z(綤!0d ZnoVӃs*+Uk]]Z8QmVV> u[>u78P#Ȟ6 tC3wA;C6�x 9&um#"[s77 3H;cMUΡCkPOoi{| A޽h߻Zldd }hOs=vF]X[ު[tzUVq-5FGDD]†7I |aq?GBBVfd K5mZn7<}^xjklѿ?ee YY;1-5z '"L5b(/G8+xP3gƌ'0DڈpռGR mknnsҏȼ5z^''"Je_c*"NJX=zU矏%KTΖzp>n/*qq.""Z_c9},}hnsֆw݅SO:N̋. S[A2.@^Ԉs:M_cju҇K �͛g$`G~zږի~]?�S^EkaMD=z5źsLQph/^,R4]}5zv2&LNxXks]'!"JA?c >(ʗ-Me%6E<{'OF]UerA鶃W}>Djb핈†v\V*rg[7{viپu bτ ]Y?)~~[^8`OEJKs=p8#nڨ?شADDoj-}_sCXXӑuȾRdMgEETn4&^}kV}/Gkר1-5z'" /( HcoEкcGDzFĉl6nٰAv ᭫Cۧp^UsPo=#f\R\&" 3e q'WFSOw#^Zaq:awAˑ:puy_gha̭7ZYȝ9WcȎ(nՏy*i#Gی"k5 ".X4F+A(UU({^u!3Ruס;QQx5.r|4fDDS Cb xY̚Yý~=֬AӛodwP1kDDz5=num c- ڵhs؁{v fS <X^SuիW6Q=VډK?w>wѾkZwxUn7V(mmkاni#G7jC’.ϨF&"2WghFk@ڙg"3r>#k>(!".v)Y@`XsuMDnDKLյl"" /(e{!O`M3s"" -^eX#".v 5U~RauDDFTdY] "ToD\`ꚫk""3hMyb=VF9'".1J,&Rru͕7b-@au-ԅMd $H+7"/ӘZkS9'"Ks5LcKDD):qs"" ] WFeLdq/Ǵ5_>(<5X""._ikTxΉ'ü5z%DD]R|u-B._Q+Z\'"и˗~Dk9u._cdyι&"wGFu\DƉHwz'Әwj\km*wFd""ꉻ|ik>> l"h._Zj/Q:'|5_+k'vR#Z`ʛ(Rj/K`um"I]Ԉ2X&"KK^%KxruMD$KK^s%DD%vR|\yGRF%Xe쇈%._Zj/Ճk"K]1+o""$._ZjO11%._"Zke +ٞs̗P|ik>d׵+avZ` "KK^%ʘl6KFd Tzr/-5z͗(cDD#._5z` "ФKKhlH5|LKK^1X9H|ik.2U?؈R)|ik>\j!"Fd TaMDdFrZj(X\vR\ VƴQhFda|ic.ŠwR|2֏?-uDDN]DƵH2؏hM4DDN]5Lc5Qry/c׏hM4DD%Dk/Qd'n6$"ТKFR=XeG&Z""RF4D d5n6$".B_FrZj(E-e d V[р_]JruMDB~#յla  r"Ȣ{\Kl$S?ZjMD$&Ed d V5QjtZI~d95H;Ed d VZDDыxxD[]'Kshk.9Ql=F^kaMD?%S %K&׵eȆ! Vk>!2&[?\]Q$m"[XzZj+o""c }+*Yzc*+o""ĴaUCK^quMD?!-%X\&BXi{<SCK^qMDd-[ %KzXz,=`R|\]/ha-Սh VWz5\4#L)[z'sNDD7%ҋ|Fd{^KoDKdUFd}QoDK`5xe}QhQm)S@&R qu&"d{i,cEk+s""rl"+W\y-R!X$HTE>JK^4&2NDD˗czkMp8SFdX"" ._ikdyΉ(w25z͗(c"DD|<FADDq/k.W^&"2waLK^sNDD=q/k.W^&"k~DDwXꚈKc?5z眈:}JDX=N]k>>DD|qu1q""R]Id""._QkM`5^""._Q5Lc2CDD=q/qMD_)˗K1IDD._5z͗,DDI]5_uI]Dk/׵'%vR\2=>DDI]5_'WDDI]5L]"@DDbn/-5z͗ *(%._Zj+YլsQ@RFR!Xe]Q@FR%XDDI]5Lcð&"2^BFR%XDDrK]5Lcð&"Kd\kmk"g@DDk?O]����IENDB`��������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/bitmaps/banner.jpg�����������������������������������������������0000664�0000000�0000000�00000012004�12614627753�0022304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���C��C��:���������������  �'�������� ! "1������������ �3�� ����!1A"2 Q#$3CDRaq� ��?���������������������������������������������������������������zg;5)KT&<)+kX"0 q h5]m[a\tuEJgynG�=YM�rHO~ܿES{cWuMVε?tu)4gM0,A[zkYwMӾETZ)z<8c%�S_7x/qXjEOrJm�^�{_�M奄n_xvHtP#Ymr{G5KYCr: '=�$_k2oqcaOܦ5S�L*f,tWS�Mq޿$MO\ƹ_ Q�35+}3x)M:/tJxtSfL4n-tx$%h{:nI' S}l\͹v_ݭ#dj9?v==9Oix?M|) WgmQ@sYjoڹNUk+$}]RX3Ȑ����������������������������������������������������������������ϊ<8_R =%ɛQuB*aЮloiISVIl}kGĥ6OTXg Vr)fT�)>ۦc=_y:~m<Y]f֖ ƽRKZ֕k9Yލw¿g)u|Bf,[?1g]rMXK2R5(4Wu8mDå�;\=MIm˲N�{_ِƢzE/.'>>EH8H{б˪V^}m{c֍"Xp:[>2><.jDḼZ[h]~Ϳ""4OMd��m,q<,rsX`έVOKV8eO?</KMKPVUoT_O ˚4^r~?{?KIgnwy&?/d_^<]YE%fC~̊QUf-q[ubZAjB.?fb˫ؖII2B$'sƨβ#`<}E}Uf^^Zt6#>f=[FC*ѵ)ߵY2K&KvS)I6ky< 7WQh'I4UZ>W,suirU}t?~9}ڪ]]KobU-z.V H__8 =~X%k״1~*(x'}贈!4Jg{^XդQϚ7='ƒ9Qx6������������������������������������������������������������������j(馲+'K")tQ5t9}6u\q EE5c9{cڪ5_ms\j**~Q(W]}[΂鴨rνxᵤWH%}QPm)�##(Dt*?1>׎EFףpH7 rO_;9X7>;7Կ25n[#TG~Hi ph����������������������������������������������������������������{Bb'+mGeMl׏hڽFEnmۥˍwM]2>�o?yzݬw1Q--(h�FibI5d{׋a[ךs<ndRoK߿R_6/?Zgi#Zך}٤w*}uw]ߵ4\_􍛣KZQ!Zf#yez3'*ȃ#jh-yOgȱ_w[ԊRKt{{ZSE#q~M)Is>olms6w3_ѕG= w4_hdQK[ջ-,M6"`[kuJ4avH(fkHJ=_mjŃ&9rcDO}gfĬ#|M#mW#ܿEsdBǣgO[Z\PŻ*U4W=dQFW=DOܭsɏY^ &|G=xE-Qqh=\]}!ei3&.4Gl働tr7dzdK}25g5?ZGK�:[ ?}=}63ػÞ?s fnM5kbAckfL:x3K��������������������������������������������������������������w#{nnKZNfR2rͯܛVr(њ.tCmsfFeI!t*nHk3 F#j+&>=lZZYxz~AV֥URCt28Oi,OR*<_. M9(4kzHW'yv/uE'.c$;k9 J"A<xA<E Xy;vȫv}H-N)Z=a|5{^Ǔ1 oxju9ZIbSĚHKU׬GEA- V^xҸGYW[f~aάVnկ [g\쳭pM2 [?v<lͿ ԅ,,[14"=femhZ=>g8nw굙_yuzIEl{WNFV_oJ%mFFeińmlY<7zM[ Q9$r]us|IenDt^Vl\$S�\H�_ޞ>jW͈˧~^WW՞oR_�kISs]EeL< zv,x/-7R,^UwΩ7pklYw9YČR,ŠmsfQǣ_7:+Sτ139}HsꯑsܪU9=Oz״׳oZ[z:U=Qb6duhҮSUȣkRV3Ș��������������������������������������������������������������idXj>>z+oFTeֳ.geLJ0ҽ{U_)(Bj?GUU<-K_j X~΅WYZײ {~ͯac~h�ܞvnj-K[E kl[5l;GZR+%+XlV~�Ak-�][�kwUѝ ocnԑ$ګ-~NnE_m<w3\ڥ_Q}6Q$7V^Ɖ_rU9_jE0cȽ~]>SEж.V_vPlmU~ggϾ%m%{U۴EXPj#(8IrY]FcP5w"VK�럩t0u{;OkkJ9mJ4 У ,2L1z#RGDOy柑>iX^x>&mzgMuu}^O͗:KvjY%8?6}ڂL}^FS)P5jv)/ _blL[$mvL~4u6|޵AN*+V8 EQ� j"'�'(M^vM V{FrO<kQ]kQ=95`���������������������������������������������������������������gy/8Åv}th2,f1ID]u; "!qRwhpf>~u8>K-D{}5cONG1\՜,nvOE+ZA<NrnI^'/p~!TB4?"{cvN5>+nq3c6:JߪsMLkXm" IAkrݞiWh1>|ޢ~Hԉ/slIY Lj#ơꭿ<}4z=;?j9;efǥn{ ٺtlL؞|Q]ʼ/pWJMAkltWjy[Sr06QtQ,�GCVVkBfčϞ:,SCb;Sط3H>l&39Fjn| M;nm!wo '>tQz_jv=Qծ‰qP���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/bitmaps/header.png�����������������������������������������������0000664�0000000�0000000�00000075245�12614627753�0022313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR�����:������sBIT|d��� pHYs�� �� ~���tEXtCreation Time�06/14/07Qk���tEXtSoftware�Macromedia Fireworks 8hx���prVWxڹmC1@AJ 5 6 LS0+[ 6}<�Fy|{O}6z[s^.�Y-8[A<ӱ-ykZ, 8^Qf>cv_b[3s5?��������׏9S?�����? d���HmkBF�������������������������������������������������������������������)3��mkTSx]YsƖvd[r+0/ vMEIl9*6oW[9 h�Ea%j;t7tu=v&S-|<ڶj9S5xɊmj6``O-'iCz Է> V~l.ʆ2T<U{4QGPsjC�O8mk tdj>FIPa7hw~T`;I}8fɴi!G~8VcԠ}M:ަ}bPс::+ ,B eKنJW*1n,ps.q.6&f*ب9xK 2xq~x0y=,�|Q>r}�A@g[�MA4]$m[ab5}V!Cڢ8Q<chA|cV曋WqܺemF}8~Nv5nK؁بq ς-L#2RzyCԠXM<[@Qz"EMcm0_n+Nqz$ʼnSyyd1,u\+_Kb0 &$43>6">q\Ә{fE˦2hTʠQ4*FM@ɡ8ނWP1"c c�D] =#!3L2YbMD| W@ øy�'( 򑔎| &R"`b`>`½(IC~[(kY~Z*C՝X mT1!7^[zE+YU~q:�H fT7PQ-b 'R%�֭hV=�}fZszpq9zvclbבM |C=JR :hMCm! xi'EL W^L+u9f,l;V9妦<]"AYrD q 'Y<_?Fܘ[~@d_~蕆^2aV^s Rg#_(=UfǬ,'E)Ɇˏ=tðvڸ05Fu,'UbdhF!BŌu;K Z.Cfh - eFa CmLo"oU~qM"h1՛h2Ia9AQi�pXɑgsͳ,0L_yVM{eFq!,=Ւ3 ^0ۓ!Cvh!N 0W'I n)GX9/e�֬qZh[aF&}n7CϹt̺42!#^4o.PlEOs'S^oox&^ /v>`O]:4K\su"Y֢ JNU'ޑd84a@B 2Z Kw {Mf}0k.Oc_ 4Y|JÐ\At! qOE<s0.: X/8#z5~H/<EB7㖻 ~:A�~cT~!Ngx&(M14$RɈ#=E{I'.Թ(pJJs7a dV[W6ˁ'I�;y'o"2S<�]a&ik7S σZ|"{ ~S3@kr_x-b,6όi@D(7JmHFyYN|wSja-�-qSw# pwa*2dq'-ZX[2.ϹOr�3vH A}(`gYG۟;;@f C;[B[ B>^" y!l|_o ٠ZU)VjqC|jhOE\H!^>0%>b^ȑ,$(i8A/Cth&\P4CYBSqL #7M{6ybi8vgk͌xwrG |.yJiU.aQGLK$UO<;x%Y7 !q*7_%i =hJ ~ԺdYY,.WE'3֓TP_Q:s* ڻMJE3N?RcE焌/ɧ S)fq0wZaʹ mf<}'.CiWlYY$Cj$}ΤFحHRWi*N{w[OB'Oj:i+l3r)2SD)RE<v3r?eӱ<FN[ZW6+*и"XZԕ7ITB>EʹGYt�K6v-b�[EV<\s 7 Fx:Zh$sjȧ;Uezne<:ذdևQ*Ŗo�x-_g%N;uϘ!Igi-s8|bIY-JƐ֪hmT~&/ ! y *#Z@=v}:i''Y)!7mQI€w$.TKuzm:cu8"ģ8 #6I̚jMY؋ZE/`2>h{|FS~ _W{ﰛ.^ҿ VU+XԛGx u|.kB+(G/Jjr3܌Zne˭x[̛(T$-#HĹ�4q7ڏu9u$g2ə䪌E&KJx cQ~isnĮVHgKo-Vy?<~q,&.Viuɉb{}LO3WVIQK:(#ijrZZeKkKHwNr8{F5Y6,,e&S/)V?v:h59yLN^-2rڈ;+;b@>YM5F̪X^sjǫIk̤5U%ΦU"~NsIg یh 6 ӻڈs5R^,Z N[O|3ķ5(]EM zIڴ <SW##P]7HTZ|NV6+E}^~ġƚ! vxtgV7FִfC[λs&H_RBc\2SS֚fô5a��JV:Qc͖vd쏆(-4a]xűKk{hrSjUK-ڰІYJMߴ2vǞe)yƚآBcV7]Jq+E5=P7G˶mg!騎* IfIg!5࿂pnE&Ֆ=Vޞ&''_>q.ٝ9ug6[,!vkM?Y#xh 1m;M <d %_<#_Q}7_W|`!^3b趶}TM>Ko=MյY&V*>)LE Ynݗt"Y7@_BnF`cM,7iBLt.!HvNl^sL0Jf[p΋ rv.zF,i^l݄s8knbǮ}^s5Lڊ?+?g'<6DԨcљ A ~ OݘQ(D'&μ;mTs%~;;\tB蚆b ]Ћh,4ßѦ^= {"H\I"�:_|=fmrV8!b5*ja|C-%s8v-ʼcBux&\v$tzF{>לs?xp`~Wc? XWwx@wxˍ+mD]k.%0]sֈ> ;Z]ER'ͻԌfH~yƊWnDWZ<ߡ˜\s.x[]bwhğñ8l"ʃn8(;h 뚝kv^:;[5;\svވcf蚡v5C ]po۽f蚡" ]3t26|]W9es^sv5g <5k^6G5G]stGkz m ]3tCK4\y| ع^yW3\;+jv \ٹf"孼60tf蚡0fʻk.ʻog+jή9g+j ]92/g]зw5C =c6gNгw.JZvߚ ?#bQ]!z:%3v1ns9�^O[ ]){"nU8]9SZk[7\0 v_gl틊yǿ'*cݞhjخ=l~ޜ)0t 0t0!D?o}͚k,Tr_oͽM $ ů8{>!SI9&5i ?>pm|Fp~,=ނ>+x912jZtw}}O7ʨ`wj9FZ-L ]_N'?&]]|B7)YsJi/R-Ut~najN'r@`̑!W!{U׻"^-kG&gelr,-MR7aølŐ uo{xޮXFcfyq.(MApM1RFt,ޝLP@ ɗC|7b*ejDzd.W9o@<^x}0ҠV*tЖ19 UxA&- ,~_++y%J1܈/ G oZޏ3#Ϯ*'e>)bOIF_+߫ΊyO|,E$H?G*['8ka:YJ#)t?$ JxM=,됼1=MzDR8ٹI6oD\;aAyuнzzvn%+1ݲQمEss6z.>G1uEZ`1>]u^IM}eyϱI{ X[ۄ+ҹQ^Fy.s]=<<tAzEz:=,DRˆ+hcҒ݋\.]y�Wmߊ7(R2o]:Z:Z-ݍ{:5nybKY]+7'{ @kqo8B }[VlÝ?LG F%݃Ҥ9Ը,k(e9H>=-gkf)>RI>ӬlQ%I`}~ǫ@hVa?^o |fٚzъ\#VX{ ݠbG#Y4t,kRl yo%|I[jg8m_BI̫M̶}:>G6_|ɻhA@[oGqNY i=Z}&PiqD -5 Þ]VOWVe\Ä\rwg%ɫhMŷУQ/H5e~뱸0|fy6t>LOW#j1 WWx,||us)03^_)=b֔ОҮf+ZUU#cҼcr^ߗߑed.h"<2Ko z}y{7 hxy?Gղ1騶VM 旣<z#Cu&ݍHW ^&sL8WJaYMe*RF# zE;տ)RXx5Ru2.qWbl+^ V=}W١_A /5avNVs+qfv [v`c!@Ołtj|"_~�O \]ZWCeASU>eZt Skrxf{TЋ][^|&w{)0*ag>$U9}"\ 7n_j{|\FF=k͈&[mc!P듏ݟ}_ ]EIlޒ�4hA@&_" {"1|>y>7Y$w-vЄ+gMWo`Y|>op[ݯ3Y8|1ދ1q -oϏ/aoHpqp2ۃikp2& :tgC3GfԉXOifM}2AgК`ۡ4m0jAצSz=Vϊ3,Yz|:BНg]8Q}^Tp�'ӆ?2}{us`{=Qw{Xt[w@><Ʀw nlwYNooз6}l{xS5djPVt?˅r}~.!z /~�<?A?XYq'ݝ>eѷn0;&MJZ?u܃6OӏV~"E*~Gtv 1 oڸ-QbjG�#<n^)ó=D:w&P;gAopu)!Q $8>2 t!g U(0ެ CjLg(><: #h_nx=1!4Ţ!`vi!r.gVEN:4&^+QiQiQ$esmw[G{x<vTr?;lx0O)45C!1|S zvn%}fPd%ymp3RU#Al0D1D~M _SC56D~M YGO㤿MQ[���mkBSx]N0�Æ WM- 2*5X|DZ=fLc(F? hҶ BLrGpodgd/e>f 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y X���mkBT�~��������������������������������������������������������������������x �� /@H����������������������������TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUu/.�� mkBT�W��������������������������������������������������������������������x흍8 FSHI!)$FRHnw HYx3ꇤ�saaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>�c=1Ow y^- ڶ,Xz�usM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-�(W? źvƔOʙRv[K?[A}?-wmՑ}<GcK1}uxLzަU0 0 Pc[<>g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8g�ʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K�֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL<?<nѯn!>=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-t�ĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3� %��:mkBT�|��������������������������������������������������������������������xyhYzTaEu?]<@pBaU x⁈"ڢ}ico{6Ie~;of3iH켙*/_M̄K2o&oF9YҧOa()&F2| ȵkU^L>fx]oxJ2,sAEqq捕͚EtdgOBeΚeϿ}ol,';ӤOׯݺQR^ѝwOg"~3ͧcC׬KȗDnwe C*;qB'ky^"~3sϸkNjzy Iki);F&n>_?ٙ9rO/,A{Ftdgoin)uPJl imMxJSN%?k74XY\td<}-@\EEOv+1fsn.b'ISV%vnu!~s sC"'Jczq,Pv4"'s(i.~Z?;W̱]?E\9F>]' 6aYs]ĥ)3v>$'KPg\tdg;Js))GIq'WWV1cYs(!(R~U3)ϥFʃhRZ^o˗F9&]?يRX~ %a)-?妥u[_o\tdg+oc`Kdν޶jm1#EDOvcw'Rkmr!+c?([OJpMs:^ Zq<b';[Qj?}X4nεys(2sc |mUUAח8ӎ9#~>)NoavaɁ0^2DOv<^XvDQ'HwnNtdM?uڮ-{AოM㉏+M>v ͈Ru>'wovm+H|dǕ7>um5eNy}R&';q{``%'s/rvR'Mƴ4+,';k2><6<s-[~挾ÈϧOJe'ORյkT}?N.9s\^ֶQMFtdg|L[|{]X{m-o?Сu|u=>}x6g5';Ӱ{6N&~;GSz\uLV[Ɏ+m1s1/ߵc5e g;ǻ9+]?q|uL}�=Oj׾3ؘѸRؼ|ƌ ]~`9rى4{qvΖݷM3Y{6_ϑx1Ftdgv\\}W~~H7oR{=+CDOv\]4:Ʊ OswɎ;%j}qFTu1㭹}l ;]?Y 7;3&t}Ų{FGSɁV7a5';a.PZy\gS΢ETq9|]������������������������������������������������������������������������������x[Zg=d��mkBT���������������������������������������������������������������������x흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:s�eQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~<Vrv@>!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fz<AǏߊg_ly=Uy3= [6_3]U_k]]ײ2;j->t|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"w<Tk.\rnO>U쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8�֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?�v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ <FVr2nlo؍ا|mo'qbӋr`eef6 0lzsA_x7췣*U}R%+C_ ڟ~I\Q~ky#_jo~DyU^`5pko?:ˮCw>?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}�7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;<sy}ڛk}~|M'8CTo+[WUQr'\'tTYwz.D=W|~q=_�yMǏktbS=2|ұyN_}Oe摽ۏtLS6q`Cjf3#ܰ?z1 H]\"W]O;2'@@~tG:{u7m1Q]PWV2Sz]ϥzs3]vxwҞ:ڗ>y`$jw��ymkBT�6��������������������������������������������������������������������x횉m0]HI!)$FR?6c<lHٱd tC"+RJ)RJkJ߃L_SUn7ss~uU-Uyy9c/Juz?i>>>~�sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{<d6dn;Qm{{5$iѦxg<$"^%=RJ)Ste/֔ a};k_y?9Ԛlz}m#GKk!k(9G1z,Q&liV濊#_<3Ξm$^9g {9&w&:˙uf֚R:ֽL+mWW^z%I2loZf?k4W-# ?V/c^!!{u̵ʴUٷAGe>G}?v✽3X~j{zTAO^ʰ>?sy|G)P</11~2ў׆R/7�Ӿsmsr"(2cϹ;~u-)}<U1g:apb5{3(k!m'mʞ2.~[)}GκbXELp–aԃ77Fy0@ߋL?󞕹Khi@=RJ)RJ)RJ]M;;j;��SmkBT���������������������������������������������������������������������xi`Qqqqq ! COMlS$I$I$I$I$I$IqO9˵wOo]ss,Խu˲<^0 tc}av=7_{V9z}ٿ^s_y~?}ez۶@wE՟k$I$I$I�����������������������������������������@? R*f��*mkBT��������������������������������������������������������������������x}+(H,"H$"#X$,QԈZs>U{ ..T}6�ڳ-F`p]k�߅~b  О$wݓٱ|sCo�A+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ<Qq  +H} eq~~[).5c6,muO9p\<//?N:M›p) Ĝ-2p'uKq`_/64<~� 77SNBQ맨uM{5%.BNɊ k: kNm9*uU|2%;]Faג) RE%HWc0Mg>)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(?<?-1$pO=�x ]<Jt¡Vg`|I,<丕}FQj]o%[Pa6XY<?Yoh�F067ၭ6JFG[wv)7?,@w nMǦmk>?Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($�Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:><M@J9$q]�}=H k3鲺tQ=, 7߻s >36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv<gz 1F*qm-; I�7 ?O(Yr de F ѥrHaۡ>�,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1<u}E Dzl$H+N_2scۯ-rHV.֏'(} o :]謧6Fhlw@z{6P_?  Eh߹vK /B"Mh;бo)gRm $5, Ex(?:gU뵅F4 ߹E4!q?lAYvs:mR(GZyGq+w0)NzuY-&"Y ='I8{mL/~!.BA=缱Y |z:f#¬oh2XjǼI|1i3A(|vf1 NKLͫ.?r]qBS^#o.l%z⁋ Y~i䔃P�qu&7(U;Bl zFx׎M ,|Pf V֠k'Nb̔/$EN HAiQ =u-/TQAD9gW%YZ\aԥ5Ojru"9Bzp̬vll= ɸYyܾ5t mEz+M>Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft <PJZ@4K|#`}akRN'~IU!kWLZDNK̡U ;gL~a(]!Bjv(f\B}AuHR�gM <7 O:[m6uv;3=wwn3pKM{.�t "nt?dibC6=E ,ѮO 0hvG;=MV%ʪr�4H 8rK썀xA:2 e.ݟ0N<g'6%G1ַm}^jnҽS0 CzLX3UM;^^~XcavGHu" 1kNKT?,r=܎X}6CBW6ۻ�F\3m{4!]9ửJ4n5Jsw^ Dhz8P]z1x~�J8#c%ϾcF{do@w0QsP_́ ?3yB2Đ{|5}>x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ<![NwaZx\Rtv^ZJa\(ZPE 1ޣhy0S�L!yQP̞#R@ӱ&4a9'2ċIE8XIr 4*yb˼/# x;2R~�O7h՘U^k (侠,2)C:(ِ;Q3>4)%b6B8\�pe<S+jsp%<&t{3?|N)p7b?aiDWlXZ>;u)ko)#WSncRx{[sXv195_0Kՙ7>�Tp5ٴl3S"؝LX睫[5m Q�="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# B�Hǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$�պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(�5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"<HN&] 569!I1;"YxAK-ym|h d "]U.akgbbw24j- Q�Od-:N dG˥MI VG=W!r6wH3p"ۋ #g6*x9k{H<WBQߍOMV{Kh^<FW <L:w$|oY-Q]<ʫ!!垹Fq@}3fR%oĿMrD+N|YY6jr11k4i'Xf\:e޼ ~P91ߍ &78Qape5 9osMy K-uu9Bdx7HV&_!ClgL 04yS}|qٳkbs:f'/㼳@!]%z#=Js`3W ez<PIGC0@4 55gxcTGU#RCC?tdxL`Ɓ8dgsT?M6}, _ \k٬lt΄ls:m"25be\]\ ˛{xaLoQlPwK7?M�^a,_lb(1?3݌^7:ރ^usϚqB8*hGxYCm5M~{Sg9nRXC}[hOtC1#W3*:;&_Gۂ&H|5L<4Ƀ\bD?]fM{V6*S<e0,! AؾKmmߍrOoC2 #p'$F˿@!{0VYWoe,'H'`r1#ͿMRSYZBh|xH@ 6YziWlwQ }yqs!`~y#-O ՑIXmy|*0o@]ۓ^(`Pqƒvefv'OA=B݂pCJ#  ֞q5 RwV&) ԩn@po]{3v: Yf*aW_&' Jk0nDx \/HD uqZ\ڌG+啵X ZT>z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)n�Ҁ lEGyl:̑IoB<A\\6dFqϡɅQ[1<kN>S%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣ�OP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/N�W:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI<k¶ ٤^Sx[sGD(�+"EHnֆA_\F Z%?4`w_{7"0Y@f}PEjmv:QrN[wz*5c?jf7?K_P', sZ(oT |Ó\-%蔒hy\ cK/ ˧YGԻڐz&c" *(,yEq(y[q`a7Xļ~R/{hh"g=wݠ՗?̶uNh{g?tqm,u[Yot+!hf.2]ݹ?&wARFľ붾Ue%dliqMs&6Xw-&Y3(G9{cׁ֬ǿM;vn"b)<׾e_1p}11F#YXpq]s,[%*&@DfҹAٙfs ,>3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,�'C4i<Dn#xг Hz5[ _QtmvNC_`x~ Mb s�PEx؇;cW*n\?׿v:O3@fR&em[mٜC5f( MNiYXxШ=4 yHO<0|3[B :d1"ZO$+Kxi̒=sJg ~i[Rz'G#v}>?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|�8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!3<Vyx,!C b.lf'\ ןgu,μw-/3ۥNX(c oMDsa##0{c %uDWCBZAZ6,؏x (Z%wHbhTb2<$*cnk_א#{D+B<!S/gÏ`9.^]ßC+>3+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!�!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w�)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷�m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"�{d#!φt},nyWFKv„X4|<B+8i=-;X 5l=/xlwn] +SӼ,{՞�/ДV�+<< o ԇeNp^OOv qR wHF3݁=o;`~kRwCu¦kjE|qϩKV, *?xk}QxU/M= հp=犐^xBˏKx@[IYB]T➐Kq.ὀPwAG\Wϋ92SA\Y\y=ǨGjբM@tԂvDz+Bĺ\լ6k6LʦR_rnl|UAϯ< |!;8_1gsލC >VB~,˘_&fjp/Wԍwa�O H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)��mkBT�|��������������������������������������������������������������������x1 �0 'ݑSő 3[{vo;vo;vo;vo;vo;vo;vo;m���������������������������������=<H��IDATx]LTgfAڂPИƗmLJMMizxv-nI^mڪn5EK} - *ZGpT`@f"Ԗ$OBfΙ3i&"""gDDD$: maB-""2L(EDD P7 ""GVSCci)Mee_H!@Lb"Tlii8'M5ubq|~Kî]4vlRSI|-=cƀ kܷ++WV3a|26lw]K-""ӤI9ya`l;:0n7`LQ] ;I{mms1c1w.3qN-- {zs.\ |GҴgf(c̨#k~ ;}~0H)*"ױV[nڄ|K/O-""v:=@Ƈ Rvr׮:S\o:ȯʀ6@;0@ݚ54:Zi]\ gMRnĞA^y9V; m{q~$\> m{z"n A~e%E5OEDDUbӤ~ݺ)EDD\/[RB0y$ m!b�xKJ·Ya(EDD{,�ZB[DDdϞ  TVqB[DDd 7F"o%r$[A"""Ú[Huc876åaV,/{ls٠^-""rkep1.\ڂ<6.~f~y>nޖq.b?` Xh\eׯscή DMjK}.>.rÙy?ݓ.[a}X #Qh&sQv,\04+cǸzuqjqqTtO[DD7qٝ]TW>0b#?L^WG͂�3HY4V"""0FN'~+`B# xTϟOr1vӦ{qHl;N|<#^KPUX�&nĨ0L4ֹ�pǘUS8?oz�bF`}?HOEDDw'ou?rہ>6h-""rƽ{uWu.<<nmiiK\ӦV"""xl<Owŋ{ȅ +/w`B[DDFUa!-Nյkc�۶Νؒ7]LV.�ȄpM\m-٘ypH_Ziʄ2١Υ, wcBb!BEu[PC�qZkr2F\55ﳳf|&i6)EDD7nd؁51͛Խ6-[\rь|Y2ׯ3iiX޺5)EDD=͜yYYdo~o㯮lk9}:]5:D9ϜIޟ1 {UqI=(˖t)q99�8>ux)Ѓh"""ؒ9xQK`vtPn?rǨ۰o�&=7EDD'8&L 1\YO?w�~ss纎e@Shص 0r&qvx7oIZO z3C! )k?HXGo9~ج,\Ӧ~IXN,n7qyySRBGkEDD9S4|9,_NJQĨ{mp8p_V56`qI(,$'pϙ##klu|;x>Ծ"""!ݸw%pr {FĈ!u [zP{RhDp#Gh>zテII*q'z maB  maB-""2L(EDD'7����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/ca/��������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0017264�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/ca/ca.c����������������������������������������������������������0000664�0000000�0000000�00000003246�12614627753�0020020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <windows.h> #undef RtlZeroMemory NTSYSAPI VOID NTAPI RtlZeroMemory(VOID UNALIGNED *Destination, SIZE_T Length); #include <msi.h> #include <msiquery.h> #pragma comment(linker, "/EXPORT:CheckPaths=_CheckPaths@4") BOOL __stdcall _DllMainCRTStartup(HINSTANCE hInstance, DWORD dwReason, LPVOID lpData) { return TRUE; } struct { LPCTSTR file; LPCTSTR var; } filesTest[] = { {"c2s.xml", "C2S.XML.EXISTS"}, {"resolver.xml", "RESOLVER.XML.EXISTS"}, {"router.xml", "ROUTER.XML.EXISTS"}, {"router-filter.xml", "ROUTER_FILTER.XML.EXISTS"}, {"router-users.xml", "ROUTER_USERS.XML.EXISTS"}, {"s2s.xml", "S2S.XML.EXISTS"}, {"sm.xml", "SM.XML.EXISTS"}, {"server.pem", "SERVER.PEM.EXISTS"}, {"sqlite.db", "SQLITE.DB.EXISTS"}, {NULL, NULL} }; UINT __stdcall CheckPaths(MSIHANDLE hInstall) { TCHAR installDir[MAX_PATH], filePath[MAX_PATH]; DWORD installDirLen = MAX_PATH; int i; MsiGetProperty(hInstall, "INSTALLDIR", installDir, &installDirLen); installDir[installDirLen] = 0; for(i = 0; filesTest[i].file; i++) { WIN32_FIND_DATA fd; HANDLE hff; BOOL bFound = FALSE; if(installDirLen > 0 && installDirLen + lstrlen(filesTest[i].file) + 2 < MAX_PATH) { wsprintf(filePath, "%s%s%s", installDir, installDir[installDirLen - 1] == '\\' ? "" : "\\", filesTest[i].file); ZeroMemory(&fd, sizeof(fd)); if(INVALID_HANDLE_VALUE != (hff = FindFirstFile(filePath, &fd))) { FindClose(hff); if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) bFound = TRUE; } } MsiSetProperty(hInstall, filesTest[i].var, bFound ? filePath : ""); } return ERROR_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/ca/ca.vcproj�����������������������������������������������������0000664�0000000�0000000�00000010453�12614627753�0021077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="ca" ProjectGUID="{4AC65E06-5A7F-4E52-9623-CE18666AFF52}" RootNamespace="ca" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;CA_EXPORTS" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="msi.lib" OutputFile="../../bin/debug/jabberd2$(ProjectName).dll" LinkIncremental="2" GenerateDebugInformation="true" SubSystem="2" EntryPointSymbol="" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CA_EXPORTS" RuntimeLibrary="2" BufferSecurityCheck="false" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="msi.lib" OutputFile="../../bin/jabberd2$(ProjectName).dll" LinkIncremental="1" GenerateManifest="false" IgnoreAllDefaultLibraries="true" IgnoreDefaultLibraryNames="" SubSystem="2" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath=".\ca.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/libraries.wxs����������������������������������������������������0000664�0000000�0000000�00000003662�12614627753�0021427�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <DirectoryRef Id="INSTALLDIR" FileSource="$(var.TargetDir)"> <Component Id="libmysql.dll" Guid="{10A12E1B-55F5-43C1-955D-729CA860416B}"> <File Id="libmysql.dll" Name="libmysql.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="libexpat.dll" Guid="{28B2C906-9655-48F4-BFD4-9448FB504750}"> <File Id="libexpat.dll" Name="libexpat.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="libidn.dll" Guid="{68DC74AB-28C9-4C96-841A-BC6E3020243E}"> <File Id="libidn.dll" Name="libidn.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="sqlite3.dll" Guid="{53BCD278-9B09-4246-BEED-C38695F7A6A8}"> <File Id="sqlite3.dll" Name="sqlite3.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="udns.dll" Guid="{7A0B45E4-6A3E-48FC-9A2B-85702A398F1B}"> <File Id="udns.dll" Name="udns.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="zlib1.dll" Guid="{D0FCED72-651D-4E1B-BFA5-85BCA9E337C9}"> <File Id="zlib1.dll" Name="zlib1.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="libeay32.dll" Guid="{3ABC0783-B198-4FCC-8C71-625F58CCBE51}"> <File Id="libeay32.dll" Name="libeay32.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="ssleay32.dll" Guid="{4979A2FF-254D-449B-94F2-17DFB5A6D6D6}"> <File Id="ssleay32.dll" Name="ssleay32.dll" KeyPath="yes" Vital="yes" /> </Component> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="Libraries"> <ComponentRef Id="libmysql.dll" /> <ComponentRef Id="libexpat.dll" /> <ComponentRef Id="libidn.dll" /> <ComponentRef Id="sqlite3.dll" /> <ComponentRef Id="udns.dll" /> <ComponentRef Id="zlib1.dll" /> <ComponentRef Id="libeay32.dll" /> <ComponentRef Id="ssleay32.dll" /> </ComponentGroup> </Fragment> </Wix>������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/license/���������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0020323�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/license/GPL.rtf��������������������������������������������������0000664�0000000�0000000�00000044336�12614627753�0021474�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fprq1\fcharset0 Courier New;}{\f1\fswiss\fcharset0 Arial;}} {\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\lang2057\f0\fs16\pard\qc GNU GENERAL PUBLIC LICENSE\par Version 2, June 1991\par \pard\par \pard\li100Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\par Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\par \pard\par \pard\qc Preamble\par \pard\par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par The precise terms and conditions for copying, distribution and modification follow.\par \par \pard\qc GNU GENERAL PUBLIC LICENSE\par TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\par \pard\par 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".\par \par 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.\par \par 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.\par \par 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.\par \par 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:\par \par \pard\li256a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\par \par 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.\par \par 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.)\par \pard\par 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.\par \par 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.\par \par 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.\par \par 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:\par \par \pard\li256a) 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,\par \par 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,\par \par 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.)\par \pard\par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\par \par 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.\par \par 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.\par \par 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.\par \par 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.\par \par \tab\tab\tab NO WARRANTY\par \par 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.\par \par 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.\par \par \pard\qc END OF TERMS AND CONDITIONS\par \par How to Apply These Terms to Your New Programs\par \pard\par 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.\par \par 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.\par \par \pard\li256<one line to give the program's name and a brief idea of what it does.>\par Copyright (C) <year> <name of author>\par \pard\par \pard\li256This 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.\par \pard\par \pard\li256This 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.\par \pard\par \pard\li256You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\par \pard\par \par Also add information on how to contact you by electronic and paper mail.\par \par If the program is interactive, make it output a short notice like this when it starts in an interactive mode:\par \par \pard\li256Gnomovision version 69, Copyright (C) year name of author\par 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.\par \pard\par 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.\par \par 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:\par \par \pard\li256Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.\par \pard\par \pard\li256<signature of Ty Coon>, 1 April 1989\par Ty Coon, President of Vice\par \pard\par 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.\par \f1\par } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/make-config.pl���������������������������������������������������0000775�0000000�0000000�00000001204�12614627753�0021416�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl my @file = <>; $_ = join '', @file; s/\r//gi; s/localhost\.localdomain/localhost/gi; s/\@(?:bindir|sysconfdir|localstatedir)\@/./gi; s/\@(?:pkglibdir)\@/modules/gi; s/\/jabberd\/(?:pid|log|db|stats)//gi; s/we use the MySQL driver for all storage/we use the SQLite driver for all storage/gi; s/<driver>mysql<\/driver>/<driver>sqlite<\/driver>/gi; s/<module>mysql<\/module>/<module>sqlite<\/module>/gi; s/type='syslog'/type='file'/gi; s/\s*<!--\s*\n(\s*<\w+[^>]*>[^<]*\.(?:log|pem)<\/\w+>)\s*\n\s*-->[^\n]*/\n$1/gi; s/<id register-enable='true'>localhost/<id register-enable='true' pemfile='.\/server.pem'>localhost/gi; print; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/modules.wxs������������������������������������������������������0000664�0000000�0000000�00000016367�12614627753�0021131�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <DirectoryRef Id="ModulesDir" FileSource="$(var.TargetDir)\modules"> <Component Id="authreg_anon.dll" Guid="{2801B3BA-A499-47E6-B345-3ABA71D9C8DA}"> <File Id="authreg_anon.dll" Name="authreg_anon.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="authreg_mysql.dll" Guid="{FC2B8A7D-07EE-46EB-AC73-B48841454B9E}"> <File Id="authreg_mysql.dll" Name="authreg_mysql.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="authreg_ntlogon.dll" Guid="{50AFB047-D221-412D-BCDD-E2EC87BD0E8B}"> <File Id="authreg_ntlogon.dll" Name="authreg_ntlogon.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="authreg_sqlite.dll" Guid="{B988F232-D183-4DB5-870D-934F77102635}"> <File Id="authreg_sqlite.dll" Name="authreg_sqlite.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="authreg_sspi.dll" Guid="{CD3B4C55-A7EE-484E-AAB5-72F310DB1AA0}"> <File Id="authreg_sspi.dll" Name="authreg_sspi.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_active.dll" Guid="{7B9FE117-4850-4ECF-BE3C-50DE8F7890B0}"> <File Id="mod_active.dll" Name="mod_active.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_amp.dll" Guid="{01C261B2-E6C7-453E-BDDE-D31212E417A2}"> <File Id="mod_amp.dll" Name="mod_amp.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_announce.dll" Guid="{DD4DB0C0-11AF-4334-9C92-9E0B3405238E}"> <File Id="mod_announce.dll" Name="mod_announce.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_deliver.dll" Guid="{F6DC414E-1436-4455-B427-A712D0585AF1}"> <File Id="mod_deliver.dll" Name="mod_deliver.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_discopublish.dll" Guid="{F88B4012-C199-4A31-8E8F-FB2189A3AF0C}"> <File Id="mod_discopublish.dll" Name="mod_disco-publish.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_disco.dll" Guid="{1396DE84-5B5B-46A3-8D0B-0B992C9E4AA9}"> <File Id="mod_disco.dll" Name="mod_disco.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_echo.dll" Guid="{56B33E35-932C-496D-AF07-17FE6330F0BF}"> <File Id="mod_echo.dll" Name="mod_echo.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_help.dll" Guid="{75BA1193-9370-4412-B19F-99AD3362B7AC}"> <File Id="mod_help.dll" Name="mod_help.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqlast.dll" Guid="{713A54DB-B00B-4383-A349-408BB6121A36}"> <File Id="mod_iqlast.dll" Name="mod_iq-last.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqping.dll" Guid="{A9DD9803-CEF6-47B2-8D4D-254A3B603AD7}"> <File Id="mod_iqping.dll" Name="mod_iq-ping.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqprivate.dll" Guid="{F14BCCF3-BFF4-4641-A0DB-2FBDB9DB03A8}"> <File Id="mod_iqprivate.dll" Name="mod_iq-private.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqtime.dll" Guid="{22650353-0F56-41EE-B321-00D140C719F2}"> <File Id="mod_iqtime.dll" Name="mod_iq-time.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqvcard.dll" Guid="{FBFB22D2-0594-4F32-A114-4ADDCAB9874D}"> <File Id="mod_iqvcard.dll" Name="mod_iq-vcard.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_iqversion.dll" Guid="{211EAC8A-963A-4813-B293-A5BDCDA4D9E5}"> <File Id="mod_iqversion.dll" Name="mod_iq-version.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_offline.dll" Guid="{4ECFBB60-269E-4222-986F-B2919F216A81}"> <File Id="mod_offline.dll" Name="mod_offline.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_presence.dll" Guid="{82220B4C-A18E-4E59-BBEB-2A63C702A809}"> <File Id="mod_presence.dll" Name="mod_presence.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_privacy.dll" Guid="{6C619BCE-A850-4E82-9307-50E4520BE79F}"> <File Id="mod_privacy.dll" Name="mod_privacy.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_roster.dll" Guid="{437373A4-53C1-4B06-9459-9467C7514DB8}"> <File Id="mod_roster.dll" Name="mod_roster.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_rosterpublish.dll" Guid="{A3706FEE-3A58-4175-A91F-8C66E5C2078B}"> <File Id="mod_rosterpublish.dll" Name="mod_roster-publish.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_session.dll" Guid="{3630201D-7112-436E-B4F5-E1683BE6C57B}"> <File Id="mod_session.dll" Name="mod_session.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_status.dll" Guid="{E47BFDB6-BDBB-4DCD-AFA3-201349274B9F}"> <File Id="mod_status.dll" Name="mod_status.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_templateroster.dll" Guid="{914F3FAA-8641-47EE-90FF-6E9E91E16041}"> <File Id="mod_templateroster.dll" Name="mod_template-roster.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_vacation.dll" Guid="{77F1A3C2-B611-4609-BA9A-EEC5D2881460}"> <File Id="mod_vacation.dll" Name="mod_vacation.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="mod_validate.dll" Guid="{DA34D6BE-2BE4-41C8-AF01-4B13C1024E4B}"> <File Id="mod_validate.dll" Name="mod_validate.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="storage_mysql.dll" Guid="{9DC4348B-D28F-47FF-AD11-0540671A9B8E}"> <File Id="storage_mysql.dll" Name="storage_mysql.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="storage_sqlite.dll" Guid="{2603734F-2F90-4EE4-8A53-63F480841CDA}"> <File Id="storage_sqlite.dll" Name="storage_sqlite.dll" KeyPath="yes" Vital="yes" /> </Component> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="Modules"> <ComponentRef Id="authreg_anon.dll" /> <ComponentRef Id="authreg_mysql.dll" /> <ComponentRef Id="authreg_ntlogon.dll" /> <ComponentRef Id="authreg_sqlite.dll" /> <ComponentRef Id="authreg_sspi.dll" /> <ComponentRef Id="mod_active.dll" /> <ComponentRef Id="mod_amp.dll" /> <ComponentRef Id="mod_announce.dll" /> <ComponentRef Id="mod_deliver.dll" /> <ComponentRef Id="mod_discopublish.dll" /> <ComponentRef Id="mod_disco.dll" /> <ComponentRef Id="mod_echo.dll" /> <ComponentRef Id="mod_help.dll" /> <ComponentRef Id="mod_iqlast.dll" /> <ComponentRef Id="mod_iqping.dll" /> <ComponentRef Id="mod_iqprivate.dll" /> <ComponentRef Id="mod_iqtime.dll" /> <ComponentRef Id="mod_iqvcard.dll" /> <ComponentRef Id="mod_iqversion.dll" /> <ComponentRef Id="mod_offline.dll" /> <ComponentRef Id="mod_presence.dll" /> <ComponentRef Id="mod_privacy.dll" /> <ComponentRef Id="mod_roster.dll" /> <ComponentRef Id="mod_rosterpublish.dll" /> <ComponentRef Id="mod_session.dll" /> <ComponentRef Id="mod_status.dll" /> <ComponentRef Id="mod_templateroster.dll" /> <ComponentRef Id="mod_vacation.dll" /> <ComponentRef Id="mod_validate.dll" /> <ComponentRef Id="storage_mysql.dll" /> <ComponentRef Id="storage_sqlite.dll" /> </ComponentGroup> </Fragment> </Wix>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/sasl.wxs���������������������������������������������������������0000664�0000000�0000000�00000000773�12614627753�0020415�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <DirectoryRef Id="INSTALLDIR" FileSource="$(var.TargetDir)"> <Component Id="libgsasl.dll" Guid="{E390362B-74D0-400A-B531-7F49ADBB98A2}"> <File Id="libgsasl.dll" Name="libgsasl.dll" KeyPath="yes" Vital="yes" /> </Component> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="SASL"> <ComponentRef Id="libgsasl.dll" /> </ComponentGroup> </Fragment> </Wix>�����jabberd2-jabberd-2.3.4/win32/setup/server.pem�������������������������������������������������������0000664�0000000�0000000�00000003463�12614627753�0020720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN CERTIFICATE----- MIICkTCCAfoCAQEwDQYJKoZIhvcNAQEEBQAwgZAxCzAJBgNVBAYTAlBMMRIwEAYD VQQIEwlMb2NhbGhvc3QxEjAQBgNVBAcTCUxvY2FsaG9zdDESMBAGA1UEChMJTG9j YWxob3N0MRIwEAYDVQQLEwlsb2NhbGhvc3QxEjAQBgNVBAMTCWxvY2FsaG9zdDEd MBsGCSqGSIb3DQEJARYOcm9vdEBsb2NhbGhvc3QwHhcNMDcwNTIwMTk0ODQxWhcN MDkwNTE5MTk0ODQxWjCBkDELMAkGA1UEBhMCUEwxEjAQBgNVBAgTCUxvY2FsaG9z dDESMBAGA1UEBxMJTG9jYWxob3N0MRIwEAYDVQQKEwlMb2NhbGhvc3QxEjAQBgNV BAsTCWxvY2FsaG9zdDESMBAGA1UEAxMJbG9jYWxob3N0MR0wGwYJKoZIhvcNAQkB Fg5yb290QGxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA09CK 77keFhMiohXpGDbsrCKRYyIK4f0VXyQla1xLRPW6PCseLGhpVx9GZ13v+cOQex4d tkOHCuziiwRP1biPr+nzBFbcMY440VptVouvMnzmYIDds7PgfMtxAHMTYsdTGZAh szC8q7Tt43I/LWTC53YeazGWo7wMb7NEaap0jNUCAwEAATANBgkqhkiG9w0BAQQF AAOBgQCA5EwLji0OTYu4HzsOqHzBWU3oVmp77mOziivU+ZlmnIODBfvtFxod++Gh ZxVxQorl1g+s7z5EyfPDjBCfUbJihw5aEwEE8a7ca+hWm53FQcZLUtF3SyukwOfi f9d39bB2ZKensQjwpnJj3ykbIyYxw3S/u8VoKI6UHQ7XaqIxbw== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDT0IrvuR4WEyKiFekYNuysIpFjIgrh/RVfJCVrXEtE9bo8Kx4s aGlXH0ZnXe/5w5B7Hh22Q4cK7OKLBE/VuI+v6fMEVtwxjjjRWm1Wi68yfOZggN2z s+B8y3EAcxNix1MZkCGzMLyrtO3jcj8tZMLndh5rMZajvAxvs0RpqnSM1QIDAQAB AoGBAK0GOqhOgKwpn23mFg3ot/Z5GmhvY5JtaarZXRPRRc8kJ6iE1FYUSJCZhKpl iuVtAjYASOcdTE/5Z6mFsS11YTEmorCwoND1AKRYRppHkaysBurZnrZjrxfkQYg6 kpQHWcVio5vpXCAU80LNPgdzLTzrxciVfMDw9E9p5+W7HBghAkEA6+1HiejEBOkD XGdfsZw8f/RoztTjNPA4WwLjEcqqi38XE8YTf7G+YvBAIb64i92KUpSdS4W+TKrE P0Cogw83zQJBAOXWExa6i03/rVsn/CY+1q/i8/LZw91q2Vxc+Vt5loa7q8cvdcwe I3/Bwowr3tyEcYTxTqVRNMmiXgmk6WOQESkCQQCgBd1UKVFrkzD4aBV8PuC6WWkN gVBrA9T1xkuGMdTjsVxRyTRIlKLyMMsPGHHMTIQZ5zuZkim1js51qMGjw5qxAkEA qNtnuNoiwJJotcEhsqOWLTDrk29ERGdc/Evec8NXwPMemD+ZJva5lAIxwbP1j0PK 9yYmZrTLuJwOxL0hLyHISQJAdNbJG/CsGotPfuzDDVOLREvphsQKNdwII2t/wZAX zpDX5mGyPowqw1KF0vYNouDbyQV65xK92gbyFbWNwPrK8A== -----END RSA PRIVATE KEY----- �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/services.wxs�����������������������������������������������������0000664�0000000�0000000�00000022102�12614627753�0021264�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Fragment> <DirectoryRef Id="INSTALLDIR" FileSource="$(var.TargetDir)"> <Component Id="c2s.exe" Guid="{77DD37C2-8852-4347-8EFE-6FC85A988B30}"> <File Id="c2s.exe" Name="c2s.exe" KeyPath="yes" Vital="yes" /> <RemoveFile Id="c2s.log" Name="c2s.log" On="uninstall" /> <RemoveFile Id="c2s.pid" Name="c2s.pid" On="uninstall" /> <ServiceInstall Arguments="-S" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes" Id="jabberd2c2s" Name="jabberd2c2s" DisplayName="Jabber 2 C2S" Description="Jabber Open Source Server: Client to Server"> <ServiceDependency Id="jabberd2router" /> </ServiceInstall> <ServiceControl Id="jabberd2c2s" Name="jabberd2c2s" Remove="uninstall" Start="install" Stop="both" Wait="yes" /> </Component> <Component Id="c2s.dist.xml" Guid="{CFC12491-EB7B-4BFA-A0E1-4342A68DC481}"> <Condition>C2S.XML.EXISTS</Condition> <File Id="c2s.dist.xml" Name="c2s.dist.xml" Vital="yes" Source="$(var.TargetDir)\c2s.xml" /> </Component> <Component Id="c2s.xml" Guid="{C6B805D9-9171-48A3-93BC-2DF99357F791}" Permanent="yes"> <Condition>NOT C2S.XML.EXISTS</Condition> <File Id="c2s.xml" Name="c2s.xml" Vital="yes" KeyPath="yes" /> <util:XmlFile Id="c2s.configure" Action="setValue" ElementPath="/c2s/local/id" File="[INSTALLDIR]\c2s.xml" Value="[DOMAIN]" /> </Component> <Component Id="router.exe" Guid="{B633B226-3A8C-4E25-A26D-0786EC08D217}"> <File Id="router.exe" Name="router.exe" KeyPath="yes" Vital="yes" /> <RemoveFile Id="router.log" Name="router.log" On="uninstall" /> <RemoveFile Id="router.pid" Name="router.pid" On="uninstall" /> <ServiceInstall Arguments="-S" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes" Id="jabberd2router" Name="jabberd2router" DisplayName="Jabber 2 Router" Description="Jabber Open Source Server: Router" /> <ServiceControl Id="jabberd2router" Name="jabberd2router" Remove="uninstall" Start="install" Stop="both" Wait="yes" /> </Component> <Component Id="router.dist.xml" Guid="{177EB263-58C5-4E48-AFA2-C4EEBF9C5726}"> <Condition>ROUTER.XML.EXISTS</Condition> <File Id="router.dist.xml" Name="router.dist.xml" Vital="yes" Source="$(var.TargetDir)\router.xml" /> </Component> <Component Id="router_filter.dist.xml" Guid="{C894E253-4C89-462A-89AA-66A0D353C1BA}"> <Condition>ROUTER_FILTER.XML.EXISTS</Condition> <File Id="router_filter.dist.xml" Name="router-filter.dist.xml" Vital="yes" Source="$(var.TargetDir)\router-filter.xml" /> </Component> <Component Id="router_users.dist.xml" Guid="{0CD59F12-52B9-403A-8687-572D1B44A217}"> <Condition>ROUTER_USERS.XML.EXISTS</Condition> <File Id="router_users.dist.xml" Name="router-users.dist.xml" Vital="yes" Source="$(var.TargetDir)\router-users.xml" /> </Component> <Component Id="router.xml" Guid="{15EC6601-ACB1-48B7-AC01-38F3CED13E9D}" Permanent="yes"> <Condition>NOT ROUTER.XML.EXISTS</Condition> <File Id="router_router.xml" Name="router.xml" Vital="yes" KeyPath="yes" /> </Component> <Component Id="router_filter.xml" Guid="{A73E50B0-74DA-47D1-AB12-7377271F58C6}" Permanent="yes"> <Condition>NOT ROUTER_FILTER.XML.EXISTS</Condition> <File Id="router_filter.xml" Name="router-filter.xml" Vital="yes" KeyPath="yes" /> </Component> <Component Id="router_users.xml" Guid="{8A9EB164-7BE9-49A0-9C4D-4CF5FCC55233}" Permanent="yes"> <Condition>NOT ROUTER_USERS.XML.EXISTS</Condition> <File Id="router_users.xml" Name="router-users.xml" Vital="yes" KeyPath="yes" /> </Component> <Component Id="s2s.exe" Guid="{CEDBD464-DD63-4430-8469-3F3C27A06C90}"> <File Id="s2s.exe" Name="s2s.exe" KeyPath="yes" Vital="yes" /> <RemoveFile Id="s2s.log" Name="s2s.log" On="uninstall" /> <RemoveFile Id="s2s.pid" Name="s2s.pid" On="uninstall" /> <ServiceInstall Arguments="-S" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes" Id="jabberd2s2s" Name="jabberd2s2s" DisplayName="Jabber 2 S2S" Description="Jabber Open Source Server: Server to Server"> <ServiceDependency Id="jabberd2router" /> </ServiceInstall> <ServiceControl Id="jabberd2s2s" Name="jabberd2s2s" Remove="uninstall" Start="install" Stop="both" Wait="yes" /> </Component> <Component Id="s2s.dist.xml" Guid="{44A615A2-9452-4AD6-AFD6-7D52BE6E7EF5}"> <Condition>S2S.XML.EXISTS</Condition> <File Id="s2s.dist.xml" Name="s2s.dist.xml" Vital="yes" Source="$(var.TargetDir)\s2s.xml" /> </Component> <Component Id="s2s.xml" Guid="{554A5AFC-CA6C-45A8-AFB8-65F51C108861}" Permanent="yes"> <Condition>NOT S2S.XML.EXISTS</Condition> <File Id="s2s.xml" Name="s2s.xml" Vital="yes" KeyPath="yes" /> </Component> <Component Id="sm.exe" Guid="{B5C795C8-6FFC-441C-9F7C-6846124C2D43}"> <File Id="sm.exe" Name="sm.exe" KeyPath="yes" Vital="yes" /> <RemoveFile Id="sm.log" Name="sm.log" On="uninstall" /> <RemoveFile Id="sm.pid" Name="sm.pid" On="uninstall" /> <ServiceInstall Arguments="-S" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes" Id="jabberd2sm" Name="jabberd2sm" DisplayName="Jabber 2 Session Manager" Description="Jabber Open Source Server: Session Manager"> <ServiceDependency Id="jabberd2router" /> </ServiceInstall> <ServiceControl Id="jabberd2sm" Name="jabberd2sm" Remove="uninstall" Start="install" Stop="both" Wait="yes" /> </Component> <Component Id="sm.dist.xml" Guid="{7A694B6F-FB52-42B2-8D23-06E6C725E1D0}"> <Condition>SM.XML.EXISTS</Condition> <File Id="sm.dist.xml" Name="sm.dist.xml" Vital="yes" Source="$(var.TargetDir)\sm.xml" /> </Component> <Component Id="sm.xml" Guid="{74E3ADAC-1CE9-41A4-9B30-3CA98D2E6BDA}" Permanent="yes"> <Condition>NOT SM.XML.EXISTS</Condition> <File Id="sm.xml" Name="sm.xml" Vital="yes" KeyPath="yes" /> <util:XmlFile Id="smConfigure" Action="setValue" ElementPath="/sm/id" File="[INSTALLDIR]\sm.xml" Value="[DOMAIN]" /> </Component> <Component Id="server.dist.pem" Guid="{B397D554-041C-4142-B4B0-7DB105001DE1}"> <Condition>SERVER.PEM.EXISTS</Condition> <File Id="server.dist.pem" Name="server.dist.pem" Vital="yes" Source="$(var.TargetDir)\server.pem" /> </Component> <Component Id="server.pem" Guid="{8AA5D8A8-A7EC-4F9F-BD19-FE0DD03BA620}" Permanent="yes"> <Condition>NOT SERVER.PEM.EXISTS</Condition> <File Id="server.pem" Name="server.pem" KeyPath="yes" Vital="yes" /> </Component> <Component Id="jabberd2.dll" Guid="{4C6C8EBD-DB23-498C-8E1E-0254631AB252}"> <File Id="jabberd2.dll" Name="jabberd2.dll" KeyPath="yes" Vital="yes" /> </Component> <Component Id="dbsetup.mysql" Guid="{0EE029D6-DFD1-4F20-A910-02B472940D7F}"> <File Id="dbsetup.mysql" Name="db-setup.mysql" KeyPath="yes" Vital="yes" /> </Component> <Component Id="dbupdate.mysql" Guid="{E6CEA2B8-BFF6-4969-9B4E-3F6F5AF8CB06}"> <File Id="dbupdate.mysql" Name="db-update.mysql" KeyPath="yes" Vital="yes" /> </Component> <Component Id="dbsetup.sqlite" Guid="{5C39F304-CD9E-4488-8C8D-5C629EB315D1}"> <File Id="dbsetup.sqlite" Name="db-setup.sqlite" KeyPath="yes" Vital="yes" /> </Component> <Component Id="dbupdate.sqlite" Guid="{609ED973-93AE-4CCF-8B04-661DEBDC466E}"> <File Id="dbupdate.sqlite" Name="db-update.sqlite" KeyPath="yes" Vital="yes" /> </Component> <Component Id="sqlite.dist.db" Guid="{928DD3B5-F429-45C4-B677-F3A2FFE23051}"> <Condition>SQLITE.DB.EXISTS</Condition> <File Id="sqlite.dist.db" Name="sqlite.dist.db" KeyPath="yes" Vital="yes" Source="$(var.TargetDir)\sqlite.db" /> </Component> <Component Id="sqlite.db" Guid="{54949691-C375-45B4-9936-D10967CCD0B2}" Permanent="yes"> <Condition>NOT SQLITE.DB.EXISTS</Condition> <File Id="sqlite.db" Name="sqlite.db" KeyPath="yes" Vital="yes" /> </Component> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="Services"> <ComponentRef Id="c2s.exe" /> <ComponentRef Id="c2s.xml" /> <ComponentRef Id="c2s.dist.xml" /> <ComponentRef Id="router.exe" /> <ComponentRef Id="router.xml" /> <ComponentRef Id="router.dist.xml" /> <ComponentRef Id="router_filter.xml" /> <ComponentRef Id="router_filter.dist.xml" /> <ComponentRef Id="router_users.xml" /> <ComponentRef Id="router_users.dist.xml" /> <ComponentRef Id="s2s.exe" /> <ComponentRef Id="s2s.xml" /> <ComponentRef Id="s2s.dist.xml" /> <ComponentRef Id="sm.exe" /> <ComponentRef Id="sm.xml" /> <ComponentRef Id="sm.dist.xml" /> <ComponentRef Id="server.pem" /> <ComponentRef Id="server.dist.pem" /> <ComponentRef Id="jabberd2.dll" /> <ComponentRef Id="dbsetup.mysql" /> <ComponentRef Id="dbupdate.mysql" /> <ComponentRef Id="dbsetup.sqlite" /> <ComponentRef Id="dbupdate.sqlite" /> <ComponentRef Id="sqlite.dist.db" /> <ComponentRef Id="sqlite.db" /> </ComponentGroup> </Fragment> </Wix>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/setup.wixproj����������������������������������������������������0000664�0000000�0000000�00000003451�12614627753�0021470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProductVersion>3.0</ProductVersion> <ProjectGuid>{8504d60e-b1c4-4fe8-a5c2-3f36b1a5e2bd}</ProjectGuid> <SchemaVersion>2.0</SchemaVersion> <OutputName>jabberd-svn-win32</OutputName> <OutputType>Package</OutputType> <WixToolPath>$(ProgramFiles)\Windows Installer XML v3\bin\</WixToolPath> <Cultures>en-US</Cultures> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <OutputPath>..\bin\debug\</OutputPath> <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath> <DefineConstants>Debug</DefineConstants> <Cultures>en-US</Cultures> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <OutputPath>..\bin\</OutputPath> <IntermediateOutputPath>obj\Release\</IntermediateOutputPath> <DefineConstants></DefineConstants> <Cultures>en-US</Cultures> <WixVariables> </WixVariables> <VerboseOutput>True</VerboseOutput> </PropertyGroup> <ItemGroup> <Compile Include="libraries.wxs" /> <Compile Include="modules.wxs" /> <Compile Include="sasl.wxs" /> <Compile Include="services.wxs" /> <Compile Include="setup.wxs" /> <Compile Include="ui.wxs" /> </ItemGroup> <ItemGroup> <WixExtension Include="WixUIExtension"> <HintPath>C:\Program Files\Windows Installer XML v3\bin\WixUIExtension.dll</HintPath> </WixExtension> <WixExtension Include="WixUtilExtension"> <HintPath>C:\Program Files\Windows Installer XML v3\bin\WixUtilExtension.dll</HintPath> </WixExtension> </ItemGroup> <Import Project="$(MSBuildExtensionsPath)\Microsoft\WiX\v3.0\Wix.targets" /> </Project>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/setup.wxs��������������������������������������������������������0000664�0000000�0000000�00000006562�12614627753�0020615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <?include "../include/version.wxi" ?> <?define ProductName = "jabberd $(var.ProductVersion) for Windows" ?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Product Id="*" Name="$(var.ProductName)" xmlns:De="http://schemas.microsoft.com/wix/2006/wi" Language="1033" Version="$(var.ProductFileVersion)" Manufacturer="jabberd2" UpgradeCode="5f4d7239-76fb-40e6-92b4-cb4aff5082d0"> <Package InstallerVersion="200" Compressed="yes" Description="$(var.ProductName) installer" Keywords="jabber" /> <Media Id="1" Cabinet="setup.cab" EmbedCab="yes" /> <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="INSTALLDIR" Name="jabberd2"> <Directory Id="ModulesDir" Name="modules" /> </Directory> </Directory> </Directory> <Upgrade Id="5f4d7239-76fb-40e6-92b4-cb4aff5082d0"> <UpgradeVersion OnlyDetect="yes" Property="NEWER_VER_FOUND" IncludeMinimum="yes" Minimum="$(var.ProductFileVersion)" /> <UpgradeVersion Property="OLDER_VER_FOUND" IncludeMinimum="yes" Minimum="1.0.0" IncludeMaximum="no" Maximum="$(var.ProductFileVersion)" /> </Upgrade> <Feature Id="Complete" Title="$(var.ProductName)" Description="Complete package" Display="expand" Level="1" ConfigurableDirectory="INSTALLDIR"> <Feature Id="jabberd2" Title="$(var.ProductName)" Level="1"> <ComponentGroupRef Id="Libraries" /> <ComponentGroupRef Id="SASL" /> <ComponentGroupRef Id="Services" /> <ComponentGroupRef Id="Modules" /> </Feature> </Feature> <WixVariable Id="WixUILicenseRtf" Value="license\GPL.rtf" /> <WixVariable Id="WixUIBannerBmp" Value="bitmaps\banner.jpg" /> <WixVariable Id="WixUIDialogBmp" Value="bitmaps\background.jpg" /> <InstallExecuteSequence> <FindRelatedProducts Before="LaunchConditions" /> <RemoveExistingProducts After="InstallValidate" /> </InstallExecuteSequence> <InstallUISequence> <FindRelatedProducts Before="LaunchConditions" /> <Show Dialog="JabberWelcomeDlg" Before="ProgressDlg">NOT Installed</Show> </InstallUISequence> <Property Id="VC9SP1RTM"> <DirectorySearch Id="VC9SP1RTM" Path="[WindowsFolder]WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e"> <FileSearch Id="VC9SP1RTM" Name="msvcr90.dll"/> </DirectorySearch> </Property> <Property Id="VC9SP1RTM_VISTA"> <DirectorySearch Id="VC9SP1RTM_VISTA" Path="[WindowsFolder]WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.1_none_e163563597edeada"> <FileSearch Id="VC9SP1RTM_VISTA" Name="msvcr90.dll"/> </DirectorySearch> </Property> <Property Id="VC9SP1RTM_WINDOWS7"> <DirectorySearch Id="VC9SP1RTM_WINDOWS7" Path="[WindowsFolder]WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.715_none_90ba96fe148b75ae"> <FileSearch Id="VC9SP1RTM_WINDOWS7" Name="msvcr90.dll"/> </DirectorySearch> </Property> <Condition Message="Please install Visual C++ 2008 SP1 Redistributable Package (x86). http://www.microsoft.com/downloads/details.aspx?familyid=A5C84275-3B97-4AB7-A40D-3802B2AF5FC2"> VC9SP1RTM OR VC9SP1RTM_VISTA OR VC9SP1RTM_WINDOWS7 </Condition> <Condition Message="A later version of [ProductName] is already installed."> NOT NEWER_VER_FOUND </Condition> <UIRef Id="WixUI_Common" /> <UIRef Id="jabberd2UI" /> </Product> </Wix> ����������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/setup/ui.wxs�����������������������������������������������������������0000664�0000000�0000000�00000022220�12614627753�0020057�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Fragment> <CustomAction Id="CheckPaths" BinaryKey="jabberd2ca" DllEntry="CheckPaths" /> <Binary Id="jabberd2ca" SourceFile="$(var.TargetDir)\jabberd2ca.dll" /> <UI Id="jabberd2UI"> <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" /> <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" /> <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" /> <TextStyle Id="WixUI_Font_Description" FaceName="Tahoma" Size="8" Italic="yes" /> <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" /> <Property Id="ARPNOMODIFY" Value="1" /> <DialogRef Id="BrowseDlg" /> <DialogRef Id="DiskCostDlg" /> <DialogRef Id="ErrorDlg" /> <DialogRef Id="FatalError" /> <DialogRef Id="FilesInUse" /> <DialogRef Id="MsiRMFilesInUse" /> <DialogRef Id="PrepareDlg" /> <DialogRef Id="ProgressDlg" /> <DialogRef Id="ResumeDlg" /> <DialogRef Id="UserExit" /> <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish> <Publish Dialog="JabberWelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> <Publish Dialog="JabberWelcomeDlg" Control="Upgrade" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="JabberWelcomeDlg">1</Publish> <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">LicenseAccepted = "1"</Publish> <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Property="DOMAIN" Value="[%USERDNSDOMAIN]" Order="1">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Property="DOMAIN" Value="[%USERDOMAIN]" Order="2">DOMAIN = ""</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Property="INSTALLDIR" Value="[INSTALLDIR]" Order="3">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="CheckPaths" Order="4">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="ConfigurationDlg" Order="5">NOT C2S.XML.EXISTS AND NOT S2S.XML.EXISTS</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="DetectedDlg" Order="6">C2S.XML.EXISTS OR S2S.XML.EXISTS</Publish> <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> <Publish Dialog="ConfigurationDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">1</Publish> <Publish Dialog="ConfigurationDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">NOT DOMAIN = ""</Publish> <Publish Dialog="DetectedDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">1</Publish> <Publish Dialog="DetectedDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="ConfigurationDlg" Order="1">NOT Installed AND NOT C2S.XML.EXISTS AND NOT S2S.XML.EXISTS</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="DetectedDlg" Order="2">NOT Installed AND (C2S.XML.EXISTS OR S2S.XML.EXISTS)</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="3">Installed</Publish> <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish> <Dialog Id="ConfigurationDlg" Width="370" Height="270" Title="[ProductName] [Setup]"> <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}jabberd2 Configuration" /> <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Modify your initial configuration options" /> <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" /> <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" /> <Control Id="DomainLabel" Type="Text" X="20" Y="60" Width="290" Height="13" Text="XMPP Domain Name:*" /> <Control Id="Domain" Type="Edit" X="20" Y="72" Width="320" Height="18" Property="DOMAIN" Text="47"/> <Control Id="DomainDescription" Type="Text" X="20" Y="93" Width="290" Height="13" Text="{\WixUI_Font_Description}*Must be valid DNS entry pointing to this machine, i.e.: samplexmppserver.com" /> <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next"> <Condition Action="disable">DOMAIN = ""</Condition> <Condition Action="enable"><![CDATA[DOMAIN <> ""]]></Condition> </Control> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back" /> <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel"> <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> </Control> </Dialog> <Dialog Id="JabberWelcomeDlg" Width="370" Height="270" Title="!(loc.WelcomeDlg_Title)"> <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)"> <Condition Action="hide">OLDER_VER_FOUND</Condition> </Control> <Control Id="Upgrade" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Upgrade"> <Condition Action="hide">NOT OLDER_VER_FOUND</Condition> </Control> <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)"> <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> </Control> <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.WelcomeDlgBitmap)" /> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" /> <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> <Control Id="Description" Type="Text" X="135" Y="80" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.WelcomeDlgDescription)"> <Condition Action="hide">OLDER_VER_FOUND</Condition> </Control> <Control Id="UpgradeDescription" Type="Text" X="135" Y="80" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="jabberd2 is already installed on this computer.&#xA;&#xA;Setup will remove existing installation before installing this version, configuration files and database will not be removed."> <Condition Action="hide">NOT OLDER_VER_FOUND</Condition> </Control> <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.WelcomeDlgTitle)" /> </Dialog> <Dialog Id="DetectedDlg" Width="370" Height="270" Title="[ProductName] [Setup]"> <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}Existing jabberd2 configuration detected" /> <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Setup has detected existing jabberd2 configuration" /> <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" /> <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" /> <Control Id="HelpLabel" Type="Text" X="20" Y="60" Width="330" Height="170" Text="Existing configuration was detected at &quot;[INSTALLDIR]&quot; folder.&#xA;&#xA;Setup will not modify or overwrite old configuration files.&#xA;&#xA;New distribution configuration files will be written with &quot;dist.xml&quot; extension." /> <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next" /> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back" /> <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel"> <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> </Control> </Dialog> </UI> </Fragment> </Wix>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/sm/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�12614627753�0016160�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������jabberd2-jabberd-2.3.4/win32/sm/sm.vcproj�����������������������������������������������������������0000664�0000000�0000000�00000016522�12614627753�0020032�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" Name="sm" ProjectGUID="{FD37421A-5883-48EE-8AF7-342839ED5564}" RootNamespace="sm" Keyword="Win32Proj" TargetFrameworkVersion="131072" > <Platforms> <Platform Name="Win32" /> </Platforms> <ToolFiles> </ToolFiles> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libeay32.lib libidn.lib ws2_32.lib" OutputFile="../bin/debug/$(ProjectName).exe" LinkIncremental="2" AdditionalLibraryDirectories="../lib/debug;../lib" GenerateDebugInformation="true" SubSystem="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/debug/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" WholeProgramOptimization="1" > <Tool Name="VCPreBuildEventTool" /> <Tool Name="VCCustomBuildTool" /> <Tool Name="VCXMLDataGeneratorTool" /> <Tool Name="VCWebServiceProxyGeneratorTool" /> <Tool Name="VCMIDLTool" /> <Tool Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories=".;../include;../.." PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;USE_LIBSUBST;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" RuntimeLibrary="2" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" /> <Tool Name="VCResourceCompilerTool" /> <Tool Name="VCPreLinkEventTool" /> <Tool Name="VCLinkerTool" AdditionalDependencies="jabberd2.lib libeay32.lib libidn.lib ws2_32.lib" OutputFile="../bin/$(ProjectName).exe" LinkIncremental="1" AdditionalLibraryDirectories="../lib" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" ImportLibrary="../lib/$(ProjectName).lib" TargetMachine="1" /> <Tool Name="VCALinkTool" /> <Tool Name="VCManifestTool" /> <Tool Name="VCXDCMakeTool" /> <Tool Name="VCBscMakeTool" /> <Tool Name="VCFxCopTool" /> <Tool Name="VCAppVerifierTool" /> <Tool Name="VCPostBuildEventTool" /> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source Files" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File RelativePath="..\..\sm\aci.c" > </File> <File RelativePath="..\..\sm\dispatch.c" > </File> <File RelativePath="..\..\sm\feature.c" > </File> <File RelativePath="..\..\sm\main.c" > </File> <File RelativePath="..\..\sm\mm.c" > </File> <File RelativePath="..\..\sm\object.c" > </File> <File RelativePath="..\..\sm\pkt.c" > </File> <File RelativePath="..\..\sm\pres.c" > </File> <File RelativePath="..\..\sm\sess.c" > </File> <File RelativePath="..\..\sm\sm.c" > </File> <File RelativePath="..\..\sm\storage.c" > </File> <File RelativePath="..\..\sm\user.c" > </File> </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > <File RelativePath="..\include\ac-stdint.h" > </File> <File RelativePath="..\include\config.h" > </File> <File RelativePath="..\..\sm\sm.h" > </File> <File RelativePath="..\include\win32_port.h" > </File> </Filter> <Filter Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File RelativePath="..\jabberd2.rc" > </File> <File RelativePath="..\setup\server.pem" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating default certificate: $(TargetDir)$(InputFileName)" CommandLine="copy /y $(InputPath) $(TargetDir)$(InputFileName)&#x0D;&#x0A;" Outputs="$(TargetDir)$(InputFileName)" /> </FileConfiguration> </File> <File RelativePath="..\..\etc\sm.xml.dist.in" > <FileConfiguration Name="Debug|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> <FileConfiguration Name="Release|Win32" > <Tool Name="VCCustomBuildTool" Description="Generating configuration: $(TargetDir)$(TargetName).xml" CommandLine="perl ../setup/make-config.pl $(InputPath) &gt; $(TargetDir)$(TargetName).xml&#x0D;&#x0A;" AdditionalDependencies="../setup/make-config.pl" Outputs="$(TargetDir)$(TargetName).xml" /> </FileConfiguration> </File> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������